diff --git a/.coveragerc b/.coveragerc index e1c2549..2ead244 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,6 +1,8 @@ [run] source = spyrmsd -omit = spyrmsd/_version.py +omit = + spyrmsd/_version.py + spyrmsd/due.py [report] exclude_lines = diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..b6bd69c --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: ["https://www.buymeacoffee.com/rmeli"] diff --git a/.gitignore b/.gitignore index 20a5983..fb96dca 100644 --- a/.gitignore +++ b/.gitignore @@ -70,6 +70,9 @@ ENV/ # mypy .mypy_cache/ +# duecredit +.duecredit.p + # macOS .DS_Store diff --git a/README.md b/README.md index 2f20aa3..6b42569 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,10 @@ To ensure code quality and consistency the following tools are used during devel Copyright (c) 2019-2020, Rocco Meli. +## References + +References are tracked with [duecredit](https://github.com/duecredit/duecredit/). Run the `credits.sh` script in order to print up-to-date references. + ### Acknowledgements Project based on the [Computational Molecular Science Python Cookiecutter](https://github.com/molssi/cookiecutter-cms) version `1.1`. diff --git a/credits.sh b/credits.sh new file mode 100644 index 0000000..d50b841 --- /dev/null +++ b/credits.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +cd tests + +python -m duecredit test_import.py + +printf "\n\nBIBTEX\n------\n\n" + +duecredit summary --format bibtex \ No newline at end of file diff --git a/devtools/conda-envs/spyrmsd-all.yaml b/devtools/conda-envs/spyrmsd-all.yaml index 06a5a67..7c24732 100644 --- a/devtools/conda-envs/spyrmsd-all.yaml +++ b/devtools/conda-envs/spyrmsd-all.yaml @@ -35,7 +35,9 @@ dependencies: # Doc - sphinx - - sphinx_rtd_theme + - sphinx_rtd_theme + - pip: + - duecredit # Dev - mypy diff --git a/setup.py b/setup.py index 9b927b9..1d1e8f8 100644 --- a/setup.py +++ b/setup.py @@ -32,6 +32,7 @@ include_package_data=True, url="https://spyrmsd.readthedocs.io", install_requires=["numpy", "scipy", "qcelemental", "networkx>=2"], + extras_require={"bib": ["duecredit"]}, platforms=["Linux", "Mac OS-X", "Unix", "Windows"], python_requires=">=3.6", ) diff --git a/spyrmsd/__init__.py b/spyrmsd/__init__.py index e98056c..4f59222 100644 --- a/spyrmsd/__init__.py +++ b/spyrmsd/__init__.py @@ -2,10 +2,17 @@ Python RMSD tool with symmetry correction. """ -# Handle versioneer +from .due import due, Doi from ._version import get_versions versions = get_versions() __version__ = versions["version"] __git_revision__ = versions["full-revisionid"] del get_versions, versions + +# This will print latest Zenodo version +due.cite( + Doi("10.5281/zenodo.3631876"), # lgtm[py/procedure-return-value-used] + path="spyrmsd", + description="spyRMSD: Symmetry-Corrected RMSD in Python", +) diff --git a/spyrmsd/due.py b/spyrmsd/due.py new file mode 100644 index 0000000..82d15e0 --- /dev/null +++ b/spyrmsd/due.py @@ -0,0 +1,79 @@ +# emacs: at the end of the file +# ex: set sts=4 ts=4 sw=4 et: +# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### # +""" + +Stub file for a guaranteed safe import of duecredit constructs: if duecredit +is not available. + +To use it, place it into your project codebase to be imported, e.g. copy as + + cp stub.py /path/tomodule/module/due.py + +Note that it might be better to avoid naming it duecredit.py to avoid shadowing +installed duecredit. + +Then use in your code as + + from .due import due, Doi, BibTeX, Text + +See https://github.com/duecredit/duecredit/blob/master/README.md for examples. + +Origin: Originally a part of the duecredit +Copyright: 2015-2019 DueCredit developers +License: BSD-2 +""" + +__version__ = "0.0.8" + + +class InactiveDueCreditCollector(object): + """Just a stub at the Collector which would not do anything""" + + def _donothing(self, *args, **kwargs): + """Perform no good and no bad""" + pass + + def dcite(self, *args, **kwargs): + """If I could cite I would""" + + def nondecorating_decorator(func): + return func + + return nondecorating_decorator + + active = False + activate = add = cite = dump = load = _donothing + + def __repr__(self): + return self.__class__.__name__ + "()" + + +def _donothing_func(*args, **kwargs): + """Perform no good and no bad""" + pass + + +try: + from duecredit import due, BibTeX, Doi, Url, Text # lgtm[py/unused-import] + + if "due" in locals() and not hasattr(due, "cite"): + raise RuntimeError("Imported due lacks .cite. DueCredit is now disabled") +except Exception as e: + if not isinstance(e, ImportError): + import logging + + logging.getLogger("duecredit").error( + "Failed to import duecredit due to %s" % str(e) + ) + # Initiate due stub + due = InactiveDueCreditCollector() + BibTeX = Doi = Url = Text = _donothing_func + +# Emacs mode definitions +# Local Variables: +# mode: python +# py-indent-offset: 4 +# tab-width: 4 +# indent-tabs-mode: nil +# End: diff --git a/spyrmsd/hungarian.py b/spyrmsd/hungarian.py index b2cc7fb..1c36393 100644 --- a/spyrmsd/hungarian.py +++ b/spyrmsd/hungarian.py @@ -1,6 +1,14 @@ import numpy as np import scipy +from .due import due, Doi + +due.cite( + Doi("10.1021/ci400534h"), # lgtm[py/procedure-return-value-used] + path="spyrmsd.hungarian", + description="Hungarian method", +) + def cost_mtx(A: np.ndarray, B: np.ndarray): """ diff --git a/spyrmsd/qcp.py b/spyrmsd/qcp.py index af0b18d..988cc2d 100644 --- a/spyrmsd/qcp.py +++ b/spyrmsd/qcp.py @@ -3,6 +3,14 @@ import numpy as np from scipy import optimize +from .due import due, Doi + +due.cite( + Doi("10.1107/S0108767305015266"), # lgtm[py/procedure-return-value-used] + path="spyrmsd.qcp", + description="QCP method", +) + def M_mtx(A: np.ndarray, B: np.ndarray) -> np.ndarray: """ diff --git a/tests/__init__.py b/tests/__init__.py index 325e75d..e69de29 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,3 +0,0 @@ -""" -Empty init file in case you choose a package besides PyTest such as Nose which may look for such a file -""" diff --git a/tests/test_import.py b/tests/test_import.py new file mode 100644 index 0000000..daa0b0f --- /dev/null +++ b/tests/test_import.py @@ -0,0 +1,36 @@ +""" +Test imported package and modules. + +This test is useful to generate a citation report: + +.. code + + python -m duecite test_import.py + +""" + +import sys + +import pytest + +from spyrmsd import graph, hungarian, io, molecule, qcp, rmsd, spyrmsd, utils + + +@pytest.mark.parametrize( + "name", + [ + # Package + spyrmsd.__name__, + # Modules + graph.__name__, + hungarian.__name__, + io.__name__, + molecule.__name__, + qcp.__name__, + rmsd.__name__, + spyrmsd.__name__, + utils.__name__, + ], +) +def test_imported(name): + assert name in sys.modules