- Use syntax compatible with Python
3.10+. - Use docstrings with Sphinx in mind.
- Follow the PEP8 style guide.
- Try and run tests locally before submitting a new PR.
You can open issues in the GitHub issue tracker.
For development, consider creating a new virtual environment (with any preferred method, e.g. venv). All development packages can be installed with
python -m pip install -e '.[develop,docs]'To run the tests, just use pytest. Some helpful wrappers are given in the
Makefile (see make help), e.g. to run the tests
make pytest
# or directly
python -m pytest tests papiswhich runs the full test suite and doctests for papis. To run the tests exactly
as they are set up on the Github Actions CI use
make ci-lint
make ci-testThe docs can be generated with
make docIt is generally advisable to have python-lsp-server installed, as it enables
your text editor to perform semantic operations on the codebase (eg Go to
Definition, Replace All, refactorings, etc)
To quickly get things up and running, you can also use Docker with the included
Dockerfile. To use the container run
# build the image
docker build -t papisdev .
# to run the CI tests
docker run -v $(pwd):/papis --rm -it papisdev
# enter the container interactively
docker run -v $(pwd):/papis --rm -it papisdev bash(or replace docker with podman if you prefer)
If you're using Nix, you can also use the included flake.nix and get a
development shell up with nix develop.
This also gives you access to the following convenience commands to interact with the containers (they require either Docker or Podman to run):
papis-build-container: build the container.papis-run-container-tests: run the CI tests in the container.papis-run-container-interactive: enter the container interactively and populate the library with some test documents.
To add tests to the various parts of Papis, use the functionality in
papis.testing. This is documented in the
Testing section of the
docs and more complex examples can be found in the existing tests folder.
When adding functionality or fixing a bug with an accompanying test, make sure everything still works correctly by running
make ci-test
make ci-lint
To add a new main option:
- Add a default value in
defaults.pyin thesettingsdictionary. - Document the option in
doc/source/default_settings.rst. Try to answer the following questions:
- What is it for?
- Where is it used?
- What type or format should it be?
- What values are allowed? (default values are added automatically)
The setting is now accessible with papis.config.get("myoption")
or through the command-line interface papis config myoption.
To add a new option in a custom section (or generally with a common prefix)
- Call
papis.config.register_default_settingswith a dictionary{"section": {"option1": "value", ...}}. - Document the option as above and remember to add a
:section: sectionargument to the Sphinx directive.
The setting can now be accessed with papis.config.get("section-option1")
or papis.config.get("option1", section="section").
You can share scripts with everyone by adding them to the folder examples/scripts
in the repository. These scripts will not be shipped with Papis, but they are there
for other users to use and modify.
An importer is used to get data from a file or service into papis. For example,
see the arXiv importers in arxiv.py. To add a new importer
- Create a class that inherits from
papis.importer.Importer. - Implement the
Importer.matchmethod, which is used to check if a given URI can be handled by the importer. - Implement the
Importer.fetchmethod, that gets the data. This method should updateImporter.ctxto contain the extracted information. - (Optional) Instead of the
fetchmethod, you can also implement thefetch_dataand / orfetch_filesmethods separately.
The importer is then registered with papis by adding it to pyproject.toml.
In the project.entry_points."papis.importer" section add
myimporter = "papis.myservice:Importer"
or see the existing examples.
The difference between a downloader and an importer in papis is largely
semantic. Downloaders are mostly meant to scrape websites or download files
from a remote location, while importers access a specific API or format. They
can be implemented in a very similar way:
- Create a class that inherits from
papis.downloaders.Downloader. - Implement the
Downloader.matchmethod, which generally checks if a given URI matches a website URL. - (Optional) Implement the
Downloader.get_datamethod, which returns a dictionary with scrapped metadata. - (Optional) Implement the
Downloader.get_bibtex_urlmethod to return an URL from which a BibTeX file can be downloaded. This is then parsed and merged automatically. - (Optional) Implement the
Downloader.get_document_urlmethod to return an URL from which a document (e.g. PDF file) can be downloaded.
The downloader can then be added to the project.entry-points."papis.downloader"
section, similarly to an importer.
You'll find the source code of the Papis documentation under the doc/src
directory. The documentation uses the Sphinx documentation stack to build the
manual and HTML pages and, to format the text, the Sphinx reStructuredText
markup.
To build the documentation you can directly run make doc in the main folder or
go into the doc folder and run e.g.
make html SPHINXOPTS='-W --keep-going -n'
# or
make man SPHINXOPTS='-W --keep-going -n'You can just run make to see all the supported output formats by Sphinx. Note
that some formats may require special handling and are not set up to produce
good outputs.
A new command is added in papis/commands/mycommand.py. To document the command
-
Add the relevant documentation to the top of the Python file. This should include at least some of the following:
- A description of the command and the intended use case.
- A few examples with calls to the command-line interface.
- A call to the
.. clickdirective to document the command-line based on Click (this requiressphinx-click). - If the command defines some new options, they should be added to
doc/source/default_settings.rstinstead.
-
Add a documentation file to
doc/source/commands/mycommand.rstto include the command in the documentation.
When in doubt, you can always check out some of the existing commands with
extensive documentation like papis add.
Concise API documentation for a command or module as well as their usage
examples should be generally placed in each module's source file. Visit the
papis/commands/add.py or papis/yaml.py for examples of such use. If the
new feature adds some useful API that can be used by others, make sure to also
add it to doc/source/developer_reference.rst.
Longer-form texts, such as guides, tutorials or workflows can go to an
appropriate file under doc/source.
To have a consistent naming for the project, we suggest some rules for when to capitalize the Papis name.
-
When referring to the command-line interface, use
papis, in lowercase and with code markup (double backticks in rST):- Incorrect:
The **papis** commands are ``add``, ``edit``, ``update``...
- Correct:
The **``papis``** commands are ``add``, ``edit``, ``update``...
- Incorrect:
-
When referring to the workflow or project, use uppercase P:
- Incorrect:
The YAML files contain the metadata that **papis** uses for search... The documentation for **papis** is built with Sphinx...
- Correct:
The YAML files contain the metadata that **Papis** uses for search... The documentation for **Papis** is built using Sphinx...
- Incorrect: