diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml new file mode 100644 index 0000000..ae03cd2 --- /dev/null +++ b/.github/workflows/tox.yml @@ -0,0 +1,25 @@ +name: tox + +on: + pull_request: + workflow_dispatch: # you can trigger this workflow manually + +jobs: + tox_on_ubuntu: + + runs-on: ubuntu-22.04 + strategy: + matrix: + python: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] + + steps: + - uses: actions/checkout@v3 + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python }} + - name: install tox + run: pip install tox + - name: run tox + # Run tox using the version of Python in `PATH` + run: tox -e py diff --git a/.gitignore b/.gitignore index 77e8b94..059c9f0 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,9 @@ __pycache__/ *.pdf *.svg +# experimental code: +experimental/ + # Mac OS .DS_Store @@ -26,7 +29,3 @@ htmlcov/ # due to vscode: .vscode/ - -# other -bug_reports/ -experimental/ diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..ea5ba91 --- /dev/null +++ b/docs/CODE_OF_CONDUCT.md @@ -0,0 +1,16 @@ +# Code of Conduct + +Everyone interacting in this project is expected to follow the [PSF Code of +Conduct]. This includes all infrastructure used in the development, such as +codebases, issue trackers, chat rooms, and mailing lists. + +In general, this means that everyone is expected to be **open**, +**considerate**, and **respectful** of others no matter what their position is +within the project. + + +## Reporting + +All incidents should be reported by emailing github@tambora.ch. + +[PSF Code of Conduct]: https://www.python.org/psf/conduct/ diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 0000000..8bafcd3 --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,50 @@ +# How to contribute + +Thank for considering a contribution! Any help is greatly appreciated. + + +## Did you find an issue? + +* Check whether your issue has already been reported by searching under + [existing issues](https://github.com/adrianschlatter/ppf.jabref/issues). + +* If don't find an issue addressing the problem, open a new issue. + +* Choose a meaningful title, describe clearly what you consider to be a + problem. + +* If possible, provide example code or other means to make it easy for a + maintainer to reproduce your problem. + + +## Contributing Code + +You want to help with a bug or contribute a new feature? The [development +docs](./dev/DEV_DOCS.md) might help you along. + +You already have a solution for an issue or a new feature? All the better! A +pull request ("PR") is what you want to do. + +* Open a new [pull-request](https://github.com/adrianschlatter/ppf.jabref/pulls) + with your patch. + +* Try to create PRs that address a specific issue/feature/topic. + +* Avoid PRs containing an assortment of unrelated fixes and features. Better + split it into separate PRs for each topic. + +* Clean up your code before creating a pull request: Remove code that you have + commented out for debugging, remove test code you have added. + +* Make sure the PR's description clearly describes the problem and your + solution. Include relevant issue numbers if appropriate. + +* You increase the chances of quick acceptance of your PR significantly if you + have taken measures to assure quality (such as writing and passing tests). + + +## Final remarks + +Currently, this project is maintained in the spare time of a single person +having a family and a job. If you do not get immediate feedback to your issue +or pull request, please have some patience. diff --git a/docs/README.md b/docs/README.md index 932e442..2e4652c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,5 +1,7 @@ # ppf.jabref +pypi downloads/month + ppf.jabref provides a [python](https://www.python.org) interface to [JabRef](https://www.jabref.org) SQL databases. It maps database relations to python classes using [SQLAlchemy](https://www.sqlalchemy.org). @@ -66,3 +68,37 @@ the database connection. The query then uses ppf.jabref's Entry class to obtain all Entries (=references) in the JabRef database. The for-loop shows how to access fields and uses the File class to find out where the documents linked to this entry are stored. + + +## Installation + +ppf.jabref is available via [pypi](https://pypi.org): + +``` +pip install ppf.jabref +``` + + +## Still reading? + +If you read this far, you're probably not here for the first time. If you use +and like this project, would you consider giving it a Github Star? (The button +is at the top of this website.) If not, maybe you're interested in one of +[my other projects](https://github.com/adrianschlatter/ppf.sample/blob/develop/docs/list_of_projects.md)? + + +## Contributing + +Did you find a bug and would like to report it? Or maybe you've fixed it +already or want to help fixing it? That's great! Please read +[CONTRIBUTING](./CONTRIBUTING.md) to learn how to proceed. + +To help ascertain that contributing to this project is a pleasant experience, +we have established a [code of conduct](./CODE_OF_CONDUCT.md). You can expect +everyone to adhere to it, just make sure you do as well. + + +## Change Log + +* 0.1.1: Fix sqlalchemy deprecation warning, docstrings +* 0.1.0: Initial release diff --git a/docs/README_pypi.md b/docs/README_pypi.md index 484f54b..b7a885a 100644 --- a/docs/README_pypi.md +++ b/docs/README_pypi.md @@ -42,3 +42,18 @@ the database connection. The query then uses ppf.jabref's Entry class to obtain all Entries (=references) in the JabRef database. The for-loop shows how to access fields and uses the File class to find out where the documents linked to this entry are stored. + + +## Installation + +ppf.jabref is available via [pypi](https://pypi.org): + +``` +pip install ppf.jabref +``` + + +## Change Log + +* 0.1.1: Fix sqlalchemy deprecation warning, docstrings +* 0.1.0: Initial release diff --git a/docs/dev/DEV_DOCS.md b/docs/dev/DEV_DOCS.md new file mode 100644 index 0000000..6df9ed8 --- /dev/null +++ b/docs/dev/DEV_DOCS.md @@ -0,0 +1,29 @@ +# Development Docs + +This is the top-level development document. It provides an overview and links +to more specific documents. + + +## Getting Started + +To start developing, you will need: + +``` +pip install .[test] +pip install .[dev] +``` + +(Note: Depending on your shell, you might need to escape '[' and ']'.) + + +## Packaging + +This package inherits its structure, build- and distribution "mechanics" +from [ppf.sample](https://github.com/adrianschlatter/ppf.sample). And +improvements gained with this package are also meant to flow back into said +template project. + + +## Release Process + +"[Release-Process](./release-process.md)" describes how we do a release. diff --git a/docs/dev/release_process.md b/docs/dev/release_process.md new file mode 100644 index 0000000..cf1410b --- /dev/null +++ b/docs/dev/release_process.md @@ -0,0 +1,82 @@ +# Release Process + +Make sure that you: + +* updated the changelog (/docs/README.md) +* checked the README for pypi (/docs/README_pypi.md) + + +## Pull-Request into master + +* Push changes to Github +* Create PR into master +* Github will run workflows (tox in our case) +* Merge PR when all is well (merge commit, not squash or fast forward) + +A commit in master is a release. Pull the new commit and tag it: + +```shell +git checkout master +git tag vX.Y.Z +``` + +Then push the tag back to Github: + +```shell +git push origin vX.Y.Z +``` + +Tagging is important because the version of the package we are going to build +is derived from this tag. + + +## Build + +From the root of the project folder, run + +``` +python3 -m build --wheel +``` + +This generates a wheel distribution in /dist. + +## Test-pypi + +Upload to test.pypi.org by (make sure the '*' selects only your package): + +``` +twine upload -r testpypi dist/* +``` + +Note: Your `~/.pypirc` has to specify a `[testpypi]` section providing your +username and password. + + +## pypi + +If everything worked as expected, run + +``` +twine upload dist/* +``` + +Note: Your `~/.pypirc` has to specify a `[pypi]` section providing your +username and password. + +## Test Install + +Activate an environment that does not have a (development-) installation of +this package. Run + +``` +pip install ppf.jabref +``` + +This should download and install the version you've just released. + + +## GitHub + +Finally, go to github, find the new tag, click the ellipsis, click +"create release". Enter the tag name as title and copy the commit message +into the description. diff --git a/pyproject.toml b/pyproject.toml index 6ddb34b..8fd8d67 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,3 @@ [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>=40.8.0", "wheel"] +requires = ["setuptools", "setuptools-scm"] build-backend = "setuptools.build_meta" diff --git a/setup.cfg b/setup.cfg index a0786eb..7026971 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,87 +1,71 @@ [metadata] name = ppf-jabref -# Versions should comply with PEP440. For a discussion on single-sourcing -# the version across setup.py and the project code, see -# https://packaging.python.org/en/latest/single_source_version.html version = 0.1.0 description = Python tools to work with JabRef libraries long_description = file: docs/README_pypi.md long_description_content_type = text/markdown - -# The projects main homepage. url = https://github.com/adrianschlatter/ppf.jabref/tree/master -# Author details author = Adrian Schlatter -# Do *not* provide author_email here. Instead, provide email for -# software / licensing / ... questions (centrally) on GitHub. -# If email changes (e.g. discard because of too much spam), -# adjust email in single place instead of in every package. -# author_email = private@private.pr -# Choose your license license = MIT -# See https://pypi.python.org/pypi?%3Aaction=list_classifiers classifiers = - # How mature is this project? Common values are - # Development Status :: 2 - Pre-Alpha - # 3 - Alpha - # 4 - Beta - # 5 - Production/Stable Development Status :: 2 - Pre-Alpha - # Indicate who your project is intended for Intended Audience :: Developers Intended Audience :: Science/Research - Topic :: Utilities - # Pick your license as you wish (should match "license" above) License :: OSI Approved :: MIT License - # Specify the Python versions you support here. In particular, ensure - # that you indicate whether you support Python 2, Python 3 or both. Programming Language :: Python :: 3 Operating System :: OS Independent - -# What does your project relate to? keywords = jabref, python, sqlalchemy [options] -# You can just specify the packages manually here if your project is -# simple. Or you can use find_packages(). package_dir = = src packages = find_namespace: -# List run-time dependencies here. These will be installed by pip when -# your project is installed. For an analysis of "install_requires" vs pips -# requirements files see: -# https://packaging.python.org/en/latest/requirements.html +# no python3.5 because we need f-strings: +python_requires = >=3.6 install_requires = sqlalchemy [options.packages.find] where = src [options.extras_require] -# List additional groups of dependencies here (e.g. development -# dependencies). You can install these using the following syntax, -# for example: -# $ pip install -e .[dev,test] -dev = check-manifest +# List additional groups of dependencies here. You can install these using +# pip install -e .[dev,test] test = - pytest - twine check-manifest + setuptools>=40.5.0 flake8 - coverage + pytest + pytest-cov + importlib_metadata;python_version<='3.8' +dev = + tox + twine -[check-manifest] -ignore = - tox.ini +[tool:pytest] +testpaths = tests - tests/** - docs/** + docs +addopts = + --cov=ppf.jabref + --cov-report= + --cov-fail-under=100 + --doctest-glob=*.md [flake8] per-file-ignores = # imported but unused, import *, undefined name: __init__.py: F401, F403, F821 +filename = + */src/*.py + */docs/*.py + */tests/*.py + setup.py -[tool:pytest] -testpaths = +[check-manifest] +ignore = + tox.ini tests + tests/** + docs/** + diff --git a/setup.py b/setup.py index ed8c032..c260289 100644 --- a/setup.py +++ b/setup.py @@ -1,11 +1,5 @@ # -*- coding: utf-8 -*- -""" -A setuptools based setup module. - -See: -https://packaging.python.org/en/latest/distributing.html -https://github.com/pypa/sampleproject -""" +# required for backwards compatibility import setuptools diff --git a/src/ppf/jabref/__init__.py b/src/ppf/jabref/__init__.py index 0268006..6641c03 100644 --- a/src/ppf/jabref/__init__.py +++ b/src/ppf/jabref/__init__.py @@ -1,12 +1,17 @@ """ -pyjabref +ppf.jabref ++++++ """ -# flake8: noqa +try: + from importlib_metadata import version +except ImportError: # pragma: no cover + from importlib.metadata import version # pragma: no cover # import every function, class, etc. that should be visible in the package from .jabref import * +__version__ = version(__name__) + del jabref del utils diff --git a/src/ppf/jabref/jabref.py b/src/ppf/jabref/jabref.py index d1cdbf8..76a6bf2 100644 --- a/src/ppf/jabref/jabref.py +++ b/src/ppf/jabref/jabref.py @@ -8,7 +8,7 @@ from sqlalchemy import Integer, VARCHAR, Text from sqlalchemy.orm import relationship from sqlalchemy.orm.collections import attribute_mapped_collection -from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import declarative_base from sqlalchemy.ext.associationproxy import association_proxy import re from .utils import export @@ -19,9 +19,11 @@ @export def citationkey2counter(citationkey): - # 'a': 0, 'b': 1, ..., 'z': 25 - # 'aa': 26, 'ab': 27 - # 'aaa': 26 + 26**2 + 0, 'aab': 26 + 26**2 + 1 + """ + 'a': 0, 'b': 1, ..., 'z': 25 + 'aa': 26, 'ab': 27 + 'aaa': 26 + 26**2 + 0, 'aab': 26 + 26**2 + 1 + """ # Let n = len(citationkey). # Then first count all keys used by keys of length