diff --git a/HISTORY.txt b/HISTORY.txt index 39413a6..92b4514 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -145,3 +145,5 @@ 04-May-2025 - V1.32 Add methods and support for IHM structure loading 12-Jun-2025 - V1.33 Add transformation to populate rcsb_entry_container_identifiers.pubmed_id and rcsb_polymer_entity_container_identifiers.uniprot_ids 27-Jun-2025 - V1.34 Add transformation to populate rcsb_polymer_instance_info + 4-Nov-2025 - V1.35 Strip newline characters from 'chem_comp.name'; + Switch to 'pyproject.toml' file and hatch build system, and update pipelines to Python 3.13 diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index dbdbdeb..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,7 +0,0 @@ -# -# File: py-rcsb_utils_dictionary/MANIFEST.in -# -include HISTORY.txt -include requirements.txt -include README.md -# \ No newline at end of file diff --git a/README.md b/README.md index fc1b546..b1b1172 100644 --- a/README.md +++ b/README.md @@ -24,14 +24,9 @@ git clone --recurse-submodules https://github.com/rcsb/py-rcsb_utils_dictionary. ``` Optionally, run test suite (Python versions 3.7+) using -[setuptools](https://setuptools.readthedocs.io/en/latest/) or [tox](http://tox.readthedocs.io/en/latest/example/platform.html): ```bash -python setup.py test - -or simply run - tox ``` diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1f29aa8..ec95d97 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -12,7 +12,6 @@ name: $(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.rr) trigger: - master - - utilsdict-* pr: - master @@ -27,20 +26,18 @@ schedules: jobs: - template: azure-template-tox-job.yml - parameters: { tox: "format_pep8", python: "3.10", os: "linux" } + parameters: { tox: "format_pep8", python: "3.13", os: "linux" } - template: azure-template-tox-job.yml - parameters: { tox: "lint_pylint", python: "3.10", os: "linux" } + parameters: { tox: "lint_pylint", python: "3.13", os: "linux" } - template: azure-template-tox-job.yml - parameters: { tox: "test_coverage", python: "3.10", os: "linux" } + parameters: { tox: "test_coverage", python: "3.13", os: "linux" } # - template: azure-template-tox-job.yml - parameters: { tox: "py310", python: "3.10", os: "linux" } + parameters: { tox: "py313", python: "3.13", os: "linux" } # - template: azure-template-tox-job.yml - parameters: { tox: "py310", python: "3.10", os: "macos" } + parameters: { tox: "py313", python: "3.13", os: "macos" } # - #- template: azure-template-publish-job.yml - # parameters: {tox: "py310", python: "3.10", os: 'macos'} - template: azure-template-publish-job.yml - parameters: { tox: "py310", python: "3.10", os: "linux" } + parameters: { tox: "py313", python: "3.13", os: "linux" } # diff --git a/azure-template-publish-job.yml b/azure-template-publish-job.yml index 08b5248..3348d78 100644 --- a/azure-template-publish-job.yml +++ b/azure-template-publish-job.yml @@ -41,7 +41,7 @@ jobs: - script: ls -lR $(Pipeline.Workspace)/${{ format('sw_{0}_{1}', parameters.tox, parameters.os) }} displayName: "Listing of downloaded artifacts" # - - script: python -m pip install --upgrade pip twine setuptools wheel + - script: python -m pip install --upgrade pip twine wheel hatch displayName: 'Install packaging tools' # - task: DownloadSecureFile@1 diff --git a/azure-template-tox-job.yml b/azure-template-tox-job.yml index 59a6dfc..5cca9ec 100644 --- a/azure-template-tox-job.yml +++ b/azure-template-tox-job.yml @@ -35,6 +35,7 @@ jobs: # - checkout: self submodules: true + fetchDepth: 1 # - ${{ if startsWith(parameters.os, 'macos') }}: - bash: | @@ -66,62 +67,96 @@ jobs: # - script: sudo apt-get update displayName: "update apt" - #- script: sudo apt-get upgrade - # displayName: 'upgrade apt' - #- script: sudo apt-get update - # displayName: 'update apt' - script: sudo apt-get install flex displayName: "Install flex" - script: sudo apt-get install bison displayName: "Install bison" # + - ? ${{ if and(contains(parameters.fixtures, 'mysql'), startsWith(parameters.os, 'linux')) }} + : - bash: | + sudo apt-get install libmysqlclient-dev python-mysqldb + sudo apt list --installed | grep -i mysql + displayName: "Install mysql development libraries" + - bash: | + echo "Retarting mysql service" + sudo systemctl restart mysql.service + mysql -V + mysql --user=root --password=root -e "use mysql; select * from user;" + # + echo "Try resetting password" + mysqladmin --user=root --password=root password 'ChangeMeSoon' + # + # mysql -u root -p root -e "SET PASSWORD FOR root@'localhost' = PASSWORD(‘ChangeMeSoon’);" + # mysql -u root -p root -e "FLUSH PRIVILEGES; update mysql.user set password=password('ChangeMeSoon') where user='root'; FLUSH PRIVILEGES;" + # UPDATE mysql.user SET Password=PASSWORD('ChangeMeSoon') WHERE User='root'; + + echo "Running preliminary mysql setup" + mysql --user=root --password=ChangeMeSoon <<_EOF_ + DELETE FROM mysql.user WHERE User=''; + DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1'); + DROP DATABASE IF EXISTS test; + DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%'; + FLUSH PRIVILEGES; + _EOF_ + ps -ef | grep -i my + mysql --user=root --password=ChangeMeSoon -e "show databases;" + # + displayName: "Start and configure mysql ..." + + # ----- + - ? ${{ if and(contains(parameters.fixtures, 'mongodb'), startsWith(parameters.os, 'linux')) }} + : # Mongo install + - script: | + sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 9DA31620334BD75D9DCB49F368818C72E52529D4 + sudo apt list --installed | grep mongodb + echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/4.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.0.list + sudo apt-get update + sudo apt-get install -y mongodb-org + sudo apt list --installed | grep mongo + displayName: "Installing mongodb" + # + - script: | + sudo service mongod start + sudo ss -tulpn + displayName: "Start Mongo service" + # + # - script: 'python -c "import sys; print(sys.version); print(sys.executable)"' displayName: show python information # - script: python -m pip install --upgrade pip tox displayName: "Install tools" # - - script: pip install -r requirements.txt + - script: pip install .[tests] displayName: "Install dependencies" # + # - task: DownloadSecureFile@1 + # name: oelicense + # displayName: 'Download OE license file' + # inputs: + # secureFile: 'oe_license.txt' # - - task: DownloadSecureFile@1 - name: oelicense - displayName: "Download OE license file" - inputs: - secureFile: "oe_license.txt" - - ${{ if startsWith(parameters.tox, 'py') }}: - script: | - export OE_LICENSE=$(oelicense.secureFilePath) export CONFIG_SUPPORT_TOKEN_ENV=$(VAR_CONFIG_SUPPORT_TOKEN_ENV) ${{ format('python -m tox -e {0}', parameters.tox) }} displayName: "Running tox task" - - ? ${{ if and(not(startsWith(parameters.tox, 'py')), startsWith(parameters.python, '3.10')) }} + - ? ${{ if and(not(startsWith(parameters.tox, 'py')), startsWith(parameters.python, '3.13')) }} : - script: | - export OE_LICENSE=$(oelicense.secureFilePath) export CONFIG_SUPPORT_TOKEN_ENV=$(VAR_CONFIG_SUPPORT_TOKEN_ENV) - ${{ format('python -m tox -e {0}-py310', parameters.tox) }} - displayName: "Running tox task" - - ? ${{ if and(not(startsWith(parameters.tox, 'py')), startsWith(parameters.python, '3.9')) }} - : - script: | - export OE_LICENSE=$(oelicense.secureFilePath) - export CONFIG_SUPPORT_TOKEN_ENV=$(VAR_CONFIG_SUPPORT_TOKEN_ENV) - ${{ format('python -m tox -e {0}-py39', parameters.tox) }} + ${{ format('python -m tox -e {0}-py313', parameters.tox) }} displayName: "Running tox task" # # Build artifacts if this is a test target (i.e. labeled as py##) # - ${{ if startsWith(parameters.tox, 'py') }}: - - script: pip install --upgrade pip twine setuptools wheel + - script: pip install --upgrade pip build twine hatch displayName: "Acquire build tools" - - script: python setup.py sdist --dist-dir "$(System.DefaultWorkingDirectory)/dist" - displayName: "Build source dist" - - script: python setup.py bdist_wheel --dist-dir "$(System.DefaultWorkingDirectory)/dist" - displayName: "Build wheel" - # - - script: python setup.py sdist --dist-dir "$(System.DefaultWorkingDirectory)/udist" - displayName: "Build source dist" + - script: python -m build --sdist --wheel --outdir "$(System.DefaultWorkingDirectory)/dist" + displayName: "Build source and wheel distributions" + - script: python -m build --sdist --outdir "$(System.DefaultWorkingDirectory)/udist" + displayName: "Build source distribution to udist" + # # Check the install artifacts - script: ls -lR "$(System.DefaultWorkingDirectory)/dist" "$(System.DefaultWorkingDirectory)/udist" diff --git a/pyproject.toml b/pyproject.toml new file mode 100755 index 0000000..c575792 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,88 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "rcsb.utils.dictionary" +description = "RCSB Python Dictionary Utility Classes" +readme = "README.md" +authors = [ + { name="John Westbrook", email="john.westbrook@rcsb.org" } +] +maintainers = [ + { name="Dennis Piehl", email="dennis.piehl@rcsb.org" } +] +license = "Apache-2.0" +license-files = ["LICENSE"] +requires-python = ">=3.9" +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Natural Language :: English", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.13", +] +dependencies = [ + "scipy", + "numpy", + "mmcif >= 0.91.0", + "rcsb.utils.chemref >= 0.91", + "rcsb.utils.citation >= 0.25", + "rcsb.utils.config >= 0.40", + "rcsb.utils.ec >= 0.25", + "rcsb.utils.io >= 1.52", + "rcsb.utils.multiproc >= 0.19", + "rcsb.utils.repository >= 0.50", + "rcsb.utils.seq >= 0.82", + "rcsb.utils.struct >= 0.47", + "rcsb.utils.targets >= 0.88", + "rcsb.utils.taxonomy >= 0.43", + "rcsb.utils.validation >= 0.31", + "rcsb.utils.insilico3d >= 0.42", +] +dynamic = ["version"] + +[project.optional-dependencies] +tests = ["tox", "pylint", "black>=21.5b1", "flake8", "coverage"] + +[project.urls] +Homepage = "https://github.com/rcsb/py-rcsb_utils_dictionary" + +# ---------------- hatch configuration ---------------- +[tool.hatch.version] +path = "rcsb/utils/dictionary/__init__.py" + +[tool.hatch.build] +exclude = [ + "/rcsb/utils/test*/**", + "/rcsb/mock-*/**", + "test*/**" +] + +[tool.hatch.build.targets.sdist] +include = [ + "/rcsb/**", + "/README.md", + "/LICENSE", + "/HISTORY.txt", + "/pyproject.toml" +] + +[tool.hatch.build.targets.wheel] +packages = ["rcsb"] + +[tool.hatch.envs.default] +skip-install = true + +# ---------------- test configuration ---------------- +[tool.hatch.envs.hatch-test] +dependencies = ["tox"] + +[tool.hatch.envs.hatch-test.scripts] +run = ["tox"] + +# ---------------- UV configuration ---------------- +# Add this to prevent uv from automatically creating venvs within individual packages when running 'uv run ...' from within the package directory +[tool.uv] +managed = false diff --git a/rcsb/utils/dictionary/DictMethodChemRefHelper.py b/rcsb/utils/dictionary/DictMethodChemRefHelper.py index b0a22b8..db5a262 100644 --- a/rcsb/utils/dictionary/DictMethodChemRefHelper.py +++ b/rcsb/utils/dictionary/DictMethodChemRefHelper.py @@ -10,6 +10,7 @@ # 18-Sep-2023 dwp Load COD references separately from CCDC/CSD references # 3-May-2024 dwp Change BIRD citation method to copy categories instead of just renaming, and only apply to BIRD entries # 25-Jul-2024 dwp Fix assignment logic of Pharos data for rcsb_chem_comp_related.related_mapping_method in addChemCompRelated() +# 4-Nov-2025 dwp Strip newline characters from 'chem_comp.name' ## """ Helper class implements external method references supporting chemical @@ -901,6 +902,8 @@ def addChemCompSynonyms(self, dataContainer, catName, **kwargs): ccObj = dataContainer.getObj("chem_comp") ccId = ccObj.getValue("id", 0) ccName = ccObj.getValue("name", 0) + if ccName: + ccName = ccName.replace("\n", "") # strip newline characters # ccSynonymL = [] # if ccObj.hasAttribute("pdbx_synonyms"): # ccSynonymL = str(ccObj.getValue("pdbx_synonyms", 0)).split(";") diff --git a/rcsb/utils/dictionary/DictMethodCompModelHelper.py b/rcsb/utils/dictionary/DictMethodCompModelHelper.py index 5c1b0f5..f02ad7d 100644 --- a/rcsb/utils/dictionary/DictMethodCompModelHelper.py +++ b/rcsb/utils/dictionary/DictMethodCompModelHelper.py @@ -381,7 +381,7 @@ def buildCompModelProvenance(self, dataContainer, catName, **kwargs): return False if catName != "rcsb_comp_model_provenance": - logger.warning("input catName (%s) not 'rcsb_comp_model_provenance'") + logger.warning("input catName (%s) not 'rcsb_comp_model_provenance'", catName) catName = "rcsb_comp_model_provenance" diff --git a/rcsb/utils/dictionary/DictMethodEntityHelper.py b/rcsb/utils/dictionary/DictMethodEntityHelper.py index 3dcddd7..faa1c8b 100644 --- a/rcsb/utils/dictionary/DictMethodEntityHelper.py +++ b/rcsb/utils/dictionary/DictMethodEntityHelper.py @@ -21,7 +21,8 @@ # 20-Aug-2024 dwp Add support for accessing target cofactor data from MongoDB # 7-Jan-2025 bv Stop populating rcsb_nonpolymer_instance_feature_summary from rcsb_entity_instance_validation_feature_summary # 15-Feb-2025 bv Add support for integrative structures -# 12-June-2025 bv Add tranformation to populate rcsb_polymer_entity_container_identifiers.uniprot_ids +# 12-Jun-2025 bv Add tranformation to populate rcsb_polymer_entity_container_identifiers.uniprot_ids +# 12-Nov-2025 dwp Add failover for cases where ncbi_taxonomy_id is not an integer, and log an error ## """ Helper class implements methods supporting entity-level item and category methods in the RCSB dictionary extension. @@ -736,34 +737,39 @@ def filterSourceOrganismDetails(self, dataContainer, catName, **kwargs): cObj.setValue(";".join([provSource for jj in range(len(tgL))]), "rcsb_gene_name_provenance_source", iRow) else: cObj.setValue(v[ii], at, iRow) - # if at == 'ncbi_taxonomy_id' and v[ii] and v[ii] not in ['.', '?'] and v[ii].isdigit(): if at == "ncbi_taxonomy_id" and v[ii] and v[ii] not in [".", "?"]: - taxId = int(self.__reNonDigit.sub("", v[ii])) - taxId = taxU.getMergedTaxId(taxId) - cObj.setValue(str(taxId), "ncbi_taxonomy_id", iRow) - entryTaxIdD[taxId] += 1 - entityTaxIdD.setdefault(entityId, set()).add(taxId) - # - sn = taxU.getScientificName(taxId) - if sn: - cObj.setValue(sn, "ncbi_scientific_name", iRow) - # - psn = taxU.getParentScientificName(taxId) - if psn: - cObj.setValue(psn, "ncbi_parent_scientific_name", iRow) - # - cnL = taxU.getCommonNames(taxId) - if cnL: - fcnL = self.__filterCaseDuplicates(cnL) - cObj.setValue(";".join(list(OrderedDict.fromkeys(fcnL))), "ncbi_common_names", iRow) - # Add lineage - - linL = taxU.getLineageWithNames(taxId) - if linL is not None: - cObj.setValue(";".join([str(tup[0]) for tup in OrderedDict.fromkeys(linL)]), "taxonomy_lineage_depth", iRow) - cObj.setValue(";".join([str(tup[1]) for tup in OrderedDict.fromkeys(linL)]), "taxonomy_lineage_id", iRow) - cObj.setValue(";".join([str(tup[2]) for tup in OrderedDict.fromkeys(linL)]), "taxonomy_lineage_name", iRow) + if not v[ii].strip().isdigit(): + logger.warning("Source attribute 'ncbi_taxonomy_id' value is not integer: %r. Will attempt to sanitize.", v[ii]) + reTaxId = self.__reNonDigit.sub("", v[ii]) + if not reTaxId.isdigit(): + logger.error("Source attribute 'ncbi_taxonomy_id' value is not integer: %r", v[ii]) else: - logger.warning("%s taxId %r lineage %r", dataContainer.getName(), taxId, linL) + taxId = int(reTaxId) + taxId = taxU.getMergedTaxId(taxId) + cObj.setValue(str(taxId), "ncbi_taxonomy_id", iRow) + entryTaxIdD[taxId] += 1 + entityTaxIdD.setdefault(entityId, set()).add(taxId) + # + sn = taxU.getScientificName(taxId) + if sn: + cObj.setValue(sn, "ncbi_scientific_name", iRow) + # + psn = taxU.getParentScientificName(taxId) + if psn: + cObj.setValue(psn, "ncbi_parent_scientific_name", iRow) + # + cnL = taxU.getCommonNames(taxId) + if cnL: + fcnL = self.__filterCaseDuplicates(cnL) + cObj.setValue(";".join(list(OrderedDict.fromkeys(fcnL))), "ncbi_common_names", iRow) + # Add lineage - + linL = taxU.getLineageWithNames(taxId) + if linL is not None: + cObj.setValue(";".join([str(tup[0]) for tup in OrderedDict.fromkeys(linL)]), "taxonomy_lineage_depth", iRow) + cObj.setValue(";".join([str(tup[1]) for tup in OrderedDict.fromkeys(linL)]), "taxonomy_lineage_id", iRow) + cObj.setValue(";".join([str(tup[2]) for tup in OrderedDict.fromkeys(linL)]), "taxonomy_lineage_name", iRow) + else: + logger.warning("%s taxId %r lineage %r", dataContainer.getName(), taxId, linL) logger.debug("%r entity %r - UPDATED %r %r", sType, entityId, atL, v) iRow += 1 @@ -791,30 +797,35 @@ def filterSourceOrganismDetails(self, dataContainer, catName, **kwargs): hObj.setValue(provSource, "provenance_source", iRow) for ii, at in enumerate(atL): hObj.setValue(v[ii], at, iRow) - # if at == 'ncbi_taxonomy_id' and v[ii] and v[ii] not in ['.', '?'] and v[ii].isdigit(): if at == "ncbi_taxonomy_id" and v[ii] and v[ii] not in [".", "?"]: - taxId = int(self.__reNonDigit.sub("", v[ii])) - taxId = taxU.getMergedTaxId(taxId) - hObj.setValue(str(taxId), "ncbi_taxonomy_id", iRow) - sn = taxU.getScientificName(taxId) - if sn: - hObj.setValue(sn, "ncbi_scientific_name", iRow) - # - psn = taxU.getParentScientificName(taxId) - if psn: - hObj.setValue(psn, "ncbi_parent_scientific_name", iRow) - # - cnL = taxU.getCommonNames(taxId) - if cnL: - hObj.setValue(";".join(sorted(set(cnL))), "ncbi_common_names", iRow) - # Add lineage - - linL = taxU.getLineageWithNames(taxId) - if linL is not None: - hObj.setValue(";".join([str(tup[0]) for tup in OrderedDict.fromkeys(linL)]), "taxonomy_lineage_depth", iRow) - hObj.setValue(";".join([str(tup[1]) for tup in OrderedDict.fromkeys(linL)]), "taxonomy_lineage_id", iRow) - hObj.setValue(";".join([str(tup[2]) for tup in OrderedDict.fromkeys(linL)]), "taxonomy_lineage_name", iRow) + if not v[ii].strip().isdigit(): + logger.warning("Host attribute 'ncbi_taxonomy_id' value is not integer: %r. Will attempt to sanitize.", v[ii]) + reTaxId = self.__reNonDigit.sub("", v[ii]) + if not reTaxId.isdigit(): + logger.error("Host attribute 'ncbi_taxonomy_id' value is not integer: %r", v[ii]) else: - logger.warning("%s taxId %r lineage %r", dataContainer.getName(), taxId, linL) + taxId = int(reTaxId) + taxId = taxU.getMergedTaxId(taxId) + hObj.setValue(str(taxId), "ncbi_taxonomy_id", iRow) + sn = taxU.getScientificName(taxId) + if sn: + hObj.setValue(sn, "ncbi_scientific_name", iRow) + # + psn = taxU.getParentScientificName(taxId) + if psn: + hObj.setValue(psn, "ncbi_parent_scientific_name", iRow) + # + cnL = taxU.getCommonNames(taxId) + if cnL: + hObj.setValue(";".join(sorted(set(cnL))), "ncbi_common_names", iRow) + # Add lineage - + linL = taxU.getLineageWithNames(taxId) + if linL is not None: + hObj.setValue(";".join([str(tup[0]) for tup in OrderedDict.fromkeys(linL)]), "taxonomy_lineage_depth", iRow) + hObj.setValue(";".join([str(tup[1]) for tup in OrderedDict.fromkeys(linL)]), "taxonomy_lineage_id", iRow) + hObj.setValue(";".join([str(tup[2]) for tup in OrderedDict.fromkeys(linL)]), "taxonomy_lineage_name", iRow) + else: + logger.warning("%s taxId %r lineage %r", dataContainer.getName(), taxId, linL) logger.debug("%r entity %r - UPDATED %r %r", sType, entityId, atL, v) iRow += 1 # ------------------------------------------------------------------------- diff --git a/rcsb/utils/dictionary/__init__.py b/rcsb/utils/dictionary/__init__.py index cbbc7f4..63e3bf1 100644 --- a/rcsb/utils/dictionary/__init__.py +++ b/rcsb/utils/dictionary/__init__.py @@ -2,4 +2,4 @@ __author__ = "John Westbrook" __email__ = "john.westbrook@rcsb.org" __license__ = "Apache 2.0" -__version__ = "1.34" +__version__ = "1.35" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 4e56b7d..0000000 --- a/requirements.txt +++ /dev/null @@ -1,16 +0,0 @@ -scipy -numpy -mmcif >= 0.91.0 -rcsb.utils.chemref >= 0.91 -rcsb.utils.citation >= 0.22 -rcsb.utils.config >= 0.40 -rcsb.utils.ec >= 0.25 -rcsb.utils.io >= 1.48 -rcsb.utils.multiproc >= 0.19 -rcsb.utils.repository >= 0.50 -rcsb.utils.seq >= 0.82 -rcsb.utils.struct >= 0.47 -rcsb.utils.targets >= 0.82 -rcsb.utils.taxonomy >= 0.43 -rcsb.utils.validation >= 0.31 -rcsb.utils.insilico3d >= 0.38 diff --git a/setup.cfg b/setup.cfg deleted file mode 100755 index 360a483..0000000 --- a/setup.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[bdist_wheel] -# use py2.py3 tag for pure-python dist: -universal=1 - -[metadata] -description_file = README.md - diff --git a/setup.py b/setup.py deleted file mode 100755 index 3fd1b4a..0000000 --- a/setup.py +++ /dev/null @@ -1,67 +0,0 @@ -# File: setup.py -# Date: 14-Feb-2021 -# -# Update: -# -import re - -from setuptools import find_packages -from setuptools import setup - -packages = [] -thisPackage = "rcsb.utils.dictionary" - -with open("rcsb/utils/dictionary/__init__.py", "r", encoding="utf-8") as fd: - version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', fd.read(), re.MULTILINE).group(1) - -# Load packages from requirements*.txt -with open("requirements.txt", "r", encoding="utf-8") as ifh: - packagesRequired = [ln.strip() for ln in ifh.readlines()] - -with open("README.md", "r", encoding="utf-8") as ifh: - longDescription = ifh.read() - -if not version: - raise RuntimeError("Cannot find version information") - -setup( - name=thisPackage, - version=version, - description="RCSB Python Dictionary Utility Classes", - long_description_content_type="text/markdown", - long_description=longDescription, - author="John Westbrook", - author_email="john.westbrook@rcsb.org", - url="https://github.com/rcsb/py-rcsb_utils_dictionary", - # - license="Apache 2.0", - classifiers=( - "Development Status :: 3 - Alpha", - # 'Development Status :: 5 - Production/Stable', - "Intended Audience :: Developers", - "Natural Language :: English", - "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.10", - ), - entry_points={}, - # - install_requires=packagesRequired, - packages=find_packages(exclude=["rcsb.utils.tests-dictionary", "rcsb.utils.tests-*", "tests.*"]), - package_data={ - # If any package contains *.md or *.rst ... files, include them: - "": ["*.md", "*.rst", "*.txt", "*.cfg"] - }, - # - # These basic tests require no database services - - test_suite="rcsb.utils.tests-dictionary", - tests_require=["tox"], - # - # Not configured ... - extras_require={"dev": ["check-manifest"], "test": ["coverage"]}, - # Added for - command_options={"build_sphinx": {"project": ("setup.py", thisPackage), "version": ("setup.py", version), "release": ("setup.py", version)}}, - # This setting for namespace package support - - zip_safe=False, -) diff --git a/tox.ini b/tox.ini index 364aeac..e285bd4 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ test_pattern = "test*.py" # # Source pathls (unquoted space separated list of files/directories) for linting and format checks -source_paths = rcsb/utils/dictionary rcsb/utils/tests-dictionary setup.py +source_paths = rcsb/utils/dictionary rcsb/utils/tests-dictionary # # Start directory path for test discovery # Each path must reference valid directory that is searchable by Python (i.e. contains __init__.py) @@ -13,9 +13,7 @@ source_paths = rcsb/utils/dictionary rcsb/utils/tests-dictionary setup.py # test_path_1 = "rcsb/utils/tests-dictionary" # These are placeholders valid source directories without tests files -test_path_2 = "rcsb/utils/dictionary" -test_path_3 = "rcsb/utils/dictionary" -test_path_4 = "rcsb/utils/dictionary" +# test_path_2 = "rcsb/utils/tests-dictionary" # # Comma separate list of directories for which test coverage will be evaluated coverage_source_paths = "rcsb/utils/dictionary,rcsb/utils/tests-dictionary" @@ -34,111 +32,95 @@ coverage_cutoff = 50 ## [tox] # The complete list of supported test environments to setup and invoke -envlist = format_pep8-{py310}, lint_pylint-{py310}, format_black-{py310}, py{310} +envlist = format_pep8-{py313}, lint_pylint-{py313}, format_black-{py313}, py{313}, test_coverage-{py313} # -minversion = 3.7.0 +minversion = 3.4.0 skip_missing_interpreters = true -skipsdist = True +skipsdist = false [testenv] -passenv = CONFIG_SUPPORT_TOKEN_ENV,OE_LICENSE +passenv = CONFIG_SUPPORT_TOKEN_ENV allowlist_externals = echo -basepython = py310: python3.10 commands = echo "Starting default tests in testenv" +basepython = py313: python3.13 -[testenv:py310] +[testenv:py313] description = 'Run unit tests (unittest runner) using {envpython}' -platform= - macos: darwin - linux: linux -skip_install = True -sitepackages = True -recreate = True -alwayscopy=True -package = editable-legacy +platform = + macos: darwin + linux: linux +skip_install = false +recreate = true +alwayscopy = true +usedevelop = true deps = - -r requirements.txt + .[tests] commands = - echo "Starting {envname} with {envpython}" + echo "Starting {envname}" {envpython} -V {envpython} -m unittest discover -v --start-directory {[local_settings]test_path_1} --pattern "{[local_settings]test_pattern}" - {envpython} -m unittest discover -v --start-directory {[local_settings]test_path_2} --pattern "{[local_settings]test_pattern}" - {envpython} -m unittest discover -v --start-directory {[local_settings]test_path_3} --pattern "{[local_settings]test_pattern}" - {envpython} -m unittest discover -v --start-directory {[local_settings]test_path_4} --pattern "{[local_settings]test_pattern}" - echo "Completed {envname} with {envpython}" + # {envpython} -m unittest discover -v --start-directory {[local_settings]test_path_2} --pattern "{[local_settings]test_pattern}" + echo "Completed {envname}" # -[testenv:format_pep8-py310] +[testenv:format_pep8-py313] description = 'Run selected PEP8 compliance checks (flake8)' -platform= +platform = macos: darwin linux: linux deps = - flake8 - # This plugin is no longer compatible with latest pydocstyles - - # flake8-docstrings>=0.2.7 - flake8-import-order>=0.9 - -r requirements.txt + .[tests] commands = - echo "Starting {envname}" # Exceptions: D for docstrings, I for imports order and formatting, E302 is slice spacing - W503 multiline spacing incompatible with black flake8 --max-line-length=185 --ignore=D,I,E203,W503 {[local_settings]source_paths} - echo "Completed {envname}" # -[testenv:lint_pylint-py310] +[testenv:lint_pylint-py313] description = 'Run linting compliance checks (pylint)' platform= macos: darwin linux: linux deps = - pylint - -r requirements.txt + .[tests] commands = echo "Starting {envname}" pylint --disable=R,C --reports=n --rcfile={toxinidir}/pylintrc {[local_settings]source_paths} echo "Completed {envname}" # -[testenv:format_black-py310] +[testenv:format_black-py313] description = 'Run format compliance checks (black)' -platform= +platform = macos: darwin linux: linux deps = - black>=21.5b1 - -r requirements.txt - # isort>=4.3.20 + .[tests] commands = echo "Starting {envname}" black --check --line-length 185 {[local_settings]source_paths} - # isort -rc rcsb/utils --check-only echo "Completed {envname}" # -[testenv:test_coverage-py310] +[testenv:test_coverage-py313] description = 'Run test coverage analysis' -platform= +platform = macos: darwin linux: linux recreate = true -alwayscopy=true -package = editable-legacy +alwayscopy = true +usedevelop = true deps = - coverage - -r requirements.txt + .[tests] commands = echo "Starting {envname}" coverage erase coverage run --parallel-mode --omit="{[local_settings]coverage_exclude_paths}" --source="{[local_settings]coverage_source_paths}" -m unittest discover -v --start-directory {[local_settings]test_path_1} --pattern "{[local_settings]test_pattern}" - coverage run --parallel-mode --omit="{[local_settings]coverage_exclude_paths}" --source="{[local_settings]coverage_source_paths}" -m unittest discover -v --start-directory {[local_settings]test_path_2} --pattern "{[local_settings]test_pattern}" - coverage run --parallel-mode --omit="{[local_settings]coverage_exclude_paths}" --source="{[local_settings]coverage_source_paths}" -m unittest discover -v --start-directory {[local_settings]test_path_3} --pattern "{[local_settings]test_pattern}" - coverage run --parallel-mode --omit="{[local_settings]coverage_exclude_paths}" --source="{[local_settings]coverage_source_paths}" -m unittest discover -v --start-directory {[local_settings]test_path_4} --pattern "{[local_settings]test_pattern}" - echo " ------- Consolidating {envname} data ----------" + # coverage run --parallel-mode --omit="{[local_settings]coverage_exclude_paths}" --source="{[local_settings]coverage_source_paths}" -m unittest discover -v --start-directory {[local_settings]test_path_2} --pattern "{[local_settings]test_pattern}" + echo " ------- Consolidating {envname} data ----------" coverage combine echo " ------- Building {envname} reports ----------" coverage report --fail-under={[local_settings]coverage_cutoff} - coverage xml - echo "Completed {envname}" \ No newline at end of file + echo "Completed {envname}"