diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..abbb6d6 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +# editorconfig +# Ref: https://editorconfig.org +# ------------------------------------------------------------------------------ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true + +[*.{py,pyi}] +indent_size = 4 diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..46ff4ca --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,112 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for +everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity +and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, +color, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our community include: + +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience +- Focusing on what is best not just for us as individuals, but for the overall community + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery, and sexual attention or advances of any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take +appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, +issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for +moderation decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing +the community in public spaces. Examples of representing our community include using an official e-mail address, posting +via an official social media account, or acting as an appointed representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible +for enforcement at [@afuetterer](https://github.com/afuetterer). + +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem +in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the +community. + +**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation +and an explanation of why the behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of actions. + +**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including +unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding +interactions in community spaces as well as external channels like social media. Violating these terms may lead to a +temporary or permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified +period of time. No public or private interaction with the people involved, including unsolicited interaction with those +enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate +behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the community. + +## Attribution + +*This Code of Conduct is adapted from [cookiecutter-hypermodern-python (MIT License)][hypermodern-python-coc].* + +The cookiecutter-hypermodern-python version is originally adapted from the [Contributor Covenant][homepage], version +2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][mozilla coc]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][faq]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + + + +[faq]: https://www.contributor-covenant.org/faq +[homepage]: https://www.contributor-covenant.org +[hypermodern-python-coc]: https://github.com/cjolowicz/cookiecutter-hypermodern-python/blob/main/%7B%7Bcookiecutter.project_name%7D%7D/CODE_OF_CONDUCT.md +[mozilla coc]: https://github.com/mozilla/diversity +[translations]: https://www.contributor-covenant.org/translations +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..4c1ce68 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,122 @@ +# Contributing to python-re3data + +Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given. + +You can contribute in many ways. + +## Types of Contributions + +### Report Bugs + +Report bugs at . + +If you are reporting a bug, please include: + +- Your operating system name and version. +- Any details about your local setup that might be helpful in troubleshooting. +- Detailed steps to reproduce the bug. + +### Fix Bugs + +Look through the GitHub issues for bugs. Anything tagged with [bug and help wanted][bug-issues-help-wanted] is open to +whoever wants to implement it. + +### Implement Features + +Look through the GitHub issues for features. Anything tagged with [feature and help wanted][feature-issues-help-wanted] +is open to whoever wants to implement it. + +### Write Documentation + +`python-re3data` could always use more documentation, whether as part of the official `python-re3data` docs, in +docstrings, or even on the web in blog posts, articles, and such. + +### Submit Feedback + +The best way to send feedback is to file an issue at https://github.com/afuetterer/python-re3data/issues. + +If you are proposing a feature: + +- Explain in detail how it would work. +- Keep the scope as narrow as possible, to make it easier to implement. +- Remember that this is a volunteer-driven project, and that contributions are welcome. + +## Get Started! + +Ready to contribute? + +You need Python >= 3.10 and [hatch](https://github.com/pypa/hatch). You can install it globally with +[pipx](https://github.com/pypa/pipx): + +```console +$ pipx install hatch +``` + +or locally with (this will install it in the local virtual environment): + +```console +$ python -m pip install hatch +``` + +Here's how to set up `python-re3data` for local development. + +1. Fork the python-re3data repository on GitHub. + +2. Clone your fork locally: + + ```console + $ git clone git@github.com:username/python-re3data.git + ``` + +3. Install your local copy into a virtual environment. Assuming you have hatch installed, this is how you set up your + fork for local development: + + ```console + $ cd python-re3data + $ hatch shell + ``` + +4. Create a branch for local development: + + ```console + $ git checkout -b name-of-your-bugfix-or-feature + ``` + + Now you can make your changes locally. + +5. When you're done making changes, check that your changes pass pre-commit and the tests: + + ```console + $ hatch run check + $ hatch run cov + ``` + +6. Commit your changes and push your branch to GitHub:: + + ```console + $ git add . + $ git commit -m "Your detailed description of your changes." + $ git push origin name-of-your-bugfix-or-feature + ``` + +7. Submit a pull request through the GitHub website. + +## Pull Request Guidelines + +Before you submit a pull request, check that it meets these guidelines: + +1. The pull request should include tests. +2. If the pull request adds functionality, the docs should be updated. Put your new functionality into a function with a + docstring. +3. The pull request should work for Python >= 3.10. Check and make + sure that all the tests pass. + +--- + +*This contributor guide is adapted from +[cookiecutter-pypackage (BSD 3-Clause License)](https://github.com/audreyfeldroy/cookiecutter-pypackage/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/CONTRIBUTING.rst).* + + + +[bug-issues-help-wanted]: https://github.com/afuetterer/python-re3data/issues?q=is%3Aissue+is%3Aopen+label%3A%22type%3A+bug%22+label%3A%22help+wanted%22 +[feature-issues-help-wanted]: https://github.com/afuetterer/python-re3data/issues?q=is%3Aissue+is%3Aopen+label%3A%22type%3A+feature%22+label%3A%22help+wanted%22 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..9e49895 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,51 @@ +--- +name: Bug report +about: Create a bug report to help us improve +labels: ['type: bug'] +--- + + + +## Description + + + +## Expected Behavior + + + +## Actual Behavior + + + +## Possible Fix + + + +## Steps to reproduce + + + +1. +2. +3. + +## Additional Context + + + +## Your Environment + + + +- Python version used (`python --version`): +- python-re3data version used (`python -m pip show python-re3data | grep "^Version:"`): +- Operating system and version: + + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..d7d1e7f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,24 @@ +--- +name: Feature request +about: Suggest an idea for this project +labels: ['type: feature'] +--- + + + +## Detailed Description + + + +## Context + + + + + +## Possible Implementation + + + + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..5113c1a --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,64 @@ + + + + +## Description + + + +Related issue: #ISSUE_NUMBER + +## Motivation and context + + + +## How has this been tested? + + + +## Types of changes + + + +- Breaking change (fix or feature that would cause existing functionality to change) +- New feature (non-breaking change which adds functionality) +- Bug fix (non-breaking change which fixes an issue) +- Refactoring (no functional changes, no API changes) +- Performance (improves performance) +- Test (adding new tests or correcting existing tests) +- Code style (formatting, renaming) +- Documentation content changes +- Build related changes +- Continuous Integration changes (e.g. GitHub actions, Dependabot) +- Other (please describe): + +## Checklist + + + +- I have read the [contributor guide](https://github.com/afuetterer/python-re3data/blob/main/.github/CONTRIBUTING.md). +- My code follows the code style of this project. +- My change requires a change to the documentation. +- I have updated the documentation accordingly. +- I have added tests to cover my changes. + + diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 0000000..76c8d62 --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,25 @@ +# Security Policy + +## Supported Versions + +Only the latest version of `python-re3data` will receive security updates. Previous versions of the project will not +receive patches or security improvements. Users are encouraged to update to the latest version as soon as it is +available. + +## Reporting a Vulnerability + +To report a security vulnerability, please follow these steps: + +- To report a security issue, please use the GitHub Security Advisory + [Report a Vulnerability](https://github.com/afuetterer/python-re3data/security/advisories/new) tab. +- Provide a clear and detailed account of the vulnerability, including the potential impact and steps required to + reproduce it. + +Do not report security vulnerabilities through public GitHub issues. + +## Out of Scope + +- Issues without a direct security impact. +- Vulnerabilities in any versions other than the latest. + +Contributors who report or fix issues will be publicly acknowledged. Thank you for helping keep `python-re3data` secure! diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..fdc5f87 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,38 @@ +# dependabot +# Ref: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file +# ------------------------------------------------------------------------------ +version: 2 +updates: +- package-ecosystem: github-actions + directory: / + schedule: + interval: monthly + commit-message: + prefix: ci + labels: + - 'type: ci' + - 'deps: github-actions' + groups: + github-actions: + patterns: + - '*' +- package-ecosystem: pip + directory: / + schedule: + interval: monthly + versioning-strategy: increase-if-necessary + commit-message: + prefix: build + include: scope + labels: + - 'type: build' + - 'deps: python' + groups: + docs: + patterns: + - mike + - mkdocs* + test: + patterns: + - pytest* + - respx diff --git a/.github/labels.yml b/.github/labels.yml new file mode 100644 index 0000000..93968c6 --- /dev/null +++ b/.github/labels.yml @@ -0,0 +1,92 @@ +# GitHub labels are generated automatically with GitHub Labeler +# Ref: https://github.com/marketplace/actions/github-labeler + +# Some labels are adapted from +# "cookiecutter-hypermodern-python" (MIT License) +# Ref: https://github.com/cjolowicz/cookiecutter-hypermodern-python/blob/main/%7B%7Bcookiecutter.project_name%7D%7D/.github/labels.yml + +# Default GitHub labels +- name: duplicate + description: This issue or pull request already exists + color: cfd3d7 +- name: good first issue + description: Good for newcomers + color: 7057ff +- name: help wanted + description: Extra attention is needed + color: '008672' +- name: invalid + description: This doesn't seem right + color: e4e669 +- name: question + description: Further information is requested + color: d876e3 +- name: wontfix + description: This will not be worked on + color: ffffff + +# Status +- name: 'status: abandoned' + color: '000000' +- name: 'status: accepted' + color: '009800' +- name: 'status: blocked' + color: e11d21 +- name: 'status: pending' + color: c5def5 + +# Type +- name: 'type: breaking' + description: Breaking Changes + color: e11d21 +- name: 'type: bug' + description: Something isn't working + color: e11d21 +- name: 'type: build' + description: Changes that affect the build system or external dependencies + color: d4c5f9 +- name: 'type: ci' + description: Continuous Integration + color: '000000' +- name: 'type: chore' + description: Miscellaneous changes (e.g. .gitignore, static files) + color: cfd3d7 +- name: 'type: docs' + description: Improvements or additions to documentation + color: 0075ca +- name: 'type: feature' + description: New feature or request + color: '009800' +- name: 'type: performance' + description: Changes that improve performance + color: 8fc9e1 +- name: 'type: refactor' + description: Changes that neither fix a bug nor adds a feature + color: '326770' +- name: 'type: style' + description: Changes that do not affect the meaning of the code (e.g. white-space, formatting) + color: d59d75 +- name: 'type: test' + description: Adding missing tests or correcting existing tests + color: 1b3081 + +# Priority +- name: 'priority: low' + color: '009800' +- name: 'priority: medium' + color: fbca04 +- name: 'priority: high' + color: eb6420 +- name: 'priority: critical' + color: e11d21 + +# Dependencies +- name: 'deps: python' + description: Pull requests that update Python code + color: 2b67c6 +- name: 'deps: github-actions' + description: Pull requests that update GitHub Actions code + color: '000000' +- name: 'deps: pre-commit' + description: Pull requests that update pre-commit config code + color: fbca04 diff --git a/.github/requirements/ci.in b/.github/requirements/ci.in new file mode 100644 index 0000000..86b93a5 --- /dev/null +++ b/.github/requirements/ci.in @@ -0,0 +1,5 @@ +build +hatch +pip +pipdeptree +uv diff --git a/.github/requirements/ci.txt b/.github/requirements/ci.txt new file mode 100644 index 0000000..8f8f398 --- /dev/null +++ b/.github/requirements/ci.txt @@ -0,0 +1,372 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile --generate-hashes --python-version=3.10 --output-file=.github/requirements/ci.txt .github/requirements/ci.in +anyio==4.3.0 \ + --hash=sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8 \ + --hash=sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6 + # via httpx +backports-tarfile==1.1.1 \ + --hash=sha256:73e0179647803d3726d82e76089d01d8549ceca9bace469953fcb4d97cf2d417 \ + --hash=sha256:9c2ef9696cb73374f7164e17fc761389393ca76777036f5aad42e8b93fcd8009 + # via jaraco-context +build==1.2.1 \ + --hash=sha256:526263f4870c26f26c433545579475377b2b7588b6f1eac76a001e873ae3e19d \ + --hash=sha256:75e10f767a433d9a86e50d83f418e83efc18ede923ee5ff7df93b6cb0306c5d4 + # via -r .github/requirements/ci.in +certifi==2024.2.2 \ + --hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \ + --hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1 + # via + # httpcore + # httpx +cffi==1.16.0 \ + --hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \ + --hash=sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a \ + --hash=sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417 \ + --hash=sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab \ + --hash=sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520 \ + --hash=sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36 \ + --hash=sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743 \ + --hash=sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8 \ + --hash=sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed \ + --hash=sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684 \ + --hash=sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56 \ + --hash=sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324 \ + --hash=sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d \ + --hash=sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235 \ + --hash=sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e \ + --hash=sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088 \ + --hash=sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000 \ + --hash=sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7 \ + --hash=sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e \ + --hash=sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673 \ + --hash=sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c \ + --hash=sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe \ + --hash=sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2 \ + --hash=sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098 \ + --hash=sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8 \ + --hash=sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a \ + --hash=sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0 \ + --hash=sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b \ + --hash=sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896 \ + --hash=sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e \ + --hash=sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9 \ + --hash=sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2 \ + --hash=sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b \ + --hash=sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6 \ + --hash=sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404 \ + --hash=sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f \ + --hash=sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0 \ + --hash=sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4 \ + --hash=sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc \ + --hash=sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936 \ + --hash=sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba \ + --hash=sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872 \ + --hash=sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb \ + --hash=sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614 \ + --hash=sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1 \ + --hash=sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d \ + --hash=sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969 \ + --hash=sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b \ + --hash=sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4 \ + --hash=sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627 \ + --hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \ + --hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357 + # via cryptography +click==8.1.7 \ + --hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \ + --hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de + # via + # hatch + # userpath +cryptography==42.0.7 \ + --hash=sha256:02c0eee2d7133bdbbc5e24441258d5d2244beb31da5ed19fbb80315f4bbbff55 \ + --hash=sha256:0d563795db98b4cd57742a78a288cdbdc9daedac29f2239793071fe114f13785 \ + --hash=sha256:16268d46086bb8ad5bf0a2b5544d8a9ed87a0e33f5e77dd3c3301e63d941a83b \ + --hash=sha256:1a58839984d9cb34c855197043eaae2c187d930ca6d644612843b4fe8513c886 \ + --hash=sha256:2954fccea107026512b15afb4aa664a5640cd0af630e2ee3962f2602693f0c82 \ + --hash=sha256:2e47577f9b18723fa294b0ea9a17d5e53a227867a0a4904a1a076d1646d45ca1 \ + --hash=sha256:31adb7d06fe4383226c3e963471f6837742889b3c4caa55aac20ad951bc8ffda \ + --hash=sha256:3577d029bc3f4827dd5bf8bf7710cac13527b470bbf1820a3f394adb38ed7d5f \ + --hash=sha256:36017400817987670037fbb0324d71489b6ead6231c9604f8fc1f7d008087c68 \ + --hash=sha256:362e7197754c231797ec45ee081f3088a27a47c6c01eff2ac83f60f85a50fe60 \ + --hash=sha256:3de9a45d3b2b7d8088c3fbf1ed4395dfeff79d07842217b38df14ef09ce1d8d7 \ + --hash=sha256:4f698edacf9c9e0371112792558d2f705b5645076cc0aaae02f816a0171770fd \ + --hash=sha256:5482e789294854c28237bba77c4c83be698be740e31a3ae5e879ee5444166582 \ + --hash=sha256:5e44507bf8d14b36b8389b226665d597bc0f18ea035d75b4e53c7b1ea84583cc \ + --hash=sha256:779245e13b9a6638df14641d029add5dc17edbef6ec915688f3acb9e720a5858 \ + --hash=sha256:789caea816c6704f63f6241a519bfa347f72fbd67ba28d04636b7c6b7da94b0b \ + --hash=sha256:7f8b25fa616d8b846aef64b15c606bb0828dbc35faf90566eb139aa9cff67af2 \ + --hash=sha256:8cb8ce7c3347fcf9446f201dc30e2d5a3c898d009126010cbd1f443f28b52678 \ + --hash=sha256:93a3209f6bb2b33e725ed08ee0991b92976dfdcf4e8b38646540674fc7508e13 \ + --hash=sha256:a3a5ac8b56fe37f3125e5b72b61dcde43283e5370827f5233893d461b7360cd4 \ + --hash=sha256:a47787a5e3649008a1102d3df55424e86606c9bae6fb77ac59afe06d234605f8 \ + --hash=sha256:a79165431551042cc9d1d90e6145d5d0d3ab0f2d66326c201d9b0e7f5bf43604 \ + --hash=sha256:a987f840718078212fdf4504d0fd4c6effe34a7e4740378e59d47696e8dfb477 \ + --hash=sha256:a9bc127cdc4ecf87a5ea22a2556cab6c7eda2923f84e4f3cc588e8470ce4e42e \ + --hash=sha256:bd13b5e9b543532453de08bcdc3cc7cebec6f9883e886fd20a92f26940fd3e7a \ + --hash=sha256:c65f96dad14f8528a447414125e1fc8feb2ad5a272b8f68477abbcc1ea7d94b9 \ + --hash=sha256:d8e3098721b84392ee45af2dd554c947c32cc52f862b6a3ae982dbb90f577f14 \ + --hash=sha256:e6b79d0adb01aae87e8a44c2b64bc3f3fe59515280e00fb6d57a7267a2583cda \ + --hash=sha256:e6b8f1881dac458c34778d0a424ae5769de30544fc678eac51c1c8bb2183e9da \ + --hash=sha256:e9b2a6309f14c0497f348d08a065d52f3020656f675819fc405fb63bbcd26562 \ + --hash=sha256:ecbfbc00bf55888edda9868a4cf927205de8499e7fabe6c050322298382953f2 \ + --hash=sha256:efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9 + # via secretstorage +distlib==0.3.8 \ + --hash=sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784 \ + --hash=sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64 + # via virtualenv +exceptiongroup==1.2.1 \ + --hash=sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad \ + --hash=sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16 + # via anyio +filelock==3.14.0 \ + --hash=sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f \ + --hash=sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a + # via virtualenv +h11==0.14.0 \ + --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ + --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 + # via httpcore +hatch==1.11.0 \ + --hash=sha256:0511e48b06576995a51a39af14c062431cbbbf22df8a4faccce41418ebccab30 \ + --hash=sha256:3949517cee5fdd520829b31a81c6bcd63e18750c0db0171d541bd17cdfea15c0 + # via -r .github/requirements/ci.in +hatchling==1.24.2 \ + --hash=sha256:41ddc27cdb25db9ef7b68bef075f829c84cb349aa1bff8240797d012510547b0 \ + --hash=sha256:5576ad05227cf96bb4bfd3a5dce31aa53eff05e95da57b40769bd5a3096b31b1 + # via hatch +httpcore==1.0.5 \ + --hash=sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61 \ + --hash=sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5 + # via httpx +httpx==0.27.0 \ + --hash=sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5 \ + --hash=sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5 + # via hatch +hyperlink==21.0.0 \ + --hash=sha256:427af957daa58bc909471c6c40f74c5450fa123dd093fc53efd2e91d2705a56b \ + --hash=sha256:e6b14c37ecb73e89c77d78cdb4c2cc8f3fb59a885c5b3f819ff4ed80f25af1b4 + # via hatch +idna==3.7 \ + --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \ + --hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0 + # via + # anyio + # httpx + # hyperlink +importlib-metadata==7.1.0 \ + --hash=sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570 \ + --hash=sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2 + # via + # build + # keyring +jaraco-classes==3.4.0 \ + --hash=sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd \ + --hash=sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790 + # via keyring +jaraco-context==5.3.0 \ + --hash=sha256:3e16388f7da43d384a1a7cd3452e72e14732ac9fe459678773a3608a812bf266 \ + --hash=sha256:c2f67165ce1f9be20f32f650f25d8edfc1646a8aeee48ae06fb35f90763576d2 + # via keyring +jaraco-functools==4.0.1 \ + --hash=sha256:3b24ccb921d6b593bdceb56ce14799204f473976e2a9d4b15b04d0f2c2326664 \ + --hash=sha256:d33fa765374c0611b52f8b3a795f8900869aa88c84769d4d1746cd68fb28c3e8 + # via keyring +jeepney==0.8.0 \ + --hash=sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806 \ + --hash=sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755 + # via + # keyring + # secretstorage +keyring==25.2.1 \ + --hash=sha256:2458681cdefc0dbc0b7eb6cf75d0b98e59f9ad9b2d4edd319d18f68bdca95e50 \ + --hash=sha256:daaffd42dbda25ddafb1ad5fec4024e5bbcfe424597ca1ca452b299861e49f1b + # via hatch +markdown-it-py==3.0.0 \ + --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \ + --hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb + # via rich +mdurl==0.1.2 \ + --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ + --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba + # via markdown-it-py +more-itertools==10.2.0 \ + --hash=sha256:686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684 \ + --hash=sha256:8fccb480c43d3e99a00087634c06dd02b0d50fbf088b380de5a41a015ec239e1 + # via + # jaraco-classes + # jaraco-functools +packaging==24.0 \ + --hash=sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5 \ + --hash=sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9 + # via + # build + # hatch + # hatchling + # pipdeptree +pathspec==0.12.1 \ + --hash=sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08 \ + --hash=sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712 + # via hatchling +pexpect==4.9.0 \ + --hash=sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523 \ + --hash=sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f + # via hatch +pip==24.0 \ + --hash=sha256:ba0d021a166865d2265246961bec0152ff124de910c5cc39f1156ce3fa7c69dc \ + --hash=sha256:ea9bd1a847e8c5774a5777bb398c19e80bcd4e2aa16a4b301b718fe6f593aba2 + # via + # -r .github/requirements/ci.in + # pipdeptree +pipdeptree==2.20.0 \ + --hash=sha256:8fa583060e6ee5482d5f7da00163a847c892a457ea51e720fca1b8df8fccff31 \ + --hash=sha256:bea21daf9ccb991650a237bfa4730932c7332c3c37cce7c4b4fade43ee5a2be5 + # via -r .github/requirements/ci.in +platformdirs==4.2.2 \ + --hash=sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee \ + --hash=sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3 + # via + # hatch + # virtualenv +pluggy==1.5.0 \ + --hash=sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1 \ + --hash=sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669 + # via hatchling +ptyprocess==0.7.0 \ + --hash=sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35 \ + --hash=sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220 + # via pexpect +pycparser==2.22 \ + --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \ + --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc + # via cffi +pygments==2.18.0 \ + --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ + --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a + # via rich +pyproject-hooks==1.1.0 \ + --hash=sha256:4b37730834edbd6bd37f26ece6b44802fb1c1ee2ece0e54ddff8bfc06db86965 \ + --hash=sha256:7ceeefe9aec63a1064c18d939bdc3adf2d8aa1988a510afec15151578b232aa2 + # via build +rich==13.7.1 \ + --hash=sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222 \ + --hash=sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432 + # via hatch +secretstorage==3.3.3 \ + --hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \ + --hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99 + # via keyring +shellingham==1.5.4 \ + --hash=sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686 \ + --hash=sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de + # via hatch +sniffio==1.3.1 \ + --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ + --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc + # via + # anyio + # httpx +tomli==2.0.1 \ + --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ + --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f + # via + # build + # hatchling +tomli-w==1.0.0 \ + --hash=sha256:9f2a07e8be30a0729e533ec968016807069991ae2fd921a78d42f429ae5f4463 \ + --hash=sha256:f463434305e0336248cac9c2dc8076b707d8a12d019dd349f5c1e382dd1ae1b9 + # via hatch +tomlkit==0.12.5 \ + --hash=sha256:af914f5a9c59ed9d0762c7b64d3b5d5df007448eb9cd2edc8a46b1eafead172f \ + --hash=sha256:eef34fba39834d4d6b73c9ba7f3e4d1c417a4e56f89a7e96e090dd0d24b8fb3c + # via hatch +trove-classifiers==2024.5.17 \ + --hash=sha256:2ebdddebd43e749ac6b6e9b9aa158ab489603dff147cba8714787729cdb9ea37 \ + --hash=sha256:d47a6f1c48803091c3fc81f535fecfeef65b558f2b9e4e83df7a79d17bce8bbf + # via hatchling +typing-extensions==4.11.0 \ + --hash=sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0 \ + --hash=sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a + # via anyio +userpath==1.9.2 \ + --hash=sha256:2cbf01a23d655a1ff8fc166dfb78da1b641d1ceabf0fe5f970767d380b14e89d \ + --hash=sha256:6c52288dab069257cc831846d15d48133522455d4677ee69a9781f11dbefd815 + # via hatch +uv==0.1.44 \ + --hash=sha256:012fcfc3789f303ee3ff9f2a6e09bc589710fed7c2dcbad4379832072bad7a95 \ + --hash=sha256:05774eb086b18aad488c3140daa62a235e3f270f62bd3cc4aaaa54eed927cc5b \ + --hash=sha256:26d07edb37e7bfddc3b4e1faa13420e6048ddd974b34fbc1c19fcf9bacef9e5b \ + --hash=sha256:2e5a60af214f42b621aa37ad320253c64f77dbfacafa710dc42d34965c2cd27f \ + --hash=sha256:2f95acffcdac507de9c8f8ed037e529df3ccea274b4453df05df3f331543f5fc \ + --hash=sha256:3eeac3d8be69831430743f3d00f84ddccfbd56b6835bb52d17f97914c9adfdff \ + --hash=sha256:567486ce0ad2f9778782ba6ee19d2b65516c4f4bf2b7b4fc66fc2712cd46c6d0 \ + --hash=sha256:768369a0bbdea8c3a670388ec1b4a11fe5871ef40d84a43844e9b8d97a1c2ca5 \ + --hash=sha256:7983b00d95290dcdea8488fa8ecdfdef5c8e7d3c92c90b8dcf405cc26b707add \ + --hash=sha256:8f90e80e11da409ce88424381f5c91e7f908d6a7eec53ed4ae60c5d76698d126 \ + --hash=sha256:9ef3448111b47ab95874fbf2c5ca8efd52f54de14086079e52b588d037d243f1 \ + --hash=sha256:b04eb0c8dedadfe434f9756bdc1c8a09a75df83884ba4cc7d97985ee819e4f32 \ + --hash=sha256:b076828cef1f1ae1c3b54fa97b9e16b32816acc521ca6ff4a54fd8b16df67eef \ + --hash=sha256:d60e5b77b958c559324882da13ffa642dcd511e6a7eb9b07e7308a6d71e248de \ + --hash=sha256:d82c7338f8bcb0551672e759e4115c035246321059692416ee03ebe08629b913 \ + --hash=sha256:e247dca0d8d42d71032ac99ef3d72a4fcbad4ae3114ef5979878a81a40fed274 \ + --hash=sha256:e8cb1047b8f81ef09e15ec8d1b8dfc371594232e2e4f3ef3acf8991fcda20a57 + # via + # -r .github/requirements/ci.in + # hatch +virtualenv==20.26.2 \ + --hash=sha256:82bf0f4eebbb78d36ddaee0283d43fe5736b53880b8a8cdcd37390a07ac3741c \ + --hash=sha256:a624db5e94f01ad993d476b9ee5346fdf7b9de43ccaee0e0197012dc838a0e9b + # via hatch +zipp==3.18.2 \ + --hash=sha256:6278d9ddbcfb1f1089a88fde84481528b07b0e10474e09dcfe53dad4069fa059 \ + --hash=sha256:dce197b859eb796242b0622af1b8beb0a722d52aa2f57133ead08edd5bf5374e + # via importlib-metadata +zstandard==0.22.0 \ + --hash=sha256:11f0d1aab9516a497137b41e3d3ed4bbf7b2ee2abc79e5c8b010ad286d7464bd \ + --hash=sha256:1958100b8a1cc3f27fa21071a55cb2ed32e9e5df4c3c6e661c193437f171cba2 \ + --hash=sha256:1a90ba9a4c9c884bb876a14be2b1d216609385efb180393df40e5172e7ecf356 \ + --hash=sha256:1d43501f5f31e22baf822720d82b5547f8a08f5386a883b32584a185675c8fbf \ + --hash=sha256:23d2b3c2b8e7e5a6cb7922f7c27d73a9a615f0a5ab5d0e03dd533c477de23004 \ + --hash=sha256:2612e9bb4977381184bb2463150336d0f7e014d6bb5d4a370f9a372d21916f69 \ + --hash=sha256:275df437ab03f8c033b8a2c181e51716c32d831082d93ce48002a5227ec93019 \ + --hash=sha256:2ac9957bc6d2403c4772c890916bf181b2653640da98f32e04b96e4d6fb3252a \ + --hash=sha256:2b11ea433db22e720758cba584c9d661077121fcf60ab43351950ded20283440 \ + --hash=sha256:2fdd53b806786bd6112d97c1f1e7841e5e4daa06810ab4b284026a1a0e484c0b \ + --hash=sha256:33591d59f4956c9812f8063eff2e2c0065bc02050837f152574069f5f9f17775 \ + --hash=sha256:36a47636c3de227cd765e25a21dc5dace00539b82ddd99ee36abae38178eff9e \ + --hash=sha256:39b2853efc9403927f9065cc48c9980649462acbdf81cd4f0cb773af2fd734bc \ + --hash=sha256:3db41c5e49ef73641d5111554e1d1d3af106410a6c1fb52cf68912ba7a343a0d \ + --hash=sha256:445b47bc32de69d990ad0f34da0e20f535914623d1e506e74d6bc5c9dc40bb09 \ + --hash=sha256:466e6ad8caefb589ed281c076deb6f0cd330e8bc13c5035854ffb9c2014b118c \ + --hash=sha256:48f260e4c7294ef275744210a4010f116048e0c95857befb7462e033f09442fe \ + --hash=sha256:4ac59d5d6910b220141c1737b79d4a5aa9e57466e7469a012ed42ce2d3995e88 \ + --hash=sha256:53866a9d8ab363271c9e80c7c2e9441814961d47f88c9bc3b248142c32141d94 \ + --hash=sha256:589402548251056878d2e7c8859286eb91bd841af117dbe4ab000e6450987e08 \ + --hash=sha256:68953dc84b244b053c0d5f137a21ae8287ecf51b20872eccf8eaac0302d3e3b0 \ + --hash=sha256:6c25b8eb733d4e741246151d895dd0308137532737f337411160ff69ca24f93a \ + --hash=sha256:7034d381789f45576ec3f1fa0e15d741828146439228dc3f7c59856c5bcd3292 \ + --hash=sha256:73a1d6bd01961e9fd447162e137ed949c01bdb830dfca487c4a14e9742dccc93 \ + --hash=sha256:8226a33c542bcb54cd6bd0a366067b610b41713b64c9abec1bc4533d69f51e70 \ + --hash=sha256:888196c9c8893a1e8ff5e89b8f894e7f4f0e64a5af4d8f3c410f0319128bb2f8 \ + --hash=sha256:88c5b4b47a8a138338a07fc94e2ba3b1535f69247670abfe422de4e0b344aae2 \ + --hash=sha256:8a1b2effa96a5f019e72874969394edd393e2fbd6414a8208fea363a22803b45 \ + --hash=sha256:93e1856c8313bc688d5df069e106a4bc962eef3d13372020cc6e3ebf5e045202 \ + --hash=sha256:9501f36fac6b875c124243a379267d879262480bf85b1dbda61f5ad4d01b75a3 \ + --hash=sha256:959665072bd60f45c5b6b5d711f15bdefc9849dd5da9fb6c873e35f5d34d8cfb \ + --hash=sha256:a1d67d0d53d2a138f9e29d8acdabe11310c185e36f0a848efa104d4e40b808e4 \ + --hash=sha256:a493d470183ee620a3df1e6e55b3e4de8143c0ba1b16f3ded83208ea8ddfd91d \ + --hash=sha256:a7ccf5825fd71d4542c8ab28d4d482aace885f5ebe4b40faaa290eed8e095a4c \ + --hash=sha256:a88b7df61a292603e7cd662d92565d915796b094ffb3d206579aaebac6b85d5f \ + --hash=sha256:a97079b955b00b732c6f280d5023e0eefe359045e8b83b08cf0333af9ec78f26 \ + --hash=sha256:d22fdef58976457c65e2796e6730a3ea4a254f3ba83777ecfc8592ff8d77d303 \ + --hash=sha256:d75f693bb4e92c335e0645e8845e553cd09dc91616412d1d4650da835b5449df \ + --hash=sha256:d8593f8464fb64d58e8cb0b905b272d40184eac9a18d83cf8c10749c3eafcd7e \ + --hash=sha256:d8fff0f0c1d8bc5d866762ae95bd99d53282337af1be9dc0d88506b340e74b73 \ + --hash=sha256:de20a212ef3d00d609d0b22eb7cc798d5a69035e81839f549b538eff4105d01c \ + --hash=sha256:e9e9d4e2e336c529d4c435baad846a181e39a982f823f7e4495ec0b0ec8538d2 \ + --hash=sha256:f058a77ef0ece4e210bb0450e68408d4223f728b109764676e1a13537d056bb0 \ + --hash=sha256:f1a4b358947a65b94e2501ce3e078bbc929b039ede4679ddb0460829b12f7375 \ + --hash=sha256:f9b2cde1cd1b2a10246dbc143ba49d942d14fb3d2b4bccf4618d475c65464912 \ + --hash=sha256:fe3390c538f12437b859d815040763abc728955a52ca6ff9c5d4ac707c4ad98e + # via hatch diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..2421b08 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,28 @@ +# Ref: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/customizing-code-scanning +name: CodeQL + +permissions: + contents: read + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +jobs: + analyze: + runs-on: ubuntu-24.04 + permissions: + actions: read + contents: read + security-events: write + steps: + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + # Ref: https://github.com/github/codeql-action + - name: Initialize CodeQL + uses: github/codeql-action/init@b7cec7526559c32f1616476ff32d17ba4c59b2d6 # v3.25.5 + with: + languages: python + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@b7cec7526559c32f1616476ff32d17ba4c59b2d6 # v3.25.5 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..fc3e8e9 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,45 @@ +name: Docs + +on: + release: + types: [created] + workflow_call: + # run manually from actions tab + workflow_dispatch: + +env: + PYTHONUNBUFFERED: 1 + +permissions: + contents: read + +jobs: + docs: + # Disables this workflow from running in a repository that is not part of the indicated organization/user + if: github.repository_owner == 'afuetterer' + runs-on: ubuntu-24.04 + permissions: + contents: write + steps: + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + with: + fetch-depth: 0 # fetch all commits and branches + - name: Set up Python 3.12 + uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 + with: + python-version: '3.12' + - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 + with: + key: docs-${{ hashFiles('pyproject.toml') }} + path: ~/.cache/pip + - name: Install pre-requisites (e.g. hatch) + run: python -m pip install --require-hashes --requirement=.github/requirements/ci.txt + - run: hatch run docs:build + if: github.event_name == 'pull_request' + - run: | + hatch version + hatch run docs:deploy + if: contains(fromJSON('["release", "workflow_dispatch"]'), github.event_name) + env: + GIT_COMMITTER_NAME: github-actions[bot] + GIT_COMMITTER_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml new file mode 100644 index 0000000..a2a3711 --- /dev/null +++ b/.github/workflows/label.yml @@ -0,0 +1,23 @@ +name: Label + +on: + push: + branches: + - main + paths: + - .github/labels.yml + - .github/workflows/label.yml + workflow_dispatch: + +permissions: + contents: read + +jobs: + label: + permissions: + issues: write + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - name: Run GitHub Labeler + uses: crazy-max/ghaction-github-labeler@de749cf181958193cb7debf1a9c5bb28922f3e1b # v5.0.0 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..f57c482 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,43 @@ +name: CI + +on: + push: + branches: [main] + +concurrency: + group: ci-${{ github.head_ref }} + cancel-in-progress: true + +env: + PYTHONUNBUFFERED: 1 + FORCE_COLOR: 1 + +permissions: + contents: read + +jobs: + test: + uses: ./.github/workflows/test.yml + secrets: inherit + release: + # disables this workflow from running in a repository that is not part of the indicated organization/user + if: github.repository_owner == 'afuetterer' + runs-on: ubuntu-24.04 + needs: + - test + steps: + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + with: + fetch-depth: 0 # get all commits and tags + token: ${{ secrets.SEMANTIC_RELEASE_TOKEN }} + # - name: Create semantic release + # id: release + # uses: python-semantic-release/python-semantic-release@9555482f978fee890bd79b2ebac3095a20217375 # v9.7.3 + # with: + # # allows for python-semantic-release to push to protected main branch + # github_token: ${{ secrets.SEMANTIC_RELEASE_TOKEN }} + # - name: Publish package to GitHub Release + # uses: python-semantic-release/upload-to-gh-release@0f96c02a48278aff14251e9f1a0d73122a8c638b + # if: ${{ steps.release.outputs.released }} == 'true' + # with: + # github_token: ${{ secrets.SEMANTIC_RELEASE_TOKEN }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000..c261f9f --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,38 @@ +name: Checks + +on: + pull_request: + types: + - opened + - synchronize + - reopened + - ready_for_review # this is needed to trigger checks, when an auto-generated "draft" PR is set for "ready for review". + +concurrency: + group: pr-${{ github.head_ref }} + cancel-in-progress: true + +env: + PYTHONUNBUFFERED: 1 + FORCE_COLOR: 1 + +permissions: + contents: read + +jobs: + test: + uses: ./.github/workflows/test.yml + docs: + permissions: + contents: write + uses: ./.github/workflows/docs.yml + required-checks-pass: + if: always() + needs: + - test + - docs + runs-on: ubuntu-24.04 + steps: + - uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2 + with: + jobs: ${{ toJSON(needs) }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..d286b03 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,29 @@ +name: Publish package to PyPI + +on: + release: + types: [created] + workflow_dispatch: # run manually from actions tab + +permissions: + contents: read + +jobs: + publish: + # disables this workflow from running in a repository that is not part of the indicated organization/user + if: github.repository_owner == 'afuetterer' + runs-on: ubuntu-24.04 + environment: publish + permissions: + id-token: write + steps: + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 + with: + python-version: '3.12' + cache: pip + - name: Install pre-requisites (e.g. hatch) + run: python -m pip install --require-hashes --requirement=.github/requirements/ci.txt + - run: python -m build --installer=uv + - name: Publish package to PyPI + uses: pypa/gh-action-pypi-publish@81e9d935c883d0b210363ab89cf05f3894778450 # v1.8.14 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml new file mode 100644 index 0000000..97e19f5 --- /dev/null +++ b/.github/workflows/scorecards.yml @@ -0,0 +1,44 @@ +# This CI job is adapted from: +# Scorecards' GitHub action (2013-09-12), Apache License 2.0 +# Ref: https://github.com/ossf/scorecard-action/blob/8d9d91b01b9389de406141fb47b98726a399e1ea/README.md?plain=1#L198 + +name: Scorecard analysis +on: + # Only the default branch is supported. + branch_protection_rule: + schedule: + # run once a month at midnight of the first day of the month + - cron: 0 0 1 * * + push: + branches: [main] + +# Declare default permissions as read only. +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-24.04 + permissions: + # Needed if using Code scanning alerts + security-events: write + # Needed for GitHub OIDC token if publish_results is true + id-token: write + steps: + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + with: + persist-credentials: false + # Ref: https://github.com/ossf/scorecard-action + - name: Run scorecard analysis + uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3 + with: + results_file: results.sarif + results_format: sarif + # Ref: https://github.com/ossf/scorecard-action#publishing-results. + publish_results: true + + # required for Code scanning alerts + - name: Upload SARIF results to code scanning + uses: github/codeql-action/upload-sarif@b7cec7526559c32f1616476ff32d17ba4c59b2d6 # v3.25.5 + with: + sarif_file: results.sarif diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..ab3c25c --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,34 @@ +# Ref: https://github.com/actions/stale +name: Handle stale issues and PRs + +on: + schedule: + # run once a week at midnight of sunday + - cron: 0 0 * * 0 + workflow_dispatch: # run manually from actions tab + +permissions: + contents: read + +jobs: + stale: + runs-on: ubuntu-24.04 + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9.0.0 + with: + days-before-stale: 60 + # handle issues: set to abandoned, close after 7 days with message + days-before-issue-close: 7 + stale-issue-label: 'status: abandoned' + stale-issue-message: | + This issue is stale because it has been open 60 days without activity. + Remove 'abandoned' label or comment or this will be closed in 7 days. + close-issue-message: This issue was closed because it has been stalled for 7 days with no activity. + + # handle pull requests: set to abandoned, but do not close per bot + days-before-pr-close: -1 # never close PRs + stale-pr-label: 'status: abandoned' + stale-pr-message: This PR is stale because it has been open 60 days without activity. diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..31da982 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,100 @@ +name: Test + +on: + workflow_call: + +env: + PYTHONUNBUFFERED: 1 + FORCE_COLOR: 1 + +permissions: + contents: read + +jobs: + test: + name: Python ${{ matrix.python-version }} + runs-on: ubuntu-24.04 + strategy: + matrix: + python-version: ['3.10', '3.11', '3.12'] + steps: + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 + with: + python-version: ${{ matrix.python-version }} + cache: pip + - name: Install pre-requisites (e.g. hatch) + run: python -m pip install --require-hashes --requirement=.github/requirements/ci.txt + - name: Run test suite + run: hatch run cov + - name: Generate coverage report + run: | + export TOTAL_COV=$(hatch run cov-total) + echo "TOTAL_COV=$TOTAL_COV" >> $GITHUB_ENV + hatch run cov-report-markdown + echo "### Total coverage: ${TOTAL_COV}%" >> $GITHUB_STEP_SUMMARY + cat coverage.md >> $GITHUB_STEP_SUMMARY + if: matrix.python-version == '3.12' + - name: Generate coverage badge + uses: schneegans/dynamic-badges-action@e9a478b16159b4d31420099ba146cdc50f134483 # v1.7.0 + with: + # GIST_TOKEN is a GitHub personal access token with scope "gist". + auth: ${{ secrets.GIST_TOKEN }} + gistID: fcb87d45f4d7defdfeffa65eb1d65f63 + filename: coverage-badge.json + label: Coverage + namedLogo: python + message: ${{ env.TOTAL_COV }}% + minColorRange: 50 + maxColorRange: 90 + valColorRange: ${{ env.TOTAL_COV }} + # only update coverage badge + # when push to main branch of the project -> not in forks + if: >- + env.TOTAL_COV + && github.repository == 'afuetterer/python-re3data' + && github.ref == 'refs/heads/main' + + dev-setup: + # Ref: structlog (MIT License) + name: Install [dev] on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + steps: + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 + with: + python-version: '3.12' + cache: pip + - run: python -Im pip install --editable .[dev] + - run: python -Ic 'import re3data.__about__; print(re3data.__about__.__version__)' + - name: Set up pipdeptree + if: matrix.os == 'ubuntu-latest' + run: python -m pip install --require-hashes --requirement=.github/requirements/ci.txt + - name: Write info to step summary + if: matrix.os == 'ubuntu-latest' + run: | + { + echo -e "### ✓ All dependencies installed successfully\n\n" + echo '
Installed Python packages (dependency tree)' + echo -e "\n\`\`\`console" + echo "$ python -m pipdeptree --local-only --exclude=pip,pipdeptree" + python -m pipdeptree --local-only --exclude=pip,pipdeptree + echo -e "\`\`\`\n
" + echo '
Outdated Python packages' + echo -e "\n\`\`\`console" + echo "$ python -m pip list --outdated" + python -m pip list --outdated + echo -e "\`\`\`\n
" + } >> $GITHUB_STEP_SUMMARY + + build-inspect: + name: Build and inspect the package + runs-on: ubuntu-24.04 + steps: + - run: sudo apt-get install tree # workaround for "tree: command not found" in baipp + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: hynek/build-and-inspect-python-package@4aea7de65ba374f49b5f549cd471b61de2ef19d3 # v2.5.0 diff --git a/.github/workflows/upgrade-requirements.yml b/.github/workflows/upgrade-requirements.yml new file mode 100644 index 0000000..931d993 --- /dev/null +++ b/.github/workflows/upgrade-requirements.yml @@ -0,0 +1,54 @@ +# This CI job is adapted from: +# build-and-inspect-python-package (2024-03-25), MIT license +# Ref: https://github.com/hynek/build-and-inspect-python-package/blob/v2.2.1/.github/workflows/update-dependencies.yml + +name: Upgrade requirements + +on: + schedule: + # run once a month at midnight of the first day of the month + - cron: 0 0 1 * * + workflow_dispatch: # run manually from actions tab + +permissions: + contents: read + +jobs: + upgrade: + permissions: + contents: write # for peter-evans/create-pull-request to create branch + pull-requests: write # for peter-evans/create-pull-request to create a PR + name: Upgrade requirements + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - name: Install uv + run: curl -LsSf https://astral.sh/uv/install.sh | sh + - name: Upgrade requirements + run: > + uv pip compile + --upgrade + --generate-hashes + --python-version=3.10 + --output-file=.github/requirements/ci.txt + .github/requirements/ci.in + # Ref: https://github.com/peter-evans/create-pull-request + - uses: peter-evans/create-pull-request@6d6857d36972b65feb161a90e484f2984215f83e # v6.0.5 + with: + token: ${{ secrets.GITHUB_TOKEN }} + branch: requirement-upgrades + committer: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> + author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> + title: 'build(deps-dev): upgrade ci requirements' + commit-message: 'build(deps-dev): upgrade ci requirements' + body: | + Monthly scheduled CI requirements upgrade (`uv pip compile --upgrade`). + + > [!NOTE] + > Mark this PR as "ready for review" to trigger additional checks. + add-paths: .github/requirements/ci.txt + labels: | + type: build + deps: python + delete-branch: true + draft: true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..de9dbc8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,88 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.coverage +.coverage.* +.cache +coverage.* +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +.python-version + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# mkdocs documentation +docs/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Cython debug symbols +cython_debug/ + +# ruff +.ruff_cache diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..68d2a4d --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,100 @@ +# pre-commit +# Ref: https://pre-commit.com/#usage +# ------------------------------------------------------------------------------ + +# Ref: https://pre-commit.ci/#configuration +ci: + autofix_prs: false + autoupdate_commit_msg: 'build: update pre-commit hooks' + autoupdate_schedule: monthly + skip: [licensecheck] # does not run on pre-commit.ci, due to sqlite error, runs locally + +# do not touch the cassette files: these are auto-generated by vcr.py +exclude: \/cassettes\/ + +repos: + # Ref: https://pre-commit.com/#meta-hooks +- repo: meta + hooks: + - id: check-hooks-apply + +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: 2c9f875913ee60ca25ce70243dc24d5b6415598c # frozen: v4.6.0 + hooks: + - id: check-merge-conflict + - id: check-case-conflict + - id: check-ast + - id: debug-statements + - id: check-toml + - id: check-yaml + - id: end-of-file-fixer + - id: trailing-whitespace + args: [--markdown-linebreak-ext=md] + - id: name-tests-test + args: [--pytest-test-first] + +- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks + rev: bdf9bad34ed8102dee37a1fabb11ebc40d51063f # frozen: v2.13.0 + hooks: + - id: pretty-format-yaml + args: [--autofix, --indent, '2'] + +- repo: https://github.com/python-jsonschema/check-jsonschema + rev: e35bf69a6edaf50c4ba83c0316cdfacaf76806b1 # frozen: 0.28.3 + hooks: + - id: check-dependabot + - id: check-github-workflows + +- repo: https://github.com/tox-dev/pyproject-fmt + rev: cd3f07b1c620b288cb9173e257ff3edf1a3b4edb # frozen: 2.1.1 + hooks: + - id: pyproject-fmt + +- repo: https://github.com/executablebooks/mdformat + rev: 08fba30538869a440b5059de90af03e3502e35fb # frozen: 0.7.17 + hooks: + - id: mdformat + args: [--number, --wrap=120, --ignore-missing-references] + exclude: CHANGELOG.md|.changelog.md|docs/src/api + additional_dependencies: + - mdformat-mkdocs[recommended]>=v2.0.7 + +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: f8a3f8c471fb698229face5ed7640a64900b781e # frozen: v0.4.4 + hooks: + - id: ruff + args: [--fix, --show-fixes, --exit-non-zero-on-fix] + - id: ruff-format + +- repo: https://github.com/pre-commit/mirrors-mypy + rev: e5ea6670624c24f8321f6328ef3176dbba76db46 # frozen: v1.10.0 + hooks: + - id: mypy + args: [--config-file=pyproject.toml] + additional_dependencies: + - httpx>=0.27 + - pytest>=8.1 + +- repo: https://github.com/scientific-python/cookie + rev: 28d1a53da26f9daff6d9a49c50260421ad6d05e0 # frozen: 2024.04.23 + hooks: + - id: sp-repo-review + +- repo: https://github.com/crate-ci/typos + rev: ee276ae87cb98d65004ebc0096d2c3a210ba9adc # frozen: v1.21.0 + hooks: + - id: typos + args: [--force-exclude] + # CHANGELOG.md: the commit hashes in changelog trigger the spell checker + exclude: CHANGELOG.md + +- repo: https://github.com/FHPythonUtils/LicenseCheck/ + rev: b2b50f4d40c95b15478279a7a00553a1dc2925ef # frozen: 2024.2 + hooks: + - id: licensecheck + +- repo: https://github.com/compilerla/conventional-pre-commit + rev: 4efeb931d635ed3e57749de4326b752b345c8372 # frozen: v3.2.0 + hooks: + - id: conventional-pre-commit + stages: [commit-msg] diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000..df692a6 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,20 @@ +cff-version: 1.2.0 +message: "If you use this software, please cite it as below." +type: software +authors: +- family-names: Fütterer + given-names: Heinz-Alexander + orcid: https://orcid.org/0000-0003-4397-027X +title: python-re3data +license: MIT +license-url: https://github.com/afuetterer/python-re3data/blob/main/LICENSE +repository-code: https://github.com/afuetterer/python-re3data +keywords: +- api +- api-client +- metadata +- re3data +- repositories +- research data +version: 0.1.0 +date-released: 2024-05-18 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6fccb30 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Heinz-Alexander Fütterer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6540bc0 --- /dev/null +++ b/README.md @@ -0,0 +1,63 @@ +# python-re3data: The Pythonic client for the re3data API. + +> ⚠️ Please note that this project is currently under active development. As such, it is considered a work in progress, +> and breaking changes may be introduced at any time. We encourage users to frequently check back for updates and to +> exercise caution when using this project in production environments. Contributions and feedback are welcome to help +> move the project towards a more stable release. + +| __CI__ | [![pre-commit.ci status][pre-commit-ci-badge]][pre-commit-ci-status] [![ci][ci-badge]][ci-workflow] [![coverage][coverage-badge]][ci-workflow] | +| :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| __Docs__ | [![docs][docs-badge]][docs-workflow] | +| __Meta__ | [![OpenSSF Scorecard][scorecard-badge]][scorecard-url] [![hatch][hatch-badge]][hatch] [![ruff][ruff-badge]][ruff] [![mypy][mypy-badge]][mypy] [![License][license-badge]][license-url] | + +**Table of Contents** + +- [Installation](#installation) +- [License](#license) + +## Requirements + +[Python](https://www.python.org/downloads/) >= 3.10 + +`python-re3data` is built with: + +- [httpx](https://github.com/encode/httpx) for issuing HTTP requests + +## Installation + +You can install `python-re3data` via pip from [PyPI][pypi-url]: + +```console +python -m pip install python-re3data +``` + +## Documentation + +The [documentation][docs-url] is made with [Material for MkDocs](https://github.com/squidfunk/mkdocs-material) and is +hosted by [GitHub Pages](https://docs.github.com/en/pages). + +## License + +`python-re3data` is distributed under the terms of the [MIT License][license-url]. + + + +[ci-badge]: https://github.com/afuetterer/python-re3data/actions/workflows/main.yml/badge.svg +[ci-workflow]: https://github.com/afuetterer/python-re3data/actions/workflows/main.yml +[coverage-badge]: https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/afuetterer/adc66df152c473c1aa136557ee8181ca/raw/coverage-badge.json +[docs-badge]: https://github.com/afuetterer/python-re3data/actions/workflows/docs.yml/badge.svg +[docs-url]: https://afuetterer.github.io/python-re3data +[docs-workflow]: https://github.com/afuetterer/python-re3data/actions/workflows/docs.yml +[hatch]: https://github.com/pypa/hatch +[hatch-badge]: https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg +[license-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[license-url]: https://spdx.org/licenses/MIT.html +[mypy]: https://mypy-lang.org +[mypy-badge]: https://img.shields.io/badge/types-mypy-blue.svg +[pre-commit-ci-badge]: https://results.pre-commit.ci/badge/github/afuetterer/python-re3data/main.svg +[pre-commit-ci-status]: https://results.pre-commit.ci/latest/github/afuetterer/python-re3data/main +[pypi-url]: https://pypi.org/project/python-re3data/ +[ruff]: https://github.com/astral-sh/ruff +[ruff-badge]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json +[scorecard-badge]: https://api.securityscorecards.dev/projects/github.com/afuetterer/python-re3data/badge +[scorecard-url]: https://securityscorecards.dev/viewer/?uri=github.com/afuetterer/python-re3data diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml new file mode 100644 index 0000000..228b0a0 --- /dev/null +++ b/docs/mkdocs.yml @@ -0,0 +1,70 @@ +# mkdocs +# Ref: https://www.mkdocs.org/user-guide/configuration/ +# ------------------------------------------------------------------------------ + +site_name: python-re3data +site_description: The Pythonic client for the re3data API. +site_url: https://afuetterer.github.io/python-re3data/ +repo_name: afuetterer/python-re3data +repo_url: https://github.com/afuetterer/python-re3data +docs_dir: src +edit_uri: edit/main/docs/ +strict: true +watch: +- ../src + +nav: +- Home: index.md +- Meta: + - Contributor Guide: contributing.md + - License: license.md + +theme: + name: material + features: + - content.action.edit + - content.action.view + - content.code.annotate + - content.code.copy + - navigation.footer + palette: + - media: '(prefers-color-scheme: light)' + scheme: default + toggle: + icon: material/brightness-7 + name: Switch to dark mode + - media: '(prefers-color-scheme: dark)' + scheme: slate + toggle: + icon: material/brightness-4 + name: Switch to light mode + +plugins: +- search +- include-markdown +- mkdocstrings: + default_handler: python + handlers: + python: + paths: + - ../src + options: + show_root_heading: false + show_root_toc_entry: false + import: + - https://docs.python.org/3/objects.inv + +markdown_extensions: +- admonition +- pymdownx.highlight: + anchor_linenums: true + line_spans: __span + pygments_lang_class: true +- pymdownx.inlinehilite +- pymdownx.snippets +- pymdownx.superfences + +extra: + version: + provider: mike + alias: true diff --git a/docs/src/contributing.md b/docs/src/contributing.md new file mode 100644 index 0000000..2f4af8c --- /dev/null +++ b/docs/src/contributing.md @@ -0,0 +1 @@ +{% include-markdown "../../.github/CONTRIBUTING.md" %} diff --git a/docs/src/index.md b/docs/src/index.md new file mode 100644 index 0000000..cee3f10 --- /dev/null +++ b/docs/src/index.md @@ -0,0 +1 @@ +{% include-markdown "../../README.md" %} diff --git a/docs/src/license.md b/docs/src/license.md new file mode 100644 index 0000000..0286ad2 --- /dev/null +++ b/docs/src/license.md @@ -0,0 +1 @@ +{% include-markdown "../../LICENSE" %} diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..550f2bf --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,289 @@ +# hatch +# Ref: https://hatch.pypa.io/latest/config/metadata/ +# ------------------------------------------------------------------------------ + +[build-system] +build-backend = "hatchling.build" +requires = [ + "hatchling", +] + +[project] +name = "python-re3data" +description = "The pythonic client for the re3data API." +readme = "README.md" +keywords = [ + "api", + "api-client", + "metadata", + "re3data", + "repositories", + "research data", +] +license = { text = "MIT" } +authors = [ + { name = "Heinz-Alexander Fütterer" }, +] +requires-python = ">=3.10" +classifiers = [ + "Development Status :: 1 - Planning", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Topic :: Text Processing :: Markup :: XML", + "Typing :: Typed", +] +dynamic = [ + "version", +] +dependencies = [ + "httpx>=0.27", +] +optional-dependencies.cli = [ + "typer>=0.12", +] +optional-dependencies.dev = [ + "pre-commit~=3.7", +] +optional-dependencies.docs = [ + "mike~=2.1", + "mkdocs~=1.6", + "mkdocs-include-markdown-plugin~=6.0", + "mkdocs-material~=9.5", + "mkdocstrings[python]~=0.25", +] +optional-dependencies.test = [ + "pytest~=8.2", + "pytest-cov~=5.0", + "pytest-mock~=3.14", + "pytest-randomly~=3.15", + "pytest-recording~=0.13", + "pytest-xdist~=3.6", + "respx~=0.21", +] +urls.Changelog = "https://github.com/afuetterer/python-re3data/blob/main/CHANGELOG.md" +urls.Documentation = "https://afuetterer.github.io/python-re3data" +urls.Issues = "https://github.com/afuetterer/python-re3data/issues" +urls.Repository = "https://github.com/afuetterer/python-re3data.git" +scripts.re3data = "re3data.__main__:app" + +[tool.hatch.build.targets.sdist] +include = [ + "src", + "CHANGELOG.md", +] + +[tool.hatch.build.targets.wheel] +packages = [ + "src/re3data", +] + +[tool.hatch.version] +path = "src/re3data/__about__.py" + +[tool.hatch.envs.default] +installer = "uv" +features = [ + "dev", + "test", +] +post-install-commands = [ + "pre-commit install", +] +[tool.hatch.envs.default.scripts] +check = [ + "lint", + "typecheck", +] +lint = "SKIP=mypy pre-commit run --all-files --color=always --show-diff-on-failure" +typecheck = "pre-commit run --all-files --color=always --show-diff-on-failure mypy" +test = "pytest {args:tests}" +cov = "pytest --cov {args:src}" +cov-report-markdown = "python -m coverage report --format=markdown {args:>coverage.md}" +cov-total = """ + python -m coverage json --quiet + python -c "import json;print(json.load(open('coverage.json'))['totals']['percent_covered_display'])" +""" + +[tool.hatch.envs.docs] +features = [ + "docs", +] +template = "docs" +[tool.hatch.envs.docs.scripts] +build = "mkdocs build --config-file=docs/mkdocs.yml" +serve = "mkdocs serve --verbose --config-file=docs/mkdocs.yml" +deploy = "mike deploy --push --update-aliases $(hatch version) latest --config-file=docs/mkdocs.yml" + +# ruff +# Ref: https://docs.astral.sh/ruff/configuration/ +# ------------------------------------------------------------------------------ + +[tool.ruff] +line-length = 120 +src = [ + "src", + "tests", +] +# Ref: https://docs.astral.sh/ruff/settings/#format +format.docstring-code-format = true +# Ref: https://docs.astral.sh/ruff/rules/ +lint.extend-select = [ + "A", # flake8-builtins + "B", # flake8-bugbear + "C4", # flake8-comprehensions + "D", # pydocstyle + "G", # flake8-logging-format + "I", # isort + "PERF", # perflint-perf + "PGH", # pygrep-hooks + "PIE", # flake8-pie + "PL", # pylint + "PT", # flake8-pytest-style + "RET", # flake8-return + "RSE", # flake8-raise + "RUF", # ruff + "SIM", # flake8-simplify + "T20", # flake8-print + "TCH", # flake8-type-checking + "UP", # pyupgrade + "W", # pycodestyle + "YTT", # flake8-2020 +] +lint.per-file-ignores."src/re3data/__about__.py" = [ + "D100", # undocumented-public-module +] +lint.per-file-ignores."tests/*" = [ + "D100", # undocumented-public-module + "D103", # undocumented-public-function + "PLR2004", # magic-value-comparison +] +lint.unfixable = [ + "F401", # unused-import +] +lint.isort.known-first-party = [ + "re3data", +] +lint.pydocstyle.convention = "google" +lint.ignore = [ + "D105", # undocumented-magic-method + "D107", # undocumented-public-init +] + +# sp-repo-review +# Ref: https://github.com/scientific-python/cookie/tree/main#list-of-checks +# ------------------------------------------------------------------------------ + +[tool.repo-review] +ignore = [ + # PC is Pre-commit + "PC111", # blacken-docs + "PC160", # codespell + "PC170", # pygrep hooks + "PC180", # prettier + "RTD", # read the docs +] + +# pytest +# Ref: https://docs.pytest.org/en/stable/customize.html +# ------------------------------------------------------------------------------ + +[tool.pytest.ini_options] +minversion = "8.0" +addopts = [ + "-ra", + "--showlocals", + "--strict-markers", + "--strict-config", +] +filterwarnings = [ + "error", +] +log_cli_level = "INFO" +xfail_strict = true +testpaths = "tests" + +# coverage.py +# Ref: https://coverage.readthedocs.io/en/latest/config.html +# ------------------------------------------------------------------------------ + +[tool.coverage.run] +branch = true +parallel = true +source = [ + "re3data", +] +omit = [ + "__about__.py", +] + +[tool.coverage.report] +exclude_also = [ + "if TYPE_CHECKING:", +] +fail_under = 90 +show_missing = true +skip_covered = true +skip_empty = true + +# mypy +# Ref: https://mypy.readthedocs.io/en/stable/config_file.html#using-a-pyproject-toml-file +# ------------------------------------------------------------------------------ + +[tool.mypy] +python_version = "3.10" +strict = true +pretty = true +show_column_numbers = true +show_error_context = true +enable_error_code = [ + "ignore-without-code", + "redundant-expr", + "truthy-bool", +] +warn_unreachable = true + +# licensecheck +# Ref: https://github.com/FHPythonUtils/LicenseCheck/#example-1-pyprojecttoml +# ------------------------------------------------------------------------------ + +[tool.licensecheck] +using = "PEP631" +format = "ansi" + +# python-semantic-release +# Ref: https://python-semantic-release.readthedocs.io/en/latest/configuration.html#settings +# ------------------------------------------------------------------------------ + +[tool.semantic_release] +commit_author = "github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>" +commit_message = "chore: release {version}\n\nAutomatically generated by python-semantic-release [skip ci]" +major_on_zero = false +tag_format = "{version}" +version_variables = [ + "src/re3data/__about__.py:__version__", +] +build_command = """ +sed -i "s/^version: .*/version: $NEW_VERSION/" CITATION.cff +sed -i "s/^date-released: .*/date-released: $(date "+%Y-%m-%d")/" CITATION.cff +git add CITATION.cff +python -m pip install "build[uv]" +python -m build --installer=uv +""" +changelog.template_dir = ".github/templates" +changelog.environment.keep_trailing_newline = true + +# typos +# Ref: https://github.com/crate-ci/typos/blob/master/docs/reference.md +# ------------------------------------------------------------------------------ + +[tool.typos] +# add "spellchecker:disable-line" to ignore specific lines +default.extend-ignore-re = [ + "(?Rm)^.*# spellchecker:disable-line$", +] diff --git a/src/re3data/__about__.py b/src/re3data/__about__.py new file mode 100644 index 0000000..9ac3f16 --- /dev/null +++ b/src/re3data/__about__.py @@ -0,0 +1,5 @@ +# SPDX-FileCopyrightText: 2024 Heinz-Alexander Fütterer +# +# SPDX-License-Identifier: MIT + +__version__ = "0.1.0" diff --git a/src/re3data/__init__.py b/src/re3data/__init__.py new file mode 100644 index 0000000..a3585c4 --- /dev/null +++ b/src/re3data/__init__.py @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2024 Heinz-Alexander Fütterer +# +# SPDX-License-Identifier: MIT + +"""python-re3data.""" + +from re3data.__about__ import __version__ + +__all__ = [ + "__version__", +] diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..c7a9c6a --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2024 Heinz-Alexander Fütterer +# +# SPDX-License-Identifier: MIT diff --git a/tests/test_version.py b/tests/test_version.py new file mode 100644 index 0000000..ee64300 --- /dev/null +++ b/tests/test_version.py @@ -0,0 +1,9 @@ +# SPDX-FileCopyrightText: 2024 Heinz-Alexander Fütterer +# +# SPDX-License-Identifier: MIT + +from re3data import __version__ + + +def test_version() -> None: + assert __version__