diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1a7a923..20d8a3f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -35,16 +35,8 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.12'] - os: [ubuntu-latest, macos-latest] - include: - - python-version: '3.11' - os: ubuntu-latest - - python-version: '3.10' - os: ubuntu-latest - - python-version: '3.9' - os: ubuntu-latest - runs-on: ${{ matrix.os }} + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff --git a/app/sample_registry/README.md b/app/sample_registry/README.md deleted file mode 100644 index 8330760..0000000 --- a/app/sample_registry/README.md +++ /dev/null @@ -1,9 +0,0 @@ -Installation ----- - -The python library may be installed system-wide by typing - - sudo python setup.py install - -in the current directory. - diff --git a/app/sample_registry/pyproject.toml b/app/sample_registry/pyproject.toml index 5946ae1..f2f8e5f 100644 --- a/app/sample_registry/pyproject.toml +++ b/app/sample_registry/pyproject.toml @@ -1,144 +1,46 @@ [project] -# This is the name of your project. The first time you publish this -# package, this name will be registered for you. It will determine how -# users can install this project, e.g.: -# -# $ pip install sampleproject -# -# And where it will live on PyPI: https://pypi.org/project/sampleproject/ -# -# There are some restrictions on what makes a valid project name -# specification here: -# https://packaging.python.org/specifications/core-metadata/#name name = "sample_registry" # Required - -# Versions should comply with PEP 440: -# https://www.python.org/dev/peps/pep-0440/ -# -# For a discussion on single-sourcing the version, see -# https://packaging.python.org/guides/single-sourcing-package-version/ -#version = "3.0.0" # Required dynamic = ["version"] - -# This is a one-line description or tagline of what your project does. This -# corresponds to the "Summary" metadata field: -# https://packaging.python.org/specifications/core-metadata/#summary description = "PennCHOP Microbiome Program Sample Registry" # Optional - -# This is an optional longer description of your project that represents -# the body of text which users will see when they visit PyPI. -# -# Often, this is the same as your README, so you can just read it in from -# that file directly (as we have already done above) -# -# This field corresponds to the "Description" metadata field: -# https://packaging.python.org/specifications/core-metadata/#description-optional readme = "README.md" # Optional - -# Specify which Python versions you support. In contrast to the -# 'Programming Language' classifiers above, 'pip install' will check this -# and refuse to install the project if the version does not match. See -# https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires -requires-python = ">=3.7" - -# This is either text indicating the license for the distribution, or a file -# that contains the license -# https://packaging.python.org/en/latest/specifications/core-metadata/#license -#license = {file = "LICENSE.txt"} - -# This field adds keywords for your project which will appear on the -# project page. What does your project relate to? -# -# Note that this is a list of additional keywords, separated -# by commas, to be used to assist searching for the distribution in a -# larger catalog. -#keywords = ["sample", "setuptools", "development"] # Optional - -# This should be your name or the name of the organization who originally -# authored the project, and a valid email address corresponding to the name -# listed. +requires-python = ">=3.9" authors = [ - {name = "Kyle Bittinger", email = "kylebitinger@gmail.com"}, + {name = "Kyle Bittinger", email = "kylebittinger@gmail.com"}, {name = "Charlie Bushman", email = "ctbushman@gmail.com" } # Optional ] -# This should be your name or the names of the organization who currently -# maintains the project, and a valid email address corresponding to the name -# listed. maintainers = [ {name = "Charlie Bushman", email = "ctbushman@gmail.com" } # Optional ] -# Classifiers help users find your project by categorizing it. -# -# For a list of valid classifiers, see https://pypi.org/classifiers/ -classifiers = [ # Optional - # How mature is this project? Common values are - # 3 - Alpha - # 4 - Beta - # 5 - Production/Stable +classifiers = [ "Development Status :: 5 - Production/Stable", - # Indicate who your project is intended for - #"Intended Audience :: Bioinformaticians", - #"Topic :: Bioinformatics :: Metagenomics", - - # Pick your license as you wish "License :: OSI Approved :: MIT License", - # Specify the Python versions you support here. In particular, ensure - # that you indicate you support Python 3. These classifiers are *not* - # checked by "pip install". See instead "python_requires" below. "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3 :: Only", ] -# This field lists other packages that your project depends on to run. -# Any package you put here will be installed by pip when your project is -# installed, so they must be valid existing projects. -# -# For an analysis of this field vs pip's requirements files see: -# https://packaging.python.org/discussions/install-requires-vs-requirements/ -dependencies = [ # Optional +dependencies = [ "sqlalchemy", + "seqbackup @ git+https://github.com/PennChopMicrobiomeProgram/seqBackup.git@master", ] -# List additional groups of dependencies here (e.g. development -# dependencies). Users will be able to install these using the "extras" -# syntax, for example: -# -# $ pip install sampleproject[dev] -# -# Similar to `dependencies` above, these must be valid existing -# projects. [project.optional-dependencies] # Optional dev = ["black"] test = ["pytest", "pytest-cov"] -# List URLs that are relevant to your project -# -# This field corresponds to the "Project-URL" and "Home-Page" metadata fields: -# https://packaging.python.org/specifications/core-metadata/#project-url-multiple-use -# https://packaging.python.org/specifications/core-metadata/#home-page-optional -# -# Examples listed include a pattern for specifying where the package tracks -# issues, where the source is hosted, where to say thanks to the package -# maintainers, and where to support the project financially. The key is -# what's used to render the link text on PyPI. [project.urls] # Optional "Homepage" = "https://github.com/PennChopMicrobiomeProgram/SampleRegistry/" "Bug Reports" = "https://github.com/PennChopMicrobiomeProgram/SampleRegistry/issues" -#"Funding" = "https://donate.pypi.org" -#"Say Thanks!" = "http://saythanks.io/to/example" "Source" = "https://github.com/PennChopMicrobiomeProgram/SampleRegistry/" -# The following would provide a command line executable called `sample` -# which executes the function `main` from this package when invoked. [project.scripts] # Optional register_run = "sample_registry.register:register_run" modify_run = "sample_registry.register:modify_run" @@ -154,13 +56,9 @@ export_samples = "sample_registry.export:export_samples" create_test_db = "sample_registry.db:create_test_db" sample_registry_version = "sample_registry:sample_registry_version" -# This is configuration specific to the `setuptools` build backend. -# If you are using a different build backend, you will need to change this. [tool.setuptools] [build-system] -# These are the assumed default build requirements from pip: -# https://pip.pypa.io/en/stable/reference/pip/#pep-517-and-518-support requires = ["setuptools>=61.0.0", "wheel"] build-backend = "setuptools.build_meta" diff --git a/app/sample_registry/src/sample_registry/__init__.py b/app/sample_registry/src/sample_registry/__init__.py index b8e49ce..92eb9ff 100644 --- a/app/sample_registry/src/sample_registry/__init__.py +++ b/app/sample_registry/src/sample_registry/__init__.py @@ -4,7 +4,7 @@ from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker -__version__ = "1.1.0" +__version__ = "1.1.1" # Doesn't include "NA" because that's what we fill in for missing values diff --git a/app/sample_registry/src/sample_registry/illumina.py b/app/sample_registry/src/sample_registry/illumina.py deleted file mode 100644 index c605562..0000000 --- a/app/sample_registry/src/sample_registry/illumina.py +++ /dev/null @@ -1,74 +0,0 @@ -import os.path -import re - - -class IlluminaFastq(object): - machine_types = { - "D": "Illumina-HiSeq", - "M": "Illumina-MiSeq", - "A": "Illumina-NovaSeq", - "N": "Illumina-MiniSeq", - "V": "Illumina-NextSeq", - } - - def __init__(self, f): - self.file = f - self.fastq_info = self._parse_header() - - def _parse_header(self): - line = next(self.file).strip() - if not line.startswith("@"): - raise ValueError("Not a FASTQ header line") - # Remove first character, @ - line = line[1:] - word1, _, word2 = line.partition(" ") - - keys1 = ("instrument", "run_number", "flowcell_id", "lane") - vals1 = dict((k, v) for k, v in zip(keys1, word1.split(":"))) - - keys2 = ("read", "is_filtered", "control_number", "index_reads") - vals2 = dict((k, v) for k, v in zip(keys2, word2.split(":"))) - - vals1.update(vals2) - return vals1 - - @property - def machine_type(self): - instrument_code = self.fastq_info["instrument"][0] - return self.machine_types[instrument_code] - - @property - def date(self): - dirs = splitall(self.file.name) - rundir = dirs[1] - if not re.match("\\d{6}_", rundir): - raise ValueError("Could not find date in folder name: {0}".format(rundir)) - year = rundir[0:2] - month = rundir[2:4] - day = rundir[4:6] - return "20{0}-{1}-{2}".format(year, month, day) - - @property - def lane(self): - return self.fastq_info["lane"] - - @property - def filepath(self): - return self.file.name - - -# From https://www.safaribooksonline.com/library/view/python-cookbook/0596001673/ch04s16.html -def splitall(path): - allparts = [] - while 1: - left, right = os.path.split(path) - if left == path: # sentinel for absolute paths - allparts.insert(0, left) - break - elif right == path: # sentinel for relative paths - allparts.insert(0, right) - break - else: - path = left - allparts.insert(0, right) - return allparts diff --git a/app/sample_registry/src/sample_registry/register.py b/app/sample_registry/src/sample_registry/register.py index 681f368..7f0d8a1 100644 --- a/app/sample_registry/src/sample_registry/register.py +++ b/app/sample_registry/src/sample_registry/register.py @@ -6,8 +6,8 @@ from sqlalchemy.orm import Session from typing import Generator from sample_registry.mapping import SampleTable -from sample_registry.illumina import IlluminaFastq from sample_registry.registrar import SampleRegistry +from seqBackupLib.illumina import IlluminaFastq SAMPLES_DESC = """\ @@ -145,7 +145,12 @@ def register_illumina_file(argv=None, session: Session = None, out=sys.stdout): registry = SampleRegistry(session) f = IlluminaFastq(gzip.open(args.file, "rt")) acc = registry.register_run( - f.date, f.machine_type, "Nextera XT", f.lane, f.filepath, args.comment + f.folder_info["date"], + f.machine_type, + "Nextera XT", + f.lane, + str(f.filepath), + args.comment, ) registry.session.commit() diff --git a/app/sample_registry/test/test_illumina.py b/app/sample_registry/test/test_illumina.py deleted file mode 100644 index 7b66951..0000000 --- a/app/sample_registry/test/test_illumina.py +++ /dev/null @@ -1,19 +0,0 @@ -from io import StringIO -from src.sample_registry.illumina import IlluminaFastq - - -def test_illuminafastq(): - fastq_file = StringIO( - "@M03543:47:C8LJ2ANXX:1:2209:1084:2044 1:N:0:NNNNNNNN+NNNNNNNN" - ) - fastq_filepath = ( - "Miseq/160511_M03543_0047_000000000-APE6Y/Data/Intensities/" - "BaseCalls/Undetermined_S0_L001_R1_001.fastq.gz" - ) - fastq_file.name = fastq_filepath - fq = IlluminaFastq(fastq_file) - - assert fq.machine_type == "Illumina-MiSeq" - assert fq.date == "2016-05-11" - assert fq.lane == "1" - assert fq.filepath == fastq_filepath diff --git a/requirements.txt b/requirements.txt index 579b019..8f5236e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ flask flask-sqlalchemy -sqlalchemy -psycopg2-binary \ No newline at end of file +sqlalchemy \ No newline at end of file