diff --git a/.cruft.json b/.cruft.json
new file mode 100644
index 0000000..d8547ae
--- /dev/null
+++ b/.cruft.json
@@ -0,0 +1,27 @@
+{
+ "template": "https://github.com/Midnighter/cookiecutter-python-package",
+ "commit": "e8988f2331b6b12f2a78358fcbd78c013b1443c5",
+ "checkout": null,
+ "context": {
+ "cookiecutter": {
+ "full_name": "OpenTECR developers",
+ "email": "opentecr@googlegroups.com",
+ "dev_platform": "GitHub",
+ "__dev_platform_url": "https://github.com",
+ "dev_platform_username": "rgiessman",
+ "project_name": "OpenTECR Schema",
+ "project_slug": "opentecr-schema",
+ "project_module": "opentecr",
+ "project_short_description": "contains the code for the schema of the openTECR database",
+ "license": "MIT",
+ "release_date": "2023-12-12",
+ "year": "2023",
+ "_extensions": [
+ "jinja2_time.TimeExtension",
+ "jinja2_strcase.StrcaseExtension"
+ ],
+ "_template": "https://github.com/Midnighter/cookiecutter-python-package"
+ }
+ },
+ "directory": null
+}
diff --git a/.editorconfig b/.editorconfig
index 711388e..179dfba 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -10,7 +10,7 @@ insert_final_newline = true
trim_trailing_whitespace = true
max_line_length = 88
-[*.{json,yml}]
+[*.{json,yml,yaml}]
indent_size = 2
[*.{md,rst}]
diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..90272fe
--- /dev/null
+++ b/.github/CODE_OF_CONDUCT.md
@@ -0,0 +1,130 @@
+
+# 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, 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
+[INSERT CONTACT METHOD].
+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 the [Contributor Covenant][homepage],
+version 2.0, available at
+https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
+
+Community Impact Guidelines were inspired by [Mozilla's code of conduct
+enforcement ladder](https://github.com/mozilla/diversity).
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see the FAQ at
+https://www.contributor-covenant.org/faq. Translations are available at
+https://www.contributor-covenant.org/translations.
+
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
new file mode 100644
index 0000000..5554b1c
--- /dev/null
+++ b/.github/CONTRIBUTING.md
@@ -0,0 +1,134 @@
+# Contributing
+
+Contributions are welcome, and they are greatly appreciated! Every little bit
+helps, and credit will always be given.
+
+## Example Contributions
+
+You can contribute in many ways, for example:
+
+* [Report bugs](#report-bugs)
+* [Fix Bugs](#fix-bugs)
+* [Implement Features](#implement-features)
+* [Write Documentation](#write-documentation)
+* [Submit Feedback](#submit-feedback)
+
+### Report Bugs
+
+Report bugs at https://github.com/rgiessman/opentecr-schema/issues.
+
+**If you are reporting a bug, please follow the template guidelines. The more
+detailed your report, the easier and thus faster we can help you.**
+
+### Fix Bugs
+
+Look through the GitHub issues for bugs. Anything labelled with `bug` and `help
+wanted` is open to whoever wants to implement it. When you decide to work on
+such an issue, please [assign yourself to
+it](https://docs.github.com/en/issues/tracking-your-work-with-issues/assigning-issues-and-pull-requests-to-other-github-users)
+and add a comment that you'll be working on that, too. If you see another issue
+without the `help wanted` label, just post a comment, the maintainers are
+usually happy for any support that they can get.
+
+### Implement Features
+
+Look through the GitHub issues for features. Anything labelled with
+`enhancement` and `help wanted` is open to whoever wants to implement it. As for
+[fixing bugs](#fix-bugs), please [assign yourself to the
+issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/assigning-issues-and-pull-requests-to-other-github-users)
+and add a comment that you'll be working on that, too. If another enhancement
+catches your fancy, but it doesn't have the `help wanted` label, just post a
+comment, the maintainers are usually happy for any support that they can get.
+
+### Write Documentation
+
+OpenTECR Schema could always use more documentation, whether as
+part of the official documentation, in docstrings, or even on the web in blog
+posts, articles, and such. Just [open an issue](https://github.com/rgiessman/opentecr-schema/issues) to let us know what you will be working on
+so that we can provide you with guidance.
+
+### Submit Feedback
+
+The best way to send feedback is to file an issue at https://github.com/rgiessman/opentecr-schema/issues. If your feedback fits the format of one of
+the issue templates, please use that. Remember that this is a volunteer-driven
+project and everybody has limited time.
+
+## Get Started!
+
+Ready to contribute? Here's how to set up OpenTECR Schema for
+local development.
+
+1. Fork the https://github.com/rgiessman/opentecr-schema
+ repository on GitHub.
+2. Clone your fork locally
+
+ ```shell
+ git clone git@github.com:your_name_here/opentecr-schema.git
+ ```
+
+3. Install your local copy into a Python virtual environment. You can [read this
+ guide to learn
+ more](https://realpython.com/python-virtual-environments-a-primer) about them
+ and how to create one. Alternatively, particularly if you are a Windows or
+ Mac user, you can also use [Anaconda](https://docs.anaconda.com/anaconda/).
+ Once you have created a virtual environment and activated it, this is how you
+ set up your fork for local development
+
+ ```shell
+ cd opentecr-schema
+ pip install -e '.[development]'
+ pre-commit install
+ ```
+
+ The commands above install the package with all of its normal and
+ development dependencies into your virtual environment. The package itself
+ is installed in editable mode (`-e`) such that any modifications that you
+ make are immediately reflected in the installed package. Furthermore, we use
+ pre-commit hooks to ensure consistent code formatting. They are installed
+ with the command above and will run when you try to `git commit` your
+ changes.
+
+4. Create a branch for local development using the `devel` branch as a starting
+ point. Use `fix` or `feat` as a prefix for your branch name.
+
+ ```shell
+ git checkout devel
+ git checkout -b fix-name-of-your-bugfix
+ ```
+
+ Now you can make your changes locally.
+
+5. When you're done making changes, apply the quality assurance tools and check
+ that your changes pass our test suite. This is all included with tox
+
+ ```shell
+ tox
+ ```
+
+ You can also run tox in parallel to speed this up.
+
+ ```shell
+ tox -p auto
+ ```
+
+6. Commit your changes and push your branch to GitHub. Please use [semantic
+ commit messages](https://www.conventionalcommits.org/).
+
+ ```shell
+ git add .
+ git commit -m "fix: summarize your changes"
+ git push origin fix-name-of-your-bugfix
+ ```
+
+7. Open the link displayed in the message when pushing your new branch in order
+ to submit a pull request.
+
+### 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. Your pull request will automatically be checked by the full tox test suite.
+ It needs to pass all of them before it can be considered for merging.
diff --git a/.github/ISSUE_TEMPLATE/01-bug-report.yml b/.github/ISSUE_TEMPLATE/01-bug-report.yml
new file mode 100644
index 0000000..a1e6f38
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/01-bug-report.yml
@@ -0,0 +1,64 @@
+name: 🐞 Bug report
+description: Report a problem to help improve this project
+title: "[BUG] "
+labels: [bug, triage]
+body:
+ - type: checkboxes
+ attributes:
+ label: Is there an existing issue for this?
+ description: Please search to see if an issue already exists for the bug you encountered.
+ options:
+ - label: I have searched the existing issues
+ required: true
+ - type: textarea
+ attributes:
+ label: Problem description
+ description: |
+ A concise description of what you're experiencing.
+
+ Please explain:
+
+ * **what** you tried to achieve,
+ * **how** you went about it (referring to the code sample), and
+ * **why** the current behaviour is a problem and what output you expected instead.
+ validations:
+ required: false
+ - type: textarea
+ attributes:
+ label: Code sample
+ description: >
+ Create a [minimal, complete, verifiable example](https://stackoverflow.com/help/mcve).
+ Please, paste your code between the ``` tickmarks below or link to a [gist](https://gist.github.com/).
+ value: |
+ Code run:
+
+ ```python
+ ```
+
+ Traceback:
+
+ ```text
+ ```
+ validations:
+ required: false
+ - type: textarea
+ attributes:
+ label: Environment
+ description: >
+ Please paste the output of running `depinfo --markdown opentecr-schema`
+ in your environment between the `details` tags below.
+ value: |
+
+
+
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: Anything else?
+ description: |
+ Links? References? Anything that will give us more context about the issue you are encountering!
+
+ Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
+ validations:
+ required: false
diff --git a/.github/ISSUE_TEMPLATE/02-question.yml b/.github/ISSUE_TEMPLATE/02-question.yml
new file mode 100644
index 0000000..aa82060
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/02-question.yml
@@ -0,0 +1,26 @@
+name: Question
+description: Ask a question
+title: "[Question] "
+labels: [question]
+body:
+ - type: checkboxes
+ attributes:
+ label: Checklist
+ description: >
+ To help keep this issue tracker clean and focused, please make sure that you have
+ tried *all* of the following resources before submitting your question.
+ options:
+ - label: I searched the [documentation](https://opentecr-schema.readthedocs.io).
+ required: true
+ - label: I looked through existing [discussion topics](https://github.com/rgiessman/opentecr-schema/discussions).
+ required: true
+ - label: I looked for [similar issues](https://github.com/rgiessman/opentecr-schema/issues).
+ required: true
+ - label: I looked up my question/problem in a search engine.
+ required: true
+ - type: textarea
+ attributes:
+ label: Question
+ description: Please ask your question
+ validations:
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/03-feature-request.yml b/.github/ISSUE_TEMPLATE/03-feature-request.yml
new file mode 100644
index 0000000..7fcd56a
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/03-feature-request.yml
@@ -0,0 +1,45 @@
+name: Feature request
+description: Suggest an idea for this project
+title: "[Feature] "
+labels: [enhancement]
+body:
+ - type: checkboxes
+ attributes:
+ label: Checklist
+ description: >
+ Please make sure you check all these items before submitting your feature request.
+ options:
+ - label: There are [no similar issues or pull requests](https://github.com/rgiessman/opentecr-schema/issues) for this yet.
+ required: true
+ - type: textarea
+ attributes:
+ label: Problem
+ description: >
+ A clear and concise description of what you are trying to achieve.
+ placeholder: >
+ "I want to be able to [...] but I can't because [...]".
+ validations:
+ required: false
+ - type: textarea
+ attributes:
+ label: Solution
+ description: >
+ A clear and concise description of what you would want to happen.
+ For API changes, try to provide a code snippet of what you would like the new API to look like.
+ validations:
+ required: false
+ - type: textarea
+ attributes:
+ label: Alternatives
+ description: >
+ Please describe any alternative solutions or features you've considered to solve
+ your problem and why they didn't help.
+ validations:
+ required: false
+ - type: textarea
+ attributes:
+ label: Anything else?
+ description: >
+ Provide any additional context, screenshots, tracebacks, etc. about the feature here.
+ validations:
+ required: false
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..0b2042f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,5 @@
+blank_issues_enabled: true
+contact_links:
+ - name: Community Support
+ url: https://github.com/rgiessman/opentecr-schema/discussions
+ about: Please ask and answer questions here.
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..81900b0
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,4 @@
+* [ ] fix #(issue number)
+* [ ] description of feature/fix
+* [ ] tests added/passed
+* [ ] add an entry to the [changelog](../CHANGELOG.md)
diff --git a/.github/SUPPORT.md b/.github/SUPPORT.md
new file mode 100644
index 0000000..fc1a74f
--- /dev/null
+++ b/.github/SUPPORT.md
@@ -0,0 +1,4 @@
+# Support
+
+* Email the authors or maintainers
+* [opentecr-schema Discussions](https://github.com/rgiessman/opentecr-schema/discussions)
diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml
new file mode 100644
index 0000000..15341ac
--- /dev/null
+++ b/.github/workflows/cron.yml
@@ -0,0 +1,32 @@
+name: Cron Test
+
+on:
+ schedule:
+ # Run every Tuesday at 11:00.
+ - cron: '0 11 * * 2'
+
+jobs:
+ test:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-latest, macos-latest, windows-latest]
+ python-version: ['3.8', '3.9', '3.10', '3.11']
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v4
+ with:
+ python-version: ${{ matrix.python-version }}
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip setuptools wheel
+ python -m pip install tox tox-gh-actions
+
+ - name: Test with tox
+ run: tox run-parallel --parallel auto --parallel-no-spinner
+
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 0000000..f88e824
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,88 @@
+name: CI-CD
+
+on:
+ push:
+ branches:
+ - main
+ - devel
+ tags:
+ - '[0-9]+.[0-9]+.[0-9]+'
+ - '[0-9]+.[0-9]+.[0-9]+(a|b|rc|post|dev)[0-9]+'
+ pull_request:
+ branches:
+ - main
+ - devel
+
+jobs:
+ test:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-latest, macos-latest, windows-latest]
+ python-version: ['3.11', '3.12']
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v4
+ with:
+ python-version: ${{ matrix.python-version }}
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip setuptools wheel
+ python -m pip install tox tox-gh-actions
+
+ - name: Test with tox
+ run: tox run-parallel --parallel auto --parallel-no-spinner -- --cov-report=xml
+
+ - name: Report coverage
+ shell: bash
+ run: bash <(curl -s https://codecov.io/bash)
+
+ release:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [ubuntu-latest]
+ python-version: ['3.11']
+ needs: test
+ if: github.ref_type == 'tag'
+ permissions:
+ contents: write
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v4
+ with:
+ python-version: ${{ matrix.python-version }}
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip setuptools wheel
+ python -m pip install hatch
+
+ - name: Build package
+ run: hatch build
+
+ - name: Publish to PyPI
+ env:
+ HATCH_INDEX_USER: ${{ secrets.PYPI_USERNAME }}
+ HATCH_INDEX_AUTH: ${{ secrets.PYPI_PASSWORD }}
+ run:
+ hatch publish --no-prompt
+
+ - name: GH release
+ uses: softprops/action-gh-release@v1
+ with:
+ body: >
+ Please see
+ https://github.com/${{ github.repository }}/blob/${{ github.ref_name }}/CHANGELOG.md
+ for the full release notes.
+ draft: false
+ prerelease: false
+
diff --git a/.gitignore b/.gitignore
index 1123d83..d5e55fc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,45 +1,4 @@
-### macOS template
-# General
-.DS_Store
-.AppleDouble
-.LSOverride
-
-# Icon must end with two \r
-Icon
-
-# Thumbnails
-._*
-
-# Files that might appear in the root of a volume
-.DocumentRevisions-V100
-.fseventsd
-.Spotlight-V100
-.TemporaryItems
-.Trashes
-.VolumeIcon.icns
-.com.apple.timemachine.donotpresent
-
-# Directories potentially created on remote AFP share
-.AppleDB
-.AppleDesktop
-Network Trash Folder
-Temporary Items
-.apdisk
-
-### JupyterNotebooks template
-# gitignore template for Jupyter Notebooks
-# website: http://jupyter.org/
-
-.ipynb_checkpoints
-*/.ipynb_checkpoints/*
-
-# IPython
-profile_default/
-ipython_config.py
-
-# Remove previous ipynb_checkpoints
-# git rm -r .ipynb_checkpoints/
-
+# Created by .ignore support plugin (hsz.mobi)
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
@@ -63,6 +22,7 @@ parts/
sdist/
var/
wheels/
+pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
@@ -89,10 +49,8 @@ htmlcov/
nosetests.xml
coverage.xml
*.cover
-*.py,cover
.hypothesis/
.pytest_cache/
-cover/
# Translations
*.mo
@@ -102,7 +60,6 @@ cover/
*.log
local_settings.py
db.sqlite3
-db.sqlite3-journal
# Flask stuff:
instance/
@@ -115,17 +72,17 @@ instance/
docs/_build/
# 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
+.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
@@ -134,12 +91,8 @@ target/
# install all needed dependencies.
#Pipfile.lock
-# PEP 582; used by e.g. github.com/David-OConnor/pyflow
-__pypackages__/
-
-# Celery stuff
+# celery beat schedule file
celerybeat-schedule
-celerybeat.pid
# SageMath parsed files
*.sage.py
@@ -171,11 +124,10 @@ dmypy.json
# Pyre type checker
.pyre/
-# pytype static type analyzer
-.pytype/
-
-# Cython debug symbols
-cython_debug/
+### TextMate template
+*.tmproj
+*.tmproject
+tmtags
### Windows template
# Windows thumbnail cache files
@@ -203,8 +155,530 @@ $RECYCLE.BIN/
# Windows shortcuts
*.lnk
-### Linux template
+### JupyterNotebooks template
+# gitignore template for Jupyter Notebooks
+# website: http://jupyter.org/
+
+*/.ipynb_checkpoints/*
+
+# IPython
+
+# Remove previous ipynb_checkpoints
+# git rm -r .ipynb_checkpoints/
+
+### Vim template
+# Swap
+[._]*.s[a-v][a-z]
+!*.svg # comment out if you don't need vector files
+[._]*.sw[a-p]
+[._]s[a-rt-v][a-z]
+[._]ss[a-gi-z]
+[._]sw[a-p]
+
+# Session
+Session.vim
+Sessionx.vim
+
+# Temporary
+.netrwhist
*~
+# Auto-generated tag files
+tags
+# Persistent undo
+[._]*.un~
+
+### VirtualEnv template
+# Virtualenv
+# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
+[Bb]in
+[Ii]nclude
+[Ll]ib
+[Ll]ib64
+[Ll]ocal
+[Ss]cripts
+pyvenv.cfg
+pip-selfcheck.json
+
+### Dropbox template
+# Dropbox settings and caches
+.dropbox
+.dropbox.attr
+.dropbox.cache
+
+### VisualStudioCode template
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+*.code-workspace
+
+# Local History for Visual Studio Code
+.history/
+
+### VisualStudio template
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
+
+### macOS template
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+### Python template
+# Byte-compiled / optimized / DLL files
+
+# C extensions
+
+# Distribution / packaging
+
+# 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.
+
+# Installer logs
+
+# Unit test / coverage reports
+*.py,cover
+cover/
+
+# Translations
+
+# Django stuff:
+db.sqlite3-journal
+
+# Flask stuff:
+
+# Scrapy stuff:
+
+# Sphinx documentation
+
+# PyBuilder
+.pybuilder/
+
+# Jupyter Notebook
+
+# IPython
+
+# 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
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow
+__pypackages__/
+
+# Celery stuff
+celerybeat.pid
+
+# SageMath parsed files
+
+# Environments
+
+# Spyder project settings
+
+# Rope project settings
+
+# mkdocs documentation
+
+# mypy
+
+# Pyre type checker
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+### Linux template
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
@@ -218,3 +692,112 @@ $RECYCLE.BIN/
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
+### SublimeText template
+# Cache files for Sublime Text
+*.tmlanguage.cache
+*.tmPreferences.cache
+*.stTheme.cache
+
+# Workspace files are user-specific
+*.sublime-workspace
+
+# Project files should be checked into the repository, unless a significant
+# proportion of contributors will probably not be using Sublime Text
+# *.sublime-project
+
+# SFTP configuration file
+sftp-config.json
+sftp-config-alt*.json
+
+# Package control specific files
+Package Control.last-run
+Package Control.ca-list
+Package Control.ca-bundle
+Package Control.system-ca-bundle
+Package Control.cache/
+Package Control.ca-certs/
+Package Control.merged-ca-bundle
+Package Control.user-ca-bundle
+oscrypto-ca-bundle.crt
+bh_unicode_properties.cache
+
+# Sublime-github package stores a github token in this file
+# https://packagecontrol.io/packages/sublime-github
+GitHub.sublime-settings
+
+### JetBrains template
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn. Uncomment if using
+# auto-import.
+# .idea/artifacts
+# .idea/compiler.xml
+# .idea/jarRepositories.xml
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+# *.iml
+# *.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+# Project
+/.ruff_cache/
+/src/opentecr/_version.py
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..f95ccf7
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,15 @@
+default_language_version:
+ python: python3.11
+repos:
+ - repo: https://github.com/pycqa/isort
+ rev: 5.12.0
+ hooks:
+ - id: isort
+ - repo: https://github.com/psf/black
+ rev: 23.1.0
+ hooks:
+ - id: black
+ - repo: https://github.com/pre-commit/mirrors-prettier
+ rev: v2.7.1
+ hooks:
+ - id: prettier
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
new file mode 100644
index 0000000..b877fec
--- /dev/null
+++ b/.readthedocs.yaml
@@ -0,0 +1,18 @@
+# Read the Docs configuration file
+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
+version: 2
+
+build:
+ os: ubuntu-22.04
+ tools:
+ python: "3.10"
+
+mkdocs:
+ configuration: mkdocs.yml
+
+python:
+ install:
+ - method: pip
+ path: .
+ extra_requirements:
+ - dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..f2fa781
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,14 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+* Upcoming features and fixes
+
+## [0.1.0] - (2023-12-12)
+
+* First release
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..4b4742d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 OpenTECR developers
+
+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 (including the next
+paragraph) 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/Makefile b/Makefile
deleted file mode 100644
index 9baa479..0000000
--- a/Makefile
+++ /dev/null
@@ -1,72 +0,0 @@
-################################################################################
-# COMMANDS #
-################################################################################
-
-.PHONY: qa
-## Apply code quality assurance tools.
-qa:
- isort src/opentecr scripts/
- black src/opentecr scripts/
-
-################################################################################
-# Self Documenting Commands #
-################################################################################
-
-.DEFAULT_GOAL := show-help
-
-# Inspired by
-#
-# sed script explained:
-# /^##/:
-# * save line in hold space
-# * purge line
-# * Loop:
-# * append newline + line to hold space
-# * go to next line
-# * if line starts with doc comment, strip comment character off and loop
-# * remove target prerequisites
-# * append hold space (+ newline) to line
-# * replace newline plus comments by `---`
-# * print line
-# Separate expressions are necessary because labels cannot be delimited by
-# semicolon; see
-.PHONY: show-help
-show-help:
- @echo "$$(tput bold)Available rules:$$(tput sgr0)"
- @echo
- @sed -n -e "/^## / { \
- h; \
- s/.*//; \
- :doc" \
- -e "H; \
- n; \
- s/^## //; \
- t doc" \
- -e "s/:.*//; \
- G; \
- s/\\n## /---/; \
- s/\\n/ /g; \
- p; \
- }" ${MAKEFILE_LIST} \
- | LC_ALL='C' sort --ignore-case \
- | awk -F '---' \
- -v ncol=$$(tput cols) \
- -v indent=19 \
- -v col_on="$$(tput setaf 6)" \
- -v col_off="$$(tput sgr0)" \
- '{ \
- printf "%s%*s%s ", col_on, -indent, $$1, col_off; \
- n = split($$2, words, " "); \
- line_length = ncol - indent; \
- for (i = 1; i <= n; i++) { \
- line_length -= length(words[i]) + 1; \
- if (line_length <= 0) { \
- line_length = ncol - indent - length(words[i]) - 1; \
- printf "\n%*s ", -indent, " "; \
- } \
- printf "%s ", words[i]; \
- } \
- printf "\n"; \
- }' \
- | more $(shell test $(shell uname) = Darwin && \
- echo '--no-init --raw-control-chars')
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0e745bd
--- /dev/null
+++ b/README.md
@@ -0,0 +1,55 @@
+# OpenTECR Schema
+
+| | |
+|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Package | [](https://pypi.org/project/opentecr-schema/) [](https://pypi.org/project/opentecr-schema/) [](https://opentecr-schema.readthedocs.io/en/latest/?badge=latest) |
+| Meta | [](LICENSE) [](.github/CODE_OF_CONDUCT.md) [](https://github.com/ambv/black) |
+| Automation | [](https://github.com/rgiessman/opentecr-schema/workflows/CI-CD) [](https://codecov.io/gh/rgiessman/opentecr-schema) |
+
+contains the code for the schema of the openTECR database
+
+## Post Template-Instantiation Steps
+
+1. Start working with git.
+
+ ```shell
+ git init
+ ```
+
+2. Install the git pre-commit hooks using the `pre-commit` tool.
+
+ ```shell
+ pip install pre-commit
+ pre-commit install
+ ```
+
+3. Commit all the files.
+
+ ```shell
+ git add .
+ git commit -m "chore: initialize project cookiecutter"
+ ```
+
+4. Create a repository on [GitHub](https://github.com) if you haven't done
+ so yet.
+5. Browse through the architecture decision records (`docs/adr`) if you want
+ to understand details of the package design.
+6. Remove this section from the readme and describe what your package is all
+ about.
+7. When you're ready to make a release, perform the following steps.
+
+ 1. On [GitHub](https://github.com) set the secure environment
+ variables `PYPI_USERNAME` and `PYPI_PASSWORD` to `__token__` and a respective PyPI API token.
+ 2. Tag your latest commit with the desired version and let GitHub handle
+ the release.
+
+ ```shell
+ git tag 0.1.0
+ git push origin 0.1.0
+ ```
+
+## Copyright
+
+* Copyright © 2023 OpenTECR developers.
+* Free software distributed under the [MIT License](../LICENSE).
+
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000..b143302
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,9 @@
+# OpenTECR Schema
+
+contains the code for the schema of the openTECR database
+
+## Copyright
+
+* Copyright © 2023 OpenTECR developers.
+* Free software distributed under the [MIT License](../LICENSE).
+
diff --git a/mkdocs.yml b/mkdocs.yml
new file mode 100644
index 0000000..3ee6ff8
--- /dev/null
+++ b/mkdocs.yml
@@ -0,0 +1,68 @@
+site_name: OpenTECR Schema
+site_description: contains the code for the schema of the openTECR database
+site_author: OpenTECR developers
+site_url: https://opentecr-schema.readthedocs.io/
+
+markdown_extensions:
+ - admonition
+ - toc:
+ permalink: true
+ - pymdownx.highlight:
+ anchor_linenums: true
+ - pymdownx.inlinehilite
+ - pymdownx.superfences:
+ - pymdownx.emoji:
+ emoji_index: !!python/name:materialx.emoji.twemoji
+ emoji_generator: !!python/name:materialx.emoji.to_svg
+
+theme:
+ features:
+ - content.code.annotate
+ - navigation.indexes
+ - navigation.instant
+ - navigation.tracking
+ - navigation.top
+ name: material
+ palette:
+ - media: "(prefers-color-scheme: light)"
+ scheme: default
+ primary: green
+ accent: light green
+ toggle:
+ icon: material/weather-night
+ name: Switch to dark mode
+ - media: "(prefers-color-scheme: dark)"
+ scheme: slate
+ primary: green
+ accent: light green
+ toggle:
+ icon: material/weather-sunny
+ name: Switch to light mode
+
+plugins:
+ - search
+ - mkdocstrings:
+ handlers:
+ python:
+ paths: [src]
+ options:
+ show_submodules: true
+ show_category_heading: true
+ show_if_no_docstring: true
+ show_signature_annotations: true
+ default_handler: python
+ - awesome-pages
+
+extra:
+ social:
+ - icon: fontawesome/brands/github
+ link: https://github.com/rgiessman
+ name: OpenTECR developers
+
+copyright: Copyright © 2023 OpenTECR developers
+
+repo_url: https://github.com/rgiessman/opentecr-schema
+repo_name: rgiessman/opentecr-schema
+
+watch:
+ - src/opentecr
diff --git a/output/openTECR.json b/output/openTECR.json
index 5f95f23..ee1ea53 100644
--- a/output/openTECR.json
+++ b/output/openTECR.json
@@ -1,191 +1,273 @@
{
- "title": "openTECR Data Model",
- "definitions": {
- "LiteratureReference": {
- "title": "LiteratureReference",
- "description": "Define a customized base model.",
- "type": "object",
+ "$defs": {
+ "Annotation": {
+ "description": "A class representing an annotation.",
"properties": {
- "pubmedId": {
- "title": "PubMed Identifier",
- "type": "string"
- },
- "doi": {
- "title": "Digital Object Identifier (DOI)",
- "type": "string"
- },
- "url": {
- "title": "Universal Resource Locator (URL)",
- "type": "string"
- },
- "title": {
- "title": "Title",
+ "namespace": {
+ "description": "The MIRIAM compliant prefix of the identifier namespace. MUST be registered at https://identifiers.org/.",
+ "title": "Namespace",
"type": "string"
},
- "authors": {
- "title": "Authors",
+ "identifier": {
+ "description": "The actual identifier within the namespace.",
+ "title": "Identifier",
"type": "string"
- },
- "year": {
- "title": "Year",
- "type": "integer"
}
},
"required": [
- "title",
- "authors",
- "year"
- ]
+ "namespace",
+ "identifier"
+ ],
+ "title": "Annotation",
+ "type": "object"
},
"Contributor": {
- "title": "Contributor",
- "description": "Define a customized base model.",
- "type": "object",
+ "description": "Data about a person who contributes to OpenTECR.",
"properties": {
"orcid": {
- "title": "ORCID",
"description": "The ORCID is a nonproprietary alphanumeric code to uniquely identify authors and contributors of scholarly communication.",
+ "title": "ORCID",
"type": "string"
},
"name": {
- "title": "Name",
"description": "The contributor's full name.",
+ "title": "Name",
"type": "string"
}
},
"required": [
"orcid",
"name"
- ]
+ ],
+ "title": "Contributor",
+ "type": "object"
},
- "Annotation": {
- "title": "Annotation",
- "description": "Define a customized base model.",
- "type": "object",
+ "LiteratureReference": {
+ "description": "Information about a literature reference.",
"properties": {
- "namespace": {
- "title": "Namespace",
- "description": "The MIRIAM compliant prefix of the identifier namespace. MUST be registered at https://identifiers.org/.",
+ "pubmedId": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "PubMed Identifier"
+ },
+ "doi": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Digital Object Identifier (DOI)"
+ },
+ "url": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "title": "Universal Resource Locator (URL)"
+ },
+ "title": {
+ "title": "Title",
"type": "string"
},
- "identifier": {
- "title": "Identifier",
- "description": "The actual identifier within the namespace.",
+ "authors": {
+ "title": "Authors",
"type": "string"
+ },
+ "year": {
+ "title": "Year",
+ "type": "integer"
}
},
"required": [
- "namespace",
- "identifier"
- ]
+ "title",
+ "authors",
+ "year"
+ ],
+ "title": "LiteratureReference",
+ "type": "object"
},
"RepresentativeReaction": {
- "title": "RepresentativeReaction",
- "type": "object",
+ "description": "Information about a reaction.",
"properties": {
"rinchi": {
- "title": "RInChI",
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
"description": "Reaction IUPAC international chemical identifier.",
- "type": "string"
+ "title": "RInChI"
},
"rinchiKey": {
- "title": "RInChIKey",
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
"description": "Hashed version of the reaction IUPAC international chemical identifier.",
- "type": "string"
+ "title": "RInChIKey"
},
"names": {
- "title": "Common Names",
- "description": "Common names or synonyms for this reaction mostly to further human understanding.",
"default": [],
- "type": "array",
+ "description": "Common names or synonyms for this reaction mostly to further human understanding.",
"items": {
"type": "string"
- }
+ },
+ "title": "Common Names",
+ "type": "array"
},
"annotation": {
- "title": "Annotation",
- "description": "Cross-references for the reaction.",
"default": [],
- "type": "array",
+ "description": "Cross-references for the reaction.",
"items": {
- "$ref": "#/definitions/Annotation"
- }
+ "$ref": "#/$defs/Annotation"
+ },
+ "title": "Annotation",
+ "type": "array"
},
"stoichiometry": {
- "title": "Stoichiometry",
- "description": "A dictionary of the stoichiometric coefficients and metabolitesthat define this reaction. Includes both reactants (negative coefficients) and products (positive coefficients).",
- "type": "object",
"additionalProperties": {
"type": "number"
- }
+ },
+ "description": "A dictionary of the stoichiometric coefficients and metabolitesthat define this reaction. Includes both reactants (negative coefficients) and products (positive coefficients).",
+ "title": "Stoichiometry",
+ "type": "object"
}
},
"required": [
"stoichiometry"
- ]
+ ],
+ "title": "RepresentativeReaction",
+ "type": "object"
+ }
+ },
+ "description": "Define a curated measurement of thermodynamic information and context.",
+ "properties": {
+ "reference": {
+ "allOf": [
+ {
+ "$ref": "#/$defs/LiteratureReference"
+ }
+ ],
+ "description": "The official source from which these measurements were curated. Ideally identified by a DOI.",
+ "title": "Literature Reference"
},
- "CuratedMeasurement": {
- "title": "CuratedMeasurement",
- "description": "Define a curated measurement of thermodynamic information and context.",
- "type": "object",
- "properties": {
- "reference": {
- "title": "Literature Reference",
- "description": "The official source from which these measurements were curated. Ideally identified by a DOI.",
- "allOf": [
- {
- "$ref": "#/definitions/LiteratureReference"
- }
- ]
- },
- "curator": {
- "title": "Contributor",
- "description": "The person who contributed these measurements.",
- "allOf": [
- {
- "$ref": "#/definitions/Contributor"
- }
- ]
- },
- "representative_reaction": {
- "title": "Representative Reaction",
- "description": "The representative biochemical reaction to which the measurements apply.",
- "allOf": [
- {
- "$ref": "#/definitions/RepresentativeReaction"
- }
- ]
+ "curator": {
+ "anyOf": [
+ {
+ "$ref": "#/$defs/Contributor"
},
- "equilibriumConstant": {
- "title": "Equilibrium Constant",
- "description": "The equilibrium constant ($K$) of this reaction.",
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "The person who contributed these measurements.",
+ "title": "Contributor"
+ },
+ "representative_reaction": {
+ "allOf": [
+ {
+ "$ref": "#/$defs/RepresentativeReaction"
+ }
+ ],
+ "description": "The representative biochemical reaction to which the measurements apply.",
+ "title": "Representative Reaction"
+ },
+ "equilibriumConstant": {
+ "anyOf": [
+ {
"type": "number"
},
- "hydrogenPotential": {
- "title": "Potential of Hydrogen",
- "description": "The potential of hydrogen (pH) at which the measurements were performed.",
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "The equilibrium constant ($K$) of this reaction.",
+ "title": "Equilibrium Constant"
+ },
+ "hydrogenPotential": {
+ "anyOf": [
+ {
"type": "number"
},
- "magnesiumPotential": {
- "title": "Potential of Magnesium",
- "description": "The potential of magnesium (pMg) at which the measurements were performed.",
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "The potential of hydrogen (pH) at which the measurements were performed.",
+ "title": "Potential of Hydrogen"
+ },
+ "magnesiumPotential": {
+ "anyOf": [
+ {
"type": "number"
},
- "temperature": {
- "title": "Temperature",
- "description": "The temperature in Kelvin (K) at which the measurements were performed.",
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "The potential of magnesium (pMg) at which the measurements were performed.",
+ "title": "Potential of Magnesium"
+ },
+ "temperature": {
+ "anyOf": [
+ {
"type": "number"
},
- "ionicStrength": {
- "title": "Ionic Strength",
- "description": "The molar ionic strength ($I$) of the solution in which the reaction occurred.",
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "The temperature in Kelvin (K) at which the measurements were performed.",
+ "title": "Temperature"
+ },
+ "ionicStrength": {
+ "anyOf": [
+ {
"type": "number"
+ },
+ {
+ "type": "null"
}
- },
- "required": [
- "reference",
- "representative_reaction"
- ]
+ ],
+ "default": null,
+ "description": "The molar ionic strength ($I$) of the solution in which the reaction occurred.",
+ "title": "Ionic Strength"
}
- }
+ },
+ "required": [
+ "reference",
+ "representative_reaction"
+ ],
+ "title": "CuratedMeasurement",
+ "type": "object"
}
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index 3d8c854..edb1cd7 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,10 +1,133 @@
+################################################################################
+# Build Configuration
+################################################################################
+
[build-system]
-build-backend = 'setuptools.build_meta'
-requires = [
- 'setuptools>=40.6.0',
- 'versioneer-518',
- 'wheel'
+build-backend = "hatchling.build"
+requires = ["hatchling", "hatch-vcs"]
+
+################################################################################
+# Project Configuration
+################################################################################
+
+[project]
+name = "opentecr-schema"
+description = "contains the code for the schema of the openTECR database"
+authors = [
+ { name = "OpenTECR developers", email = "opentecr@googlegroups.com" }
+]
+maintainers = [
+ { name = "OpenTECR developers", email = "opentecr@googlegroups.com" }
]
+license = "MIT"
+readme = {"file" = "README.md", "content-type" = "text/markdown"}
+requires-python = ">=3.11"
+# Please consult https://pypi.org/classifiers/ for a full list.
+classifiers = [
+ "Development Status :: 2 - Pre-Alpha",
+ "Intended Audience :: Science/Research",
+ "License :: OSI Approved :: MIT License",
+ "Natural Language :: English",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python :: 3 :: Only",
+ "Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3.12",
+ "Topic :: Scientific/Engineering :: Bio-Informatics"
+]
+# TODO: add keywords
+keywords = []
+dynamic = ["version"]
+dependencies = [
+ "depinfo ~=2.2",
+ "pydantic >= 2.0.0",
+]
+
+[project.urls]
+Homepage = "https://github.com/rgiessman/opentecr-schema"
+Documentation = "https://opentecr-schema.readthedocs.io"
+"Source Code" = "https://github.com/rgiessman/opentecr-schema"
+"Bug Tracker" = "https://github.com/rgiessman/opentecr-schema/issues"
+Download = "https://pypi.org/project/opentecr-schema/#files"
+
+[project.optional-dependencies]
+dev = [
+ "mkdocs-material ~=9.1",
+ "mkdocstrings[python] ~=0.20",
+ "mkdocs-awesome-pages-plugin ~=2.8",
+ "pre-commit",
+ "tox ~=4.0",
+]
+
+################################################################################
+# Tool Configuration
+################################################################################
+
+[tool.hatch.build]
+only-packages = true
+
+[tool.hatch.build.targets.wheel]
+packages = ["src/opentecr"]
+
+[tool.hatch.build.hooks.vcs]
+version-file = "src/opentecr/_version.py"
+
+[tool.hatch.version]
+source = "vcs"
[tool.black]
-python-version = ['py38']
+line-length = 88
+python-version = ["py311"]
+extend-exclude = '''
+(
+ _version.py
+)
+'''
+
+[tool.isort]
+profile = "black"
+lines_after_imports = 2
+lines_before_imports = 2
+known_first_party = "opentecr"
+skip = ["__init__.py"]
+
+[tool.pytest.ini_options]
+testpaths = ["tests"]
+markers = ["raises"]
+
+[tool.coverage.paths]
+source = [
+ "src/opentecr",
+ "*/site-packages/opentecr"
+]
+
+[tool.coverage.run]
+branch = true
+parallel = true
+
+[tool.coverage.report]
+exclude_lines = ["pragma: no cover"]
+precision = 2
+
+[tool.ruff]
+line-length = 88
+select = ["ALL"]
+ignore = [
+ "TD", # ignore flake8-todo rules
+ "FIX", # ignore flake8-fixme rules
+ "D203", # we want no blank line before class docstrings
+ "D213", # multiline docstrings should start just after the quotemarks
+ #"FA100", # pydantic/__future__ problem: see https://github.com/astral-sh/ruff/issues/5434
+]
+
+[tool.ruff.extend-per-file-ignores]
+"test_*.py" = ["S101"]
+
+[tool.mypy]
+plugins = [
+ "pydantic.mypy"
+]
+
+[tool.pydantic-mypy]
+init_forbid_extra = true
+init_typed = true
+warn_required_dynamic_aliases = true
diff --git a/requirements.in b/requirements.in
deleted file mode 100644
index 70c994b..0000000
--- a/requirements.in
+++ /dev/null
@@ -1,2 +0,0 @@
-pydantic ~=1.8
-sqlalchemy ~=1.4
diff --git a/scripts/json_schema.py b/scripts/json_schema.py
index f91953d..3012fde 100644
--- a/scripts/json_schema.py
+++ b/scripts/json_schema.py
@@ -1,22 +1,23 @@
+"""Write the CuratedMeasurement schema to a json file."""
+
import json
+import logging
import sys
from pathlib import Path
-from pydantic.schema import schema
-
+from opentecr.data import CuratedMeasurement
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root / "src"))
-from opentecr.data import CuratedMeasurement
-
-def main():
+def main() -> None:
+ """Run the script."""
+ logger = logging.getLogger()
+ logger.setLevel(logging.INFO)
result_path = project_root / "output" / "openTECR.json"
- result = json.dumps(
- schema([CuratedMeasurement], title="openTECR Data Model"), indent=2
- )
- print(result)
+ result = json.dumps(CuratedMeasurement.model_json_schema(), indent=2)
+ logging.info(result)
with result_path.open("w") as handle:
handle.write(result)
diff --git a/scripts/sql_schema.py b/scripts/sql_schema.py
deleted file mode 100644
index 5695e78..0000000
--- a/scripts/sql_schema.py
+++ /dev/null
@@ -1,19 +0,0 @@
-import sys
-from pathlib import Path
-
-from sqlalchemy import create_engine
-
-
-project_root = Path(__file__).parent.parent
-sys.path.insert(0, str(project_root / "src"))
-
-from opentecr.orm import Base
-
-
-def main():
- db_path = project_root / "output" / "openTECR.sqlite"
- Base.metadata.create_all(create_engine(f"sqlite:///{db_path}"))
-
-
-if __name__ == "__main__":
- main()
diff --git a/src/opentecr/__init__.py b/src/opentecr/__init__.py
index e69de29..c785f74 100644
--- a/src/opentecr/__init__.py
+++ b/src/opentecr/__init__.py
@@ -0,0 +1,25 @@
+# MIT License
+#
+# Copyright (c) 2023 OpenTECR developers
+#
+# 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 (including the next
+# paragraph) 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.
+
+
+"""Provide top level symbols."""
diff --git a/src/opentecr/data/__init__.py b/src/opentecr/data/__init__.py
index 395b282..fe62927 100644
--- a/src/opentecr/data/__init__.py
+++ b/src/opentecr/data/__init__.py
@@ -1,6 +1,42 @@
+# MIT License
+#
+# Copyright (c) 2023 OpenTECR developers
+#
+# 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 (including the next
+# paragraph) 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.
+
+
+"""Provide top level symbols."""
+
+
from .annotation import Annotation
from .contributor import Contributor
+from .curated_measurement import CuratedMeasurement
from .literature_reference import LiteratureReference
from .metabolite import Metabolite
from .representative_reaction import RepresentativeReaction
-from .curated_measurement import CuratedMeasurement
+
+__all__ = [
+ "Annotation",
+ "Contributor",
+ "LiteratureReference",
+ "Metabolite",
+ "RepresentativeReaction",
+ "CuratedMeasurement",
+]
diff --git a/src/opentecr/data/annotation.py b/src/opentecr/data/annotation.py
index 41031c0..9bf3c0e 100644
--- a/src/opentecr/data/annotation.py
+++ b/src/opentecr/data/annotation.py
@@ -1,9 +1,12 @@
+"""Provides dataclass Annotation."""
+
from pydantic import Field
from .base import Base
class Annotation(Base):
+ """A class representing an annotation."""
namespace: str = Field(
...,
@@ -11,6 +14,7 @@ class Annotation(Base):
"registered at https://identifiers.org/.",
)
identifier: str = Field(
- ..., description="The actual identifier within the namespace."
+ ...,
+ description="The actual identifier within the namespace.",
)
# FIXME: add a qualifier field?
diff --git a/src/opentecr/data/base.py b/src/opentecr/data/base.py
index 43f518b..7c7fdc1 100644
--- a/src/opentecr/data/base.py
+++ b/src/opentecr/data/base.py
@@ -1,3 +1,5 @@
+"""Provides class Base specifying configuration that is used in all models."""
+
from pydantic import BaseModel
diff --git a/src/opentecr/data/contributor.py b/src/opentecr/data/contributor.py
index 5a4281e..daadd83 100644
--- a/src/opentecr/data/contributor.py
+++ b/src/opentecr/data/contributor.py
@@ -1,9 +1,13 @@
+"""Provides data class Contributor."""
+
+
from pydantic import Field
from .base import Base
class Contributor(Base):
+ """Data about a person who contributes to OpenTECR."""
orcid: str = Field(
...,
diff --git a/src/opentecr/data/curated_measurement.py b/src/opentecr/data/curated_measurement.py
index 317f052..1c276e7 100644
--- a/src/opentecr/data/curated_measurement.py
+++ b/src/opentecr/data/curated_measurement.py
@@ -1,4 +1,5 @@
-from typing import Optional
+"""Provides dataclass CuratedMeasurement."""
+
from pydantic import Field
@@ -17,7 +18,7 @@ class CuratedMeasurement(Base):
description="The official source from which these measurements were curated. "
"Ideally identified by a DOI.",
)
- curator: Optional[Contributor] = Field(
+ curator: Contributor | None = Field(
None,
title="Contributor",
description="The person who contributed these measurements.",
@@ -31,33 +32,33 @@ class CuratedMeasurement(Base):
# FIXME: add fields for units? (also explicitly dimensionless)
# FIXME: free energy?
# FIXME: apparent equilibrium constant?
- equilibrium_constant: Optional[float] = Field(
+ equilibrium_constant: float | None = Field(
None,
alias="equilibriumConstant",
title="Equilibrium Constant",
description="The equilibrium constant ($K$) of this reaction.",
)
- hydrogen_potential: Optional[float] = Field(
+ hydrogen_potential: float | None = Field(
None,
alias="hydrogenPotential",
title="Potential of Hydrogen",
description="The potential of hydrogen (pH) at which the measurements were "
"performed.",
)
- magnesium_potential: Optional[float] = Field(
+ magnesium_potential: float | None = Field(
None,
alias="magnesiumPotential",
title="Potential of Magnesium",
description="The potential of magnesium (pMg) at which the measurements were "
"performed.",
)
- temperature: Optional[float] = Field(
+ temperature: float | None = Field(
None,
title="Temperature",
description="The temperature in Kelvin (K) at which the measurements were "
"performed.",
)
- ionic_strength: Optional[float] = Field(
+ ionic_strength: float | None = Field(
None,
alias="ionicStrength",
title="Ionic Strength",
diff --git a/src/opentecr/data/literature_reference.py b/src/opentecr/data/literature_reference.py
index 3ac0139..24f6abc 100644
--- a/src/opentecr/data/literature_reference.py
+++ b/src/opentecr/data/literature_reference.py
@@ -1,4 +1,4 @@
-from typing import Optional
+"""Provides dataclass LiteratureReference."""
from pydantic import Field
@@ -6,10 +6,11 @@
class LiteratureReference(Base):
+ """Information about a literature reference."""
- pubmed_id: Optional[str] = Field(None, alias="pubmedId", title="PubMed Identifier")
- doi: Optional[str] = Field(None, title="Digital Object Identifier (DOI)")
- url: Optional[str] = Field(None, title="Universal Resource Locator (URL)")
+ pubmed_id: str | None = Field(None, alias="pubmedId", title="PubMed Identifier")
+ doi: str | None = Field(None, title="Digital Object Identifier (DOI)")
+ url: str | None = Field(None, title="Universal Resource Locator (URL)")
title: str = Field(..., title="Title")
authors: str = Field(..., title="Authors")
year: int = Field(..., title="Year")
diff --git a/src/opentecr/data/metabolite.py b/src/opentecr/data/metabolite.py
index 72c9816..57a7d1a 100644
--- a/src/opentecr/data/metabolite.py
+++ b/src/opentecr/data/metabolite.py
@@ -1,4 +1,5 @@
-from typing import List, Optional
+"""Provides dataclass Metabolite."""
+
from pydantic import Field
@@ -7,8 +8,7 @@
class Metabolite(Base):
- """
- Define a metabolite ORM model.
+ """Define a metabolite ORM model.
Attributes
----------
@@ -24,38 +24,39 @@ class Metabolite(Base):
"""
- inchi: Optional[str] = Field(
+ inchi: str | None = Field(
None,
title="InChI",
description="IUPAC international chemical identifier.",
)
- inchi_key: Optional[str] = Field(
+ inchi_key: str | None = Field(
None,
alias="inchiKey",
title="InChIKey",
description="IUPAC international chemical identifier hashed key.",
)
- smiles: Optional[str] = Field(
+ smiles: str | None = Field(
None,
title="SMILES",
description="Simplified molecular-input line-entry system (SMILES).",
)
- molecular_formula: Optional[str] = Field(
+ molecular_formula: str | None = Field(
None,
alias="molecularFormula",
title="Molecular Formula",
description="The number of atoms in the metabolite.",
)
# FIXME: how do we define charge exactly? valence electrons + protons?
- charge: Optional[float] = Field(None)
+ charge: float | None = Field(None)
# FIXME: molecular weight, atomic mass, or monoisotopic mass?
- mass: Optional[float] = Field(None)
- names: List[str] = Field(
- (),
+ mass: float | None = Field(None)
+ names: list[str] = Field(
+ [],
title="Common Names",
description="Common names or synonyms for this metabolite mostly to further "
"human understanding.",
)
- annotation: List[Annotation] = Field(
- (), description="Cross-references for the metabolite."
+ annotation: list[Annotation] = Field(
+ [],
+ description="Cross-references for the metabolite.",
)
diff --git a/src/opentecr/data/representative_reaction.py b/src/opentecr/data/representative_reaction.py
index 45f771e..043d284 100644
--- a/src/opentecr/data/representative_reaction.py
+++ b/src/opentecr/data/representative_reaction.py
@@ -1,6 +1,7 @@
-from typing import Dict, List, Optional
+"""Provides dataclass RepresentativeReaction."""
-from pydantic import Field
+
+from pydantic import Field, computed_field
from .annotation import Annotation
from .base import Base
@@ -8,30 +9,31 @@
class RepresentativeReaction(Base):
- """"""
+ """Information about a reaction."""
- rinchi: Optional[str] = Field(
+ rinchi: str | None = Field(
None,
title="RInChI",
description="Reaction IUPAC international chemical identifier.",
)
- rinchi_key: Optional[str] = Field(
+ rinchi_key: str | None = Field(
None,
alias="rinchiKey",
title="RInChIKey",
description="Hashed version of the reaction IUPAC international chemical "
"identifier.",
)
- names: List[str] = Field(
- (),
+ names: list[str] = Field(
+ [],
title="Common Names",
description="Common names or synonyms for this reaction mostly to further "
"human understanding.",
)
- annotation: List[Annotation] = Field(
- (), description="Cross-references for the reaction."
+ annotation: list[Annotation] = Field(
+ [],
+ description="Cross-references for the reaction.",
)
- stoichiometry: Dict[Metabolite, float] = Field(
+ stoichiometry: dict[Metabolite, float] = Field(
...,
description="A dictionary of the stoichiometric coefficients and metabolites"
"that define this reaction. Includes both reactants (negative coefficients) "
@@ -39,9 +41,11 @@ class RepresentativeReaction(Base):
)
@property
- def reactants(self) -> List[Metabolite]:
- return [met for met, coef in self.stoichiometry if coef < 0]
+ def reactants(self: "RepresentativeReaction") -> list[Metabolite]:
+ """Add the reactants attribute."""
+ return [met for met, coef in self.stoichiometry.items() if coef < 0]
@property
- def products(self) -> List[Metabolite]:
- return [met for met, coef in self.stoichiometry if coef > 0]
+ def products(self: "RepresentativeReaction") -> list[Metabolite]:
+ """Add the products attribute."""
+ return [met for met, coef in self.stoichiometry.items() if coef > 0]
diff --git a/src/opentecr/py.typed b/src/opentecr/py.typed
new file mode 100644
index 0000000..e69de29
diff --git a/tests/integration/.keep b/tests/integration/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/tests/integration/test_json_schema.py b/tests/integration/test_json_schema.py
new file mode 100644
index 0000000..6399639
--- /dev/null
+++ b/tests/integration/test_json_schema.py
@@ -0,0 +1,17 @@
+"""Test json schema generation."""
+
+import json
+from pathlib import Path
+
+from opentecr.data import CuratedMeasurement
+
+PROJECT_ROOT = Path(__file__).parent.parent.parent
+
+
+def test_json_schema() -> None:
+ """Check that json schema generation works as expected."""
+ result_path = PROJECT_ROOT / "output" / "openTECR.json"
+ with result_path.open("r") as f:
+ expected = json.load(f)
+ actual = CuratedMeasurement.model_json_schema()
+ assert expected == actual
diff --git a/tests/system/.keep b/tests/system/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/tests/unit/.keep b/tests/unit/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/tox.ini b/tox.ini
index f26eaa4..b83f4c4 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,6 +1,74 @@
-[isort]
-skip =
- __init__.py
-profile = black
-lines_after_imports = 2
-known_first_party = opentecr
+[tox]
+envlist = darglint, ruff, safety, mypy, docs, install, py3{11,12}
+isolated_build = true
+
+[gh-actions]
+python =
+ 3.11: install, safety, py310
+ 3.12: flake8, install, safety, mpypy, docs, py312
+
+[testenv]
+# Define base for all test environments.
+parallel_show_output = true
+
+[testenv:darglint]
+# Until darglint rules are integrated with ruff.
+skip_install = True
+deps=
+ darglint
+commands=
+ darglint {toxinidir}/src/opentecr {toxinidir}/tests
+
+[testenv:ruff]
+skip_install = True
+deps=
+ ruff
+commands=
+ ruff check {toxinidir}/src/opentecr {toxinidir}/tests
+
+[testenv:safety]
+deps=
+ safety
+commands=
+ safety check --full-report
+
+[testenv:mypy]
+skip_install = True
+deps=
+ mypy
+ pydantic
+commands=
+ mypy {toxinidir}/src/opentecr
+
+[testenv:docs]
+extras = dev
+commands=
+ mkdocs build --strict
+
+[testenv:install]
+skip_install = True
+deps=
+ hatch
+ twine
+commands=
+ pip check {toxinidir}
+ hatch build
+ twine check {toxinidir}/dist/*
+
+[testenv:py3{11,12}]
+deps =
+ pytest
+ pytest-cov
+ pytest-raises
+ pytest-xdist
+commands =
+ pytest --cov=opentecr --cov-report=term {posargs}
+
+################################################################################
+# Testing tools configuration #
+################################################################################
+
+[darglint]
+strictness = long
+# TODO: Can also choose 'numpy'
+docstring_style = google