├── .codespellrc ├── .github └── workflows │ └── codespell.yml ├── .gitignore ├── LICENSE ├── README.md ├── cookiecutter.json ├── hooks ├── post_gen_project.py └── pre_gen_project.py └── {{cookiecutter.project_name}} ├── .github └── workflows │ ├── deploy-docs.yaml │ ├── main.yaml │ ├── pypi-publish.yaml │ └── test_pages_build.yaml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── config.public.mk ├── config.yaml ├── examples └── README.md ├── justfile ├── licenses ├── Apache-2 ├── BSD-3 ├── GPL-3 ├── MIT └── MPL-2 ├── mkdocs.yml ├── project.Makefile ├── project.justfile ├── project ├── excel │ └── {{cookiecutter.__project_slug}}.xlsx ├── graphql │ └── {{cookiecutter.__project_slug}}.graphql ├── jsonld │ ├── {{cookiecutter.__project_slug}}.context.jsonld │ └── {{cookiecutter.__project_slug}}.jsonld ├── jsonschema │ └── {{cookiecutter.__project_slug}}.schema.json ├── owl │ └── {{cookiecutter.__project_slug}}.owl.ttl ├── prefixmap │ └── {{cookiecutter.__project_slug}}.yaml ├── protobuf │ └── {{cookiecutter.__project_slug}}.proto ├── shacl │ └── {{cookiecutter.__project_slug}}.shacl.ttl ├── shex │ └── {{cookiecutter.__project_slug}}.shex └── sqlschema │ └── {{cookiecutter.__project_slug}}.sql ├── pyproject.toml ├── src ├── data │ └── examples │ │ ├── invalid │ │ └── {{cookiecutter.main_schema_class}}-001.yaml │ │ └── valid │ │ └── {{cookiecutter.main_schema_class}}-001.yaml ├── docs │ ├── files │ │ └── about.md │ └── templates │ │ └── README.md └── {{cookiecutter.__project_slug}} │ ├── _version.py │ ├── datamodel │ ├── __init__.py │ └── {{cookiecutter.__project_slug}}.py │ └── schema │ └── {{cookiecutter.__project_slug}}.yaml ├── tablesort.js └── tests ├── __init__.py └── test_data.py /.codespellrc: -------------------------------------------------------------------------------- 1 | [codespell] 2 | skip = .git,*.pdf,*.svg 3 | # 4 | # ignore-words-list = 5 | -------------------------------------------------------------------------------- /.github/workflows/codespell.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Codespell 3 | 4 | on: 5 | push: 6 | branches: [main] 7 | pull_request: 8 | branches: [main] 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | codespell: 15 | name: Check for spelling errors 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v3 21 | - name: Codespell 22 | uses: codespell-project/actions-codespell@v2 23 | with: 24 | skip: '*.js' 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | .idea 132 | .vscode 133 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LinkML Project Cookiecutter 2 | 3 | A [Cookiecutter](https://cookiecutter.readthedocs.io/en/stable/) template for projects using [LinkML](https://github.com/linkml/linkml). 4 | 5 | ## Prerequisites 6 | 7 | The following are required and recommended tools for using this cookiecutter and the LinkML project that it generates. This is all one-time setup, so if you have already done it skip to the [next section](#creating-a-new-project)! 8 | 9 | * **Python >= 3.9** 10 | 11 | LinkML tools are mainly written in Python, so you will need a recent Python interpreter to run this generator and to use the generated project. 12 | 13 | * **pipx** 14 | 15 | pipx is a tool for managing isolated Python-based applications. It is the recommended way to install Poetry and cruft. To install pipx follow the instructions here: https://pypa.github.io/pipx/installation/ 16 | 17 | * **Poetry** 18 | 19 | Poetry is a Python project management tool. You will use it in your generated project to manage dependencies and build distribution files. The template requires poetry version 2.0 or newer. If you have pipx installed ([alternative installation methods](https://python-poetry.org/docs/#installation) are available) you can install Poetry by running: 20 | 21 | ```shell 22 | pipx install poetry 23 | ``` 24 | 25 | - For having both Poetry 2.x and Poetry 1.x installed at the same time, 26 | pipx has the option to install another version with a suffix-modified name, 27 | here "poetry1", 28 | 29 | ```bash 30 | `pipx install --suffix=1 "poetry<2.0"`. 31 | ``` 32 | 33 | This project manages project-level configuration. User-level [configuration](https://python-poetry.org/docs/configuration/), if needed, is your responsibility. 34 | 35 | * **Poetry private repository** 36 | 37 | Sandboxed environments have private pypi repositories. Poetry supports project-level [repository](https://python-poetry.org/docs/repositories/), but it is recommended to configure [this plugin](https://pypi.org/project/poetry-plugin-pypi-mirror) to persist repository across all poetry projects (and avoid cookiecutter failure): 38 | ```shell 39 | pip3 install poetry-plugin-pypi-mirror --user 40 | # example, add line to `~/.profile` for persistence 41 | export POETRY_PYPI_MIRROR_URL = "https://pypi-proxy.myorg.com/repository/pypi-all/simple" 42 | ``` 43 | 44 | * **Poetry Dynamic Versioning Plugin**: 45 | 46 | This plugin automatically updates certain version strings in your generated project when you publish it. Your generated project will automatically be set up to use it. Install it by running: 47 | ```shell 48 | poetry self add "poetry-dynamic-versioning[plugin]" 49 | ``` 50 | 51 | 52 | * **cruft** 53 | 54 | cruft is a tool for generating projects based on a cookiecutter (like this one!) as well as keeping those projects updated if the original cookiecutter changes. Install it with pipx by running: 55 | ```shell 56 | pipx install cruft 57 | ``` 58 | You may also choose to not have a persistent installation of cruft, in which case you would replace any calls to the `cruft` command below with `pipx run cruft`. 59 | 60 | 61 | * **make or just as command runner** 62 | 63 | The project contains a makefile but also a `justfile` with pre-defined complex commands. To execute these commands you either need `make` or [just](https://github.com/casey/just) as an alternative command runner. Especially for Windows users we suggest `just`. Install it by running: 64 | ```shell 65 | pipx install rust-just 66 | ``` 67 | 68 | ## Creating a new project 69 | 70 | ### Step 1: Generate the project files 71 | 72 | To generate a new LinkML project run the following: 73 | ```bash 74 | cruft create https://github.com/linkml/linkml-project-cookiecutter 75 | ``` 76 | Alternatively, to add linkml project files to pre-existing directory, 77 | (perhaps an existing non-linkml project), pass `-f` option: 78 | ```bash 79 | cruft create -f https://github.com/linkml/linkml-project-cookiecutter 80 | ``` 81 | 82 | You will be prompted for a few values. The defaults are fine for most 83 | projects, but do name your project something that makes sense to you! 84 | The interactive session will guide you through the process: 85 | 86 | 1. `project_name`: Name of the project, use kebab-case with no spaces. 87 | Suggestions: 88 | - `patient-observation-schema` 89 | - `sample-collection-metadata` 90 | - `resume-standard` 91 | 2. `github_org`: Your github username or organization name. This is used to construct links to documentation pages. 92 | 3. `project_description`: Description of the project. 93 | - A single brief sentence is recommended 94 | - Can easily be modified later 95 | 4. `full_name`: Your name 96 | 5. `email`: Your email 97 | 6. `license`: Choose a license for the project. If your desired license is not listed you can update or remove the `LICNSE` file in the generated project. 98 | 7. `main_schema_class`: 99 | - This is used to generate an example schema which you can edit 100 | - The value of this field is ignored if this is a schemasheets project 101 | - You can always change this later 102 | - Examples: `Person`, `Observation`, `Sample`, `Entry`, `Gene`, `Event` 103 | 8. `create_python_project` 104 | - If "Yes", set this up as a python project 105 | - Select Yes if you want to make data classes that can be used by developers 106 | 9. `use_schemasheets` 107 | - If "Yes", set this to obtain your schema from 108 | [schemasheets](https://linkml.io/schemasheets) 109 | 10. `google_sheet_id` 110 | - Ignore/use default value if answer to previous question was "No" 111 | - If you are using schemasheets then enter your google doc ID here 112 | - If you like you can leave the default value, and this will use the demo schema 113 | 11. `google_sheet_tabs` 114 | - Ignore/use default value if not using schemasheets 115 | - If you are using schemasheets, enter a space-separated list of tabs 116 | - your tabs in your sheet MUST NOT have spaces in them 117 | 12. `github_token_for_pypi_deployment`: 118 | - The github token name which aligns with your autogenerated PyPI token for making releases. 119 | - This helps automated releases to PyPI 120 | - This should be ignored if this is not a python project 121 | - Even if this is a python project, you can leave blank and fill in later 122 | 123 | ### Step 2: Set up the LinkML project 124 | 125 | Change to the folder your generated project is in. 126 | 127 | Optionally customize your project if needed: 128 | 129 | * pass arguments to linkml generators via 'config.yaml' configuration file; 130 | * pass supported environment variables via '.env.public' configuration file; 131 | 132 | Setup your project 133 | ```bash 134 | cd my-awesome-schema # using the folder example above 135 | make setup 136 | ``` 137 | 138 | ### Step 3: Edit the schema 139 | 140 | Edit the schema (the .yaml file) in the 141 | `src/my_awesome_schema/schema` folder 142 | 143 | ```bash 144 | nano src/my_awesome_schema/schema/my_awesome_schema.yaml 145 | ``` 146 | 147 | ### Step 4: Validate the schema 148 | 149 | ```bash 150 | make test 151 | ``` 152 | 153 | ### Step 5: Generate documentation locally 154 | 155 | LinkML generates schema documentation automatically. The template comes with GitHub Actions that generate and publish the documentation when you push schema changes to GitHub. The published documentation can be found at a URL like this one: 156 | `https://{github-user-or-organization}.github.io/{project-name}/` 157 | 158 | You can also preview the documentation locally before pushing to GitHub by running: 159 | 160 | ```bash 161 | make serve 162 | ``` 163 | 164 | ### Step 6: Create a GitHub project 165 | 166 | 1. Go to https://github.com/new and follow the instructions, being sure to NOT add a `README` or `.gitignore` file (this cookiecutter template will take care of those files for you) 167 | 168 | 2. Add the remote to your local git repository 169 | 170 | ```bash 171 | git remote add origin https://github.com/{github-user-or-organization}/{project-name}.git 172 | git branch -M main 173 | git push -u origin main 174 | ``` 175 | 176 | 3. Configure your repository for deploying the documentation as GitHub pages 177 | 178 | * Under Settings > Actions > General in section "Workflow Permissions" mark "Read repository and packages permission". 179 | * Under Pages in section "Build and Deployment": 180 | * Under "Source" select "Deploy from a branch" 181 | * Under "Branch" select "gh-pages" and "/ (root)" 182 | 183 | ### Step 7: Register the schema 184 | 185 | See [How to register a schema](https://linkml.io/linkml/faq/contributing.html#how-do-i-register-my-schema) 186 | 187 | ### Making releases 188 | 189 | See [How to Manage Releases of your LinkML Schema](https://linkml.io/linkml/howtos/manage-releases.html) 190 | 191 | ## Keeping your project up to date 192 | 193 | In order to be up-to-date with the template, first check if there is a mismatch 194 | between the project's boilerplate code and the template by running: 195 | 196 | ```bash 197 | cruft check 198 | ``` 199 | 200 | This indicates if there is a difference between the current project's 201 | boilerplate code and the latest version of the project template. If the project 202 | is up-to-date with the template: 203 | 204 | ```output 205 | SUCCESS: Good work! Project's cruft is up to date and as clean as possible :). 206 | ``` 207 | 208 | Otherwise, it will indicate that the project's boilerplate code is not 209 | up-to-date by the following: 210 | 211 | ```output 212 | FAILURE: Project's cruft is out of date! Run `cruft update` to clean this mess up. 213 | ``` 214 | 215 | For viewing the difference, run `cruft diff`. This shows the difference between the project's boilerplate code and the template's latest version. 216 | 217 | After running `cruft update`, the project's boilerplate code will be updated to the latest version of the template. 218 | -------------------------------------------------------------------------------- /cookiecutter.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_name": "my-awesome-schema", 3 | "__project_slug": "{{ cookiecutter.project_name|lower()|replace(' ', '_')|replace('-', '_') }}", 4 | "github_org": "my-org", 5 | "__source_path": "src/{{cookiecutter.__project_slug}}/schema/{{cookiecutter.__project_slug}}.yaml", 6 | "project_description": "This is the project description.", 7 | "full_name": "My Name", 8 | "email": "my-name@my-org.org", 9 | "__author": "{{cookiecutter.full_name}} <{{cookiecutter.email}}>", 10 | "license": ["MIT", "BSD-3", "GNU GPL v3.0", "Apache Software License 2.0"], 11 | "main_schema_class": "Person", 12 | "create_python_classes": ["Yes", "No"], 13 | "use_schemasheets": [ 14 | "No", 15 | "Yes" 16 | ], 17 | "google_sheet_id": "1wVoaiFg47aT9YWNeRfTZ8tYHN8s8PAuDx5i2HUcDpvQ", 18 | "google_sheet_tabs": "personinfo enums", 19 | "__google_sheet_module": "{{ cookiecutter.google_sheet_tabs|lower()|replace(' ', '_')|replace('-', '_') }}", 20 | "github_token_for_pypi_deployment": "PYPI_PASSWORD", 21 | "_copy_without_render": [ 22 | "justfile", 23 | "src/docs/js/*", 24 | "src/docs/javascript/*" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /hooks/post_gen_project.py: -------------------------------------------------------------------------------- 1 | """Code to run after generating the project.""" 2 | 3 | import shutil 4 | 5 | shutil.rmtree("licenses") 6 | 7 | project_slug = '{{ cookiecutter.__project_slug}}' 8 | create_python_classes = '{{ cookiecutter.create_python_classes }}' 9 | 10 | if create_python_classes == "No": 11 | print("TODO - cleanup python") 12 | 13 | print("** PROJECT CREATION COMPLETE **\n") 14 | print("Next steps:") 15 | print("cd {{cookiecutter.project_name}}") 16 | print("make setup") 17 | -------------------------------------------------------------------------------- /hooks/pre_gen_project.py: -------------------------------------------------------------------------------- 1 | """Code to run before generating the project.""" 2 | 3 | import re 4 | import sys 5 | 6 | MODULE_REGEX = re.compile(r'^[_a-zA-Z][_a-zA-Z0-9\-]+$') 7 | project_name = '{{ cookiecutter.project_name }}' 8 | 9 | if not MODULE_REGEX.match(project_name): 10 | if "-" in project_name: 11 | invalid_char = "-" 12 | elif " " in project_name: 13 | invalid_char = "" 14 | else: 15 | print( 16 | f'ERROR: {project_name} is not a valid Python module name. Try again with a valid project name.' 17 | ) 18 | # Exit to cancel project 19 | sys.exit(1) 20 | print( 21 | f'WARNING: {project_name} is not a valid Python module name. Using "_" instead of {invalid_char} for module name.' 22 | ) 23 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/.github/workflows/deploy-docs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Auto-deployment of {{cookiecutter.__project_slug}} Documentation 3 | on: 4 | push: 5 | branches: [main] 6 | 7 | jobs: 8 | build-docs: 9 | runs-on: ubuntu-latest 10 | 11 | # Grant GITHUB_TOKEN the permissions required to make a Pages deployment 12 | permissions: 13 | contents: write # to let mkdocs write the new docs 14 | pages: write # to deploy to Pages 15 | id-token: write # to verify the deployment originates from an appropriate source 16 | 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v4 20 | with: 21 | fetch-depth: 0 # otherwise, you will failed to push refs to dest repo 22 | 23 | - name: Set up Python. 24 | uses: actions/setup-python@v4 25 | with: 26 | python-version: 3.9 27 | 28 | - name: Install Poetry. 29 | run: pipx install poetry 30 | 31 | - name: Install dependencies. 32 | run: poetry install 33 | 34 | - name: Build documentation. 35 | run: | 36 | mkdir -p docs 37 | touch docs/.nojekyll 38 | make gendoc 39 | ([ ! -f docs/about.md ] && cp src/docs/about.md docs/) || true 40 | make mkd-gh-deploy 41 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/.github/workflows/main.yaml: -------------------------------------------------------------------------------- 1 | # Built from: 2 | # https://docs.github.com/en/actions/guides/building-and-testing-python 3 | --- 4 | name: Build and test {{cookiecutter.__project_slug}} 5 | 6 | on: [pull_request] 7 | 8 | jobs: 9 | test: 10 | 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | python-version: ["3.9", "3.10"] 15 | 16 | steps: 17 | 18 | - name: Check out repository 19 | uses: actions/checkout@v3 20 | 21 | - name: Set up Python 22 | uses: actions/setup-python@v4 23 | with: 24 | python-version: ${{ "{{" }} matrix.python-version {{ "}}" }} 25 | 26 | - name: Install Poetry 27 | run: pipx install poetry 28 | 29 | - name: Install dependencies 30 | run: poetry install --no-interaction --no-root 31 | 32 | - name: Install project 33 | run: poetry install --no-interaction 34 | 35 | - name: Run test suite 36 | run: make test 37 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/.github/workflows/pypi-publish.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Publish Python Package 3 | 4 | on: 5 | release: 6 | types: [created] 7 | 8 | jobs: 9 | build-n-publish: 10 | name: Build and publish Python 🐍 distributions 📦 to PyPI 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v3 15 | 16 | - name: Set up Python 17 | uses: actions/setup-python@v4 18 | with: 19 | python-version: 3.9 20 | 21 | - name: Install Poetry 22 | run: | 23 | pipx install poetry 24 | poetry self add "poetry-dynamic-versioning[plugin]" 25 | 26 | # - name: Install dependencies 27 | # run: poetry install --no-interaction 28 | 29 | - name: Build source and wheel archives 30 | run: poetry build 31 | 32 | - name: Publish distribution 📦 to PyPI 33 | uses: pypa/gh-action-pypi-publish@v1.2.2 34 | with: 35 | user: __token__ 36 | password: ${{ "{{" }} secrets.{{cookiecutter.github_token_for_pypi_deployment}} {{ "}}" }} 37 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/.github/workflows/test_pages_build.yaml: -------------------------------------------------------------------------------- 1 | name: Preview {{cookiecutter.__project_slug}} documentation build 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - reopened 8 | - synchronize 9 | 10 | concurrency: {% raw %}preview-${{ github.ref }}{% endraw %} 11 | 12 | jobs: 13 | run: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | 21 | - name: Set up Python 3 22 | uses: actions/setup-python@v4 23 | with: 24 | python-version: 3.9 25 | 26 | - name: Install Poetry 27 | run: pipx install poetry 28 | 29 | - name: Install dependencies 30 | run: poetry install 31 | 32 | - name: Build documentation 33 | run: | 34 | mkdir -p site 35 | touch site/.nojekyll 36 | make gendoc 37 | ([ ! -f docs/about.md ] && cp src/docs/about.md docs/) || true 38 | poetry run mkdocs build -d site 39 | 40 | - name: Deploy preview 41 | uses: rossjrw/pr-preview-action@v1 42 | with: 43 | source-dir: site/ 44 | preview-branch: gh-pages 45 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/.gitignore: -------------------------------------------------------------------------------- 1 | /docs/ 2 | /project/docs/ 3 | /tmp/ 4 | # PyCharm files 5 | .idea/ 6 | # Byte-compiled / optimized / DLL files 7 | __pycache__/ 8 | *.py[cod] 9 | *$py.class 10 | 11 | # C extensions 12 | *.so 13 | 14 | # Distribution / packaging 15 | .Python 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | downloads/ 20 | eggs/ 21 | .eggs/ 22 | lib/ 23 | lib64/ 24 | parts/ 25 | sdist/ 26 | var/ 27 | wheels/ 28 | pip-wheel-metadata/ 29 | share/python-wheels/ 30 | *.egg-info/ 31 | .installed.cfg 32 | *.egg 33 | MANIFEST 34 | 35 | # PyInstaller 36 | # Usually these files are written by a python script from a template 37 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 38 | *.manifest 39 | *.spec 40 | 41 | # Installer logs 42 | pip-log.txt 43 | pip-delete-this-directory.txt 44 | 45 | # Unit test / coverage reports 46 | htmlcov/ 47 | .tox/ 48 | .nox/ 49 | .coverage 50 | .coverage.* 51 | .cache 52 | nosetests.xml 53 | coverage.xml 54 | *.cover 55 | *.py,cover 56 | .hypothesis/ 57 | .pytest_cache/ 58 | 59 | # Translations 60 | *.mo 61 | *.pot 62 | 63 | # Django stuff: 64 | *.log 65 | local_settings.py 66 | db.sqlite3 67 | db.sqlite3-journal 68 | 69 | # Flask stuff: 70 | instance/ 71 | .webassets-cache 72 | 73 | # Scrapy stuff: 74 | .scrapy 75 | 76 | # Sphinx documentation 77 | docs/_build/ 78 | 79 | # PyBuilder 80 | target/ 81 | 82 | # Jupyter Notebook 83 | .ipynb_checkpoints 84 | 85 | # IPython 86 | profile_default/ 87 | ipython_config.py 88 | 89 | # pyenv 90 | .python-version 91 | 92 | # pipenv 93 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 94 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 95 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 96 | # install all needed dependencies. 97 | #Pipfile.lock 98 | 99 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 100 | __pypackages__/ 101 | 102 | # Celery stuff 103 | celerybeat-schedule 104 | celerybeat.pid 105 | 106 | # SageMath parsed files 107 | *.sage.py 108 | 109 | # Environments 110 | .env 111 | .venv 112 | env/ 113 | venv/ 114 | ENV/ 115 | env.bak/ 116 | venv.bak/ 117 | 118 | # Spyder project settings 119 | .spyderproject 120 | .spyproject 121 | 122 | # Rope project settings 123 | .ropeproject 124 | 125 | # mkdocs documentation 126 | /site 127 | 128 | # mypy 129 | .mypy_cache/ 130 | .dmypy.json 131 | dmypy.json 132 | 133 | # Pyre type checker 134 | .pyre/ 135 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to make participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, 8 | body size, disability, ethnicity, gender identity and expression, level of 9 | experience, nationality, personal appearance, race, religion, or sexual 10 | identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an 52 | appointed representative at an online or offline event. Representation of a 53 | project may be further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by [contacting the project team](contact.md). All complaints will be 59 | reviewed and investigated and will result in a response that is deemed 60 | necessary and appropriate to the circumstances. The project team is obligated 61 | to maintain confidentiality with regard to the reporter of an incident. Further 62 | details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This code of conduct has been derived from the excellent code of conduct of the 71 | [ATOM project](https://github.com/atom/atom/blob/master/CODE_OF_CONDUCT.md) 72 | which in turn is adapted from the [Contributor Covenant][homepage], version 73 | 1.4, available at [https://contributor-covenant.org/version/1/4][version] 74 | 75 | [homepage]: https://contributor-covenant.org 76 | [version]: https://contributor-covenant.org/version/1/4/ 77 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to {{cookiecutter.project_name}} 2 | 3 | :+1: First of all: Thank you for taking the time to contribute! 4 | 5 | The following is a set of guidelines for contributing to 6 | {{ cookiecutter.project_name }}. These guidelines are not strict rules. 7 | Use your best judgment, and feel free to propose changes to this document 8 | in a pull request. 9 | 10 | ## Table Of Contents 11 | 12 | * [Code of Conduct](#code-of-conduct) 13 | * [Guidelines for Contributions and Requests](#contributions) 14 | * [Reporting issues and making requests](#reporting-issues) 15 | * [Questions and Discussion](#questions-and-discussion) 16 | * [Adding new elements yourself](#adding-elements) 17 | * [Best Practices](#best-practices) 18 | * [How to write a great issue](#great-issues) 19 | * [How to create a great pull/merge request](#great-pulls) 20 | 21 | 22 | 23 | ## Code of Conduct 24 | 25 | The {{cookiecutter.project_name}} team strives to create a 26 | welcoming environment for editors, users and other contributors. 27 | Please carefully read our [Code of Conduct](CODE_OF_CONDUCT.md). 28 | 29 | 30 | 31 | ## Guidelines for Contributions and Requests 32 | 33 | 34 | 35 | ### Reporting problems and suggesting changes to with the data model 36 | 37 | Please use our [Issue Tracker][issues] for any of the following: 38 | 39 | - Reporting problems 40 | - Requesting new schema elements 41 | 42 | 43 | 44 | ### Questions and Discussions 45 | 46 | Please use our [Discussions forum][discussions] to ask general questions or contribute to discussions. 47 | 48 | 49 | 50 | ### Adding new elements yourself 51 | 52 | Please submit a [Pull Request][pulls] to submit a new term for consideration. 53 | 54 | 55 | 56 | ## Best Practices 57 | 58 | 59 | 60 | ### GitHub Best Practice 61 | 62 | - Creating and curating issues 63 | - Read ["About Issues"][[about-issues]] 64 | - Issues should be focused and actionable 65 | - Complex issues should be broken down into simpler issues where possible 66 | - Pull Requests 67 | - Read ["About Pull Requests"][about-pulls] 68 | - Read [GitHub Pull Requests: 10 Tips to Know](https://blog.mergify.com/github-pull-requests-10-tips-to-know/) 69 | - Pull Requests (PRs) should be atomic and aim to close a single issue 70 | - Long running PRs should be avoided where possible 71 | - PRs should reference issues following standard conventions (e.g. “fixes #123”) 72 | - Schema developers should always be working on a single issue at any one time 73 | - Never work on the main branch, always work on an issue/feature branch 74 | - Core developers can work on branches off origin rather than forks 75 | - Always create a PR on a branch to maximize transparency of what you are doing 76 | - PRs should be reviewed and merged in a timely fashion by the {{cookiecutter.project_name}} technical leads 77 | - PRs that do not pass GitHub actions should never be merged 78 | - In the case of git conflicts, the contributor should try and resolve the conflict 79 | - If a PR fails a GitHub action check, the contributor should try and resolve the issue in a timely fashion 80 | 81 | ### Understanding LinkML 82 | 83 | Core developers should read the material on the [LinkML site](https://linkml.io/linkml), in particular: 84 | 85 | - [Overview](https://linkml.io/linkml/intro/overview.html) 86 | - [Tutorial](https://linkml.io/linkml/intro/tutorial.html) 87 | - [Schemas](https://linkml.io/linkml/schemas/index.html) 88 | - [FAQ](https://linkml.io/linkml/faq/index.html) 89 | 90 | ### Modeling Best Practice 91 | 92 | - Follow Naming conventions 93 | - Standard LinkML naming conventions should be followed (UpperCamelCase for classes and enums, snake_case for slots) 94 | - Know how to use the LinkML linter to check style and conventions 95 | - The names for classes should be nouns or noun-phrases: Person, GenomeAnnotation, Address, Sample 96 | - Spell out abbreviations and short forms, except where this goes against convention (e.g. do not spell out DNA) 97 | - Elements that are imported from outside (e.g. schema.org) need not follow the same naming conventions 98 | - Multivalued slots should be named as plurals 99 | - Document model elements 100 | - All model elements should have documentation (descriptions) and other textual annotations (e.g. comments, notes) 101 | - Textual annotations on classes, slots and enumerations should be written with minimal jargon, clear grammar and no misspellings 102 | - Include examples and counter-examples (intentionally invalid examples) 103 | - Rationale: these serve as documentation and unit tests 104 | - These will be used by the automated test suite 105 | - All elements of the nmdc-schema must be illustrated with valid and invalid data examples in src/data. New schema elements will not be merged into the main branch until examples are provided 106 | - Invalid example data files should be invalid for one single reason, which should be reflected in the filename. It should be possible to render the invalid example files valid by addressing that single fault. 107 | - Use enums for categorical values 108 | - Rationale: Open-ended string ranges encourage multiple values to represent the same entity, like “water”, “H2O” and “HOH” 109 | - Any slot whose values could be constrained to a finite set should use an Enum 110 | - Non-categorical values, e.g. descriptive fields like `name` or `description` fall outside of this. 111 | - Reuse 112 | - Existing scheme elements should be reused where appropriate, rather than making duplicative elements 113 | - More specific classes can be created by refinining classes using inheritance (`is_a`) 114 | 115 | [about-branches]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-branches 116 | [about-issues]: https://docs.github.com/en/issues/tracking-your-work-with-issues/about-issues 117 | [about-pulls]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests 118 | [issues]: https://github.com/{{ cookiecutter.github_org }}/{{ cookiecutter.project_name }}/issues/ 119 | [pulls]: https://github.com/{{ cookiecutter.github_org }}/{{ cookiecutter.project_name }}/pulls/ 120 | 121 | We recommend also reading [GitHub Pull Requests: 10 Tips to Know](https://blog.mergify.com/github-pull-requests-10-tips-to-know/) 122 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/LICENSE: -------------------------------------------------------------------------------- 1 | {%- if cookiecutter.license == "MIT" -%} 2 | {%- include 'licenses/MIT' %} 3 | {%- elif cookiecutter.license == "BSD-3" -%} 4 | {%- include 'licenses/BSD-3' %} 5 | {%- elif cookiecutter.license == "GNU GPL v3.0" -%} 6 | {%- include 'licenses/GPL-3' %} 7 | {%- elif cookiecutter.license == "Apache Software License 2.0" -%} 8 | {%- include 'licenses/Apache-2' %} 9 | {%- elif cookiecutter.license == "Mozilla Public License 2.0" -%} 10 | {%- include 'licenses/MPL-2' %} 11 | {%- endif -%} 12 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/Makefile: -------------------------------------------------------------------------------- 1 | MAKEFLAGS += --warn-undefined-variables 2 | SHELL := bash 3 | .SHELLFLAGS := -eu -o pipefail -c 4 | .DEFAULT_GOAL := help 5 | .DELETE_ON_ERROR: 6 | .SUFFIXES: 7 | .SECONDARY: 8 | 9 | # environment variables 10 | .EXPORT_ALL_VARIABLES: 11 | ifdef LINKML_ENVIRONMENT_FILENAME 12 | include ${LINKML_ENVIRONMENT_FILENAME} 13 | else 14 | include config.public.mk 15 | endif 16 | 17 | RUN = poetry run 18 | SCHEMA_NAME = $(LINKML_SCHEMA_NAME) 19 | SOURCE_SCHEMA_PATH = $(LINKML_SCHEMA_SOURCE_PATH) 20 | SOURCE_SCHEMA_DIR = $(dir $(SOURCE_SCHEMA_PATH)) 21 | SRC = src 22 | DEST = project 23 | PYMODEL = $(SRC)/$(SCHEMA_NAME)/datamodel 24 | DOCDIR = docs 25 | DOCTEMPLATES = $(SRC)/docs/templates 26 | EXAMPLEDIR = examples 27 | SHEET_MODULE = $(LINKML_SCHEMA_GOOGLE_SHEET_MODULE) 28 | SHEET_ID = $(LINKML_SCHEMA_GOOGLE_SHEET_ID) 29 | SHEET_TABS = $(LINKML_SCHEMA_GOOGLE_SHEET_TABS) 30 | SHEET_MODULE_PATH = $(SOURCE_SCHEMA_DIR)/$(SHEET_MODULE).yaml 31 | 32 | # Use += to append variables from the variables file 33 | CONFIG_YAML = 34 | ifdef LINKML_GENERATORS_CONFIG_YAML 35 | CONFIG_YAML += "--config-file" 36 | CONFIG_YAML += ${LINKML_GENERATORS_CONFIG_YAML} 37 | endif 38 | 39 | GEN_DOC_ARGS = 40 | ifdef LINKML_GENERATORS_DOC_ARGS 41 | GEN_DOC_ARGS += ${LINKML_GENERATORS_DOC_ARGS} 42 | endif 43 | 44 | GEN_OWL_ARGS = 45 | ifdef LINKML_GENERATORS_OWL_ARGS 46 | GEN_OWL_ARGS += ${LINKML_GENERATORS_OWL_ARGS} 47 | endif 48 | 49 | GEN_JAVA_ARGS = 50 | ifdef LINKML_GENERATORS_JAVA_ARGS 51 | GEN_JAVA_ARGS += ${LINKML_GENERATORS_JAVA_ARGS} 52 | endif 53 | 54 | GEN_TS_ARGS = 55 | ifdef LINKML_GENERATORS_TYPESCRIPT_ARGS 56 | GEN_TS_ARGS += ${LINKML_GENERATORS_TYPESCRIPT_ARGS} 57 | endif 58 | 59 | 60 | # basename of a YAML file in model/ 61 | .PHONY: all clean setup gen-project gen-examples gendoc git-init-add git-init git-add git-commit git-status 62 | 63 | # note: "help" MUST be the first target in the file, 64 | # when the user types "make" they should get help info 65 | help: status 66 | @echo "" 67 | @echo "make setup -- initial setup (run this first)" 68 | @echo "make site -- makes site locally" 69 | @echo "make install -- install dependencies" 70 | @echo "make test -- runs tests" 71 | @echo "make lint -- perform linting" 72 | @echo "make testdoc -- builds docs and runs local test server" 73 | @echo "make deploy -- deploys site" 74 | @echo "make update -- updates linkml version" 75 | @echo "make help -- show this help" 76 | @echo "" 77 | 78 | status: check-config 79 | @echo "Project: $(SCHEMA_NAME)" 80 | @echo "Source: $(SOURCE_SCHEMA_PATH)" 81 | 82 | # generate products and add everything to github 83 | setup: check-config git-init install gen-project gen-examples gendoc git-add git-commit 84 | 85 | # install any dependencies required for building 86 | install: 87 | poetry install 88 | .PHONY: install 89 | 90 | # --- 91 | # Project Synchronization 92 | # --- 93 | # 94 | # check we are up to date 95 | check: cruft-check 96 | cruft-check: 97 | cruft check 98 | cruft-diff: 99 | cruft diff 100 | 101 | update: update-template update-linkml 102 | update-template: 103 | cruft update 104 | 105 | # todo: consider pinning to template 106 | update-linkml: 107 | poetry add -D linkml@latest 108 | 109 | # EXPERIMENTAL 110 | create-data-harmonizer: 111 | npm init data-harmonizer $(SOURCE_SCHEMA_PATH) 112 | 113 | all: site 114 | site: gen-project gendoc 115 | %.yaml: gen-project 116 | deploy: all mkd-gh-deploy 117 | 118 | compile-sheets: 119 | $(RUN) sheets2linkml --gsheet-id $(SHEET_ID) $(SHEET_TABS) > $(SHEET_MODULE_PATH).tmp && mv $(SHEET_MODULE_PATH).tmp $(SHEET_MODULE_PATH) 120 | 121 | # In future this will be done by conversion 122 | gen-examples: 123 | cp -r src/data/examples/* $(EXAMPLEDIR) 124 | 125 | # generates all project files 126 | {% if cookiecutter.use_schemasheets == "Yes" %} 127 | gen-project: $(PYMODEL) compile-sheets 128 | $(RUN) gen-project ${CONFIG_YAML} -d $(DEST) $(SOURCE_SCHEMA_PATH) && mv $(DEST)/*.py $(PYMODEL) 129 | {% else %} 130 | gen-project: $(PYMODEL) 131 | $(RUN) gen-project ${CONFIG_YAML} -d $(DEST) $(SOURCE_SCHEMA_PATH) && mv $(DEST)/*.py $(PYMODEL) 132 | {% endif %} 133 | 134 | # non-empty arg triggers owl (workaround https://github.com/linkml/linkml/issues/1453) 135 | ifneq ($(strip ${GEN_OWL_ARGS}),) 136 | mkdir -p ${DEST}/owl || true 137 | $(RUN) gen-owl ${GEN_OWL_ARGS} $(SOURCE_SCHEMA_PATH) >${DEST}/owl/${SCHEMA_NAME}.owl.ttl 138 | endif 139 | # non-empty arg triggers java 140 | ifneq ($(strip ${GEN_JAVA_ARGS}),) 141 | $(RUN) gen-java ${GEN_JAVA_ARGS} --output-directory ${DEST}/java/ $(SOURCE_SCHEMA_PATH) 142 | endif 143 | # non-empty arg triggers typescript 144 | ifneq ($(strip ${GEN_TS_ARGS}),) 145 | mkdir -p ${DEST}/typescript || true 146 | $(RUN) gen-typescript ${GEN_TS_ARGS} $(SOURCE_SCHEMA_PATH) >${DEST}/typescript/${SCHEMA_NAME}.ts 147 | endif 148 | 149 | test: test-schema test-python test-examples 150 | 151 | test-schema: 152 | $(RUN) gen-project ${CONFIG_YAML} -d tmp $(SOURCE_SCHEMA_PATH) 153 | 154 | test-python: 155 | $(RUN) python -m pytest 156 | 157 | lint: 158 | $(RUN) linkml-lint $(SOURCE_SCHEMA_PATH) 159 | 160 | check-config: 161 | ifndef LINKML_SCHEMA_NAME 162 | $(error **Project not configured**:\n\n - See '.env.public'\n\n) 163 | else 164 | $(info Ok) 165 | endif 166 | 167 | convert-examples-to-%: 168 | $(patsubst %, $(RUN) linkml-convert % -s $(SOURCE_SCHEMA_PATH) -C Person, $(shell ${SHELL} find src/data/examples -name "*.yaml")) 169 | 170 | examples/%.yaml: src/data/examples/%.yaml 171 | $(RUN) linkml-convert -s $(SOURCE_SCHEMA_PATH) -C Person $< -o $@ 172 | examples/%.json: src/data/examples/%.yaml 173 | $(RUN) linkml-convert -s $(SOURCE_SCHEMA_PATH) -C Person $< -o $@ 174 | examples/%.ttl: src/data/examples/%.yaml 175 | $(RUN) linkml-convert -P EXAMPLE=http://example.org/ -s $(SOURCE_SCHEMA_PATH) -C Person $< -o $@ 176 | 177 | test-examples: examples/output 178 | 179 | examples/output: src/$(SCHEMA_NAME)/schema/$(SCHEMA_NAME).yaml 180 | mkdir -p $@ 181 | $(RUN) linkml-run-examples \ 182 | --output-formats json \ 183 | --output-formats yaml \ 184 | --counter-example-input-directory src/data/examples/invalid \ 185 | --input-directory src/data/examples/valid \ 186 | --output-directory $@ \ 187 | --schema $< > $@/README.md 188 | 189 | # Test documentation locally 190 | serve: mkd-serve 191 | 192 | # Python datamodel 193 | $(PYMODEL): 194 | mkdir -p $@ 195 | 196 | 197 | $(DOCDIR): 198 | mkdir -p $@ 199 | 200 | gendoc: $(DOCDIR) 201 | cp -rf $(SRC)/docs/files/* $(DOCDIR) ; \ 202 | $(RUN) gen-doc ${GEN_DOC_ARGS} -d $(DOCDIR) $(SOURCE_SCHEMA_PATH) 203 | 204 | testdoc: gendoc serve 205 | 206 | MKDOCS = $(RUN) mkdocs 207 | mkd-%: 208 | $(MKDOCS) $* 209 | 210 | git-init-add: git-init git-add git-commit git-status 211 | git-init: 212 | git init 213 | git-add: .cruft.json 214 | git add . 215 | git-commit: 216 | git commit -m 'chore: make setup was run' -a 217 | git-status: 218 | git status 219 | 220 | # only necessary if setting up via cookiecutter 221 | .cruft.json: 222 | echo "creating a stub for .cruft.json. IMPORTANT: setup via cruft not cookiecutter recommended!" ; \ 223 | touch $@ 224 | 225 | clean: 226 | rm -rf $(DEST) 227 | rm -rf tmp 228 | rm -fr $(DOCDIR)/* 229 | rm -fr $(PYMODEL)/* 230 | 231 | include project.Makefile 232 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/README.md: -------------------------------------------------------------------------------- 1 | # {{cookiecutter.project_name}} 2 | 3 | {{cookiecutter.project_description}} 4 | 5 | ## Website 6 | 7 | [https://{{cookiecutter.github_org}}.github.io/{{cookiecutter.project_name}}](https://{{cookiecutter.github_org}}.github.io/{{cookiecutter.project_name}}) 8 | 9 | ## Repository Structure 10 | 11 | * [examples/](examples/) - example data 12 | * [project/](project/) - project files (do not edit these) 13 | * [src/](src/) - source files (edit these) 14 | * [{{cookiecutter.__project_slug}}](src/{{cookiecutter.__project_slug}}) 15 | * [schema](src/{{cookiecutter.__project_slug}}/schema) -- LinkML schema 16 | (edit this) 17 | {%- if cookiecutter.create_python_classes == "Yes" %} 18 | * [datamodel](src/{{cookiecutter.__project_slug}}/datamodel) -- generated 19 | Python datamodel 20 | * [tests/](tests/) - Python tests 21 | {%- endif %} 22 | 23 | ## Developer Documentation 24 | 25 |
26 | To run commands you may use good old make or the command runner [just](https://github.com/casey/just/) which is a better choice on Windows. 27 | Use the `make` command or `duty` commands to generate project artefacts: 28 | * `make help` or `just --list`: list all pre-defined tasks 29 | * `make all` or `just all`: make everything 30 | * `make deploy` or `just deploy`: deploys site 31 |
32 | 33 | ## Credits 34 | 35 | This project was made with 36 | [linkml-project-cookiecutter](https://github.com/linkml/linkml-project-cookiecutter). 37 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/config.public.mk: -------------------------------------------------------------------------------- 1 | # config.public.mk 2 | 3 | # This file is public in git. No sensitive info allowed. 4 | # These variables are sourced in Makefile, following make-file conventions. 5 | # Be aware that this file does not follow python or bash conventions, so may appear a little unfamiliar. 6 | 7 | ###### schema definition variables, used by makefile 8 | 9 | # Note: makefile variables should not be quoted, as makefile handles quoting differently than bash 10 | LINKML_SCHEMA_NAME="{{cookiecutter.__project_slug}}" 11 | LINKML_SCHEMA_AUTHOR="{{cookiecutter.__author}}" 12 | LINKML_SCHEMA_DESCRIPTION="{{cookiecutter.project_description}}" 13 | LINKML_SCHEMA_SOURCE_PATH="{{cookiecutter.__source_path}}" 14 | LINKML_SCHEMA_GOOGLE_SHEET_MODULE="{{cookiecutter.__google_sheet_module}}" 15 | LINKML_SCHEMA_GOOGLE_SHEET_ID="{{cookiecutter.google_sheet_id}}" 16 | LINKML_SCHEMA_GOOGLE_SHEET_TABS="{{cookiecutter.google_sheet_tabs}}" 17 | LINKML_USE_SCHEMASHEETS={{cookiecutter.use_schemasheets}} 18 | 19 | ###### linkml generator variables, used by makefile 20 | 21 | ## gen-project configuration file 22 | LINKML_GENERATORS_CONFIG_YAML=config.yaml 23 | 24 | ## pass args if gendoc ignores config.yaml (i.e. --no-mergeimports) 25 | LINKML_GENERATORS_DOC_ARGS= 26 | 27 | ## pass args to workaround genowl rdfs config bug (linkml#1453) 28 | ## (i.e. --no-type-objects --no-metaclasses --metadata-profile rdfs) 29 | LINKML_GENERATORS_OWL_ARGS= 30 | 31 | ## pass args to trigger experimental java/typescript generation 32 | LINKML_GENERATORS_JAVA_ARGS= 33 | LINKML_GENERATORS_TYPESCRIPT_ARGS= 34 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/config.yaml: -------------------------------------------------------------------------------- 1 | # Configuration of generators (defaults illustrated) 2 | --- 3 | generator_args: 4 | excel: 5 | mergeimports: true 6 | owl: 7 | mergeimports: true 8 | metaclasses: true 9 | type_objects: true 10 | # throws 'Cannot handle metadata profile: rdfs' 11 | # metadata_profile: rdfs 12 | markdown: 13 | mergeimports: true 14 | graphql: 15 | mergeimports: true 16 | java: 17 | mergeimports: true 18 | metadata: true 19 | jsonld: 20 | mergeimports: true 21 | jsonschema: 22 | mergeimports: true 23 | jsonldcontext: 24 | mergeimports: true 25 | python: 26 | mergeimports: true 27 | prefixmap: 28 | mergeimports: true 29 | proto: 30 | mergeimports: true 31 | shacl: 32 | mergeimports: true 33 | shex: 34 | mergeimports: true 35 | sqlddl: 36 | mergeimports: true 37 | typescript: 38 | mergeimports: true 39 | metadata: true 40 | 41 | ... 42 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples of use of {{cookiecutter.__project_slug}} 2 | 3 | This folder contains example data conforming to {{cookiecutter.__project_slug}} 4 | 5 | The source for these is in [src/data](../src/data/examples) 6 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/justfile: -------------------------------------------------------------------------------- 1 | # On Windows the bash shell that comes with Git for Windows should be used. 2 | # If it is not on path, give the path to the executable in the following line. 3 | #set windows-shell := ["C:/Program Files/Git/usr/bin/sh", "-cu"] 4 | 5 | # Load environment variables from config.public.mk or specified file 6 | set dotenv-load := true 7 | # set dotenv-filename := env_var_or_default("LINKML_ENVIRONMENT_FILENAME", "config.public.mk") 8 | set dotenv-filename := x'${LINKML_ENVIRONMENT_FILENAME:-config.public.mk}' 9 | 10 | 11 | # List all commands as default command. The prefix "_" hides the command. 12 | _default: _status 13 | @just --list 14 | 15 | # Set cross-platform Python shebang line (assumes presence of launcher on Windows) 16 | shebang := if os() == 'windows' { 17 | 'py' 18 | } else { 19 | '/usr/bin/env python3' 20 | } 21 | 22 | # Environment variables with defaults 23 | schema_name := env_var_or_default("LINKML_SCHEMA_NAME", "") 24 | source_schema_path := env_var_or_default("LINKML_SCHEMA_SOURCE_PATH", "") 25 | 26 | use_schemasheets := env_var_or_default("LINKML_USE_SCHEMASHEETS", "No") 27 | sheet_module := env_var_or_default("LINKML_SCHEMA_GOOGLE_SHEET_MODULE", "") 28 | sheet_ID := env_var_or_default("LINKML_SCHEMA_GOOGLE_SHEET_ID", "") 29 | sheet_tabs := env_var_or_default("LINKML_SCHEMA_GOOGLE_SHEET_TABS", "") 30 | sheet_module_path := source_schema_path / sheet_module + ".yaml" 31 | 32 | config_yaml := if env_var_or_default("LINKML_GENERATORS_CONFIG_YAML", "") != "" { 33 | "--config-file " + env_var_or_default("LINKML_GENERATORS_CONFIG_YAML", "") 34 | } else { 35 | "" 36 | } 37 | gen_doc_args := env_var_or_default("LINKML_GENERATORS_DOC_ARGS", "") 38 | gen_owl_args := env_var_or_default("LINKML_GENERATORS_OWL_ARGS", "") 39 | gen_java_args := env_var_or_default("LINKML_GENERATORS_JAVA_ARGS", "") 40 | gen_ts_args := env_var_or_default("LINKML_GENERATORS_TYPESCRIPT_ARGS", "") 41 | 42 | # Directory variables 43 | src := "src" 44 | dest := "project" 45 | pymodel := src / schema_name / "datamodel" 46 | docdir := "docs" 47 | exampledir := "examples" 48 | 49 | # Show current project status 50 | _status: _check-config 51 | @echo "Project: {{schema_name}}" 52 | @echo "Source: {{source_schema_path}}" 53 | 54 | # Run initial setup (run this first) 55 | setup: _check-config _git-init install _gen-project _gen-examples _gendoc _git-add _git-commit 56 | 57 | # Install project dependencies 58 | install: 59 | poetry install 60 | 61 | # Check project configuration 62 | _check-config: 63 | #!{{shebang}} 64 | import os 65 | schema_name = os.getenv('LINKML_SCHEMA_NAME') 66 | if not schema_name: 67 | print('**Project not configured**:\n - See \'.env.public\'') 68 | exit(1) 69 | print('Project-status: Ok') 70 | 71 | # Updates project template and LinkML package 72 | update: _update-template _update-linkml 73 | 74 | # Update project template 75 | _update-template: 76 | cruft update 77 | 78 | # Update LinkML to latest version 79 | _update-linkml: 80 | poetry add -D linkml@latest 81 | 82 | # Create data harmonizer 83 | _create-data-harmonizer: 84 | npm init data-harmonizer {{source_schema_path}} 85 | 86 | # Generate all project files 87 | alias all := site 88 | 89 | # Generate site locally 90 | site: _gen-project _gendoc 91 | 92 | # Deploy site 93 | deploy: site 94 | mkd-gh-deploy 95 | 96 | _compile_sheets: 97 | @if [ "{{use_schemasheets}}" != "No" ]; then \ 98 | poetry run sheets2linkml --gsheet-id {{sheet_ID}} {{sheet_tabs}} > {{sheet_module_path}}.tmp && \ 99 | mv {{sheet_module_path}}.tmp {{sheet_module_path}}; \ 100 | fi 101 | 102 | # Generate examples 103 | _gen-examples: 104 | mkdir -p {{exampledir}} 105 | cp -r src/data/examples/* {{exampledir}} 106 | 107 | # Generate project files 108 | _gen-project: _ensure_pymodel_dir _compile_sheets 109 | poetry run gen-project {{config_yaml}} -d {{dest}} {{source_schema_path}} && \ 110 | mv {{dest}}/*.py {{pymodel}} 111 | @if [ ! -z "${{gen_owl_args}}" ]; then \ 112 | mkdir -p {{dest}}/owl || true && \ 113 | poetry run gen-owl {{gen_owl_args}} {{source_schema_path}} > {{dest}}/owl/{{schema_name}}.owl.ttl || true ; \ 114 | fi 115 | @if [ ! ${{gen_java_args}} ]; then \ 116 | poetry run gen-java {{gen_java_args}} --output-directory {{dest}}/java/ {{source_schema_path}} || true ; \ 117 | fi 118 | @if [ ! ${{gen_ts_args}} ]; then \ 119 | poetry run gen-typescript {{gen_ts_args}} {{source_schema_path}} > {{dest}}/typescript/{{schema_name}}.ts || true ; \ 120 | fi 121 | 122 | # Run all tests 123 | test: _test-schema _test-python _test-examples 124 | 125 | # Test schema generation 126 | _test-schema: 127 | poetry run gen-project {{config_yaml}} -d tmp {{source_schema_path}} 128 | 129 | # Run Python unit tests with pytest 130 | _test-python: 131 | poetry run python -m pytest 132 | 133 | # Run example tests 134 | _test-examples: _ensure_examples_output 135 | poetry run linkml-run-examples \ 136 | --output-formats json \ 137 | --output-formats yaml \ 138 | --counter-example-input-directory src/data/examples/invalid \ 139 | --input-directory src/data/examples/valid \ 140 | --output-directory examples/output \ 141 | --schema {{source_schema_path}} > examples/output/README.md 142 | 143 | # Run linting 144 | lint: 145 | poetry run linkml-lint {{source_schema_path}} 146 | 147 | # Generate documentation 148 | _gendoc: _ensure_docdir 149 | cp -r {{src}}/docs/files/* {{docdir}} 150 | poetry run gen-doc {{gen_doc_args}} -d {{docdir}} {{source_schema_path}} 151 | 152 | # Build docs and run test server 153 | testdoc: _gendoc _serve 154 | 155 | # Run documentation server 156 | _serve: 157 | poetry run mkdocs serve 158 | 159 | # Initialize and add everything to git 160 | _git-init-add: _git-init _git-add _git-commit _git-status 161 | 162 | # Initialize git repository 163 | _git-init: 164 | git init 165 | 166 | # Add files to git 167 | _git-add: 168 | touch .cruft.json 169 | git add . 170 | 171 | # Commit files to git 172 | _git-commit: 173 | git commit -m 'chore: make setup was run' -a 174 | 175 | # Show git status 176 | _git-status: 177 | git status 178 | 179 | # Clean all generated files 180 | clean: 181 | rm -rf {{dest}} 182 | rm -rf tmp 183 | rm -rf {{docdir}}/* 184 | rm -rf {{pymodel}} 185 | 186 | # Private recipes 187 | _ensure_pymodel_dir: 188 | -mkdir -p {{pymodel}} 189 | 190 | _ensure_docdir: 191 | -mkdir -p {{docdir}} 192 | 193 | _ensure_examples_output: 194 | -mkdir -p examples/output 195 | 196 | import "project.justfile" 197 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/licenses/Apache-2: -------------------------------------------------------------------------------- 1 | {#- source: http://www.apache.org/licenses/LICENSE-2.0 #} 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "{}" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright {yyyy} {name of copyright owner} 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/licenses/BSD-3: -------------------------------------------------------------------------------- 1 | {#- source: http://opensource.org/licenses/BSD-3-Clause #} 2 | Copyright (c) {% now 'utc', '%Y' %}, {{cookiecutter.full_name}} 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of pytest-{{ cookiecutter.project_name }} nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/licenses/MIT: -------------------------------------------------------------------------------- 1 | {#- source: http://opensource.org/licenses/MIT #} 2 | The MIT License (MIT) 3 | 4 | Copyright (c) {% now 'utc', '%Y' %} {{cookiecutter.full_name}} 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/licenses/MPL-2: -------------------------------------------------------------------------------- 1 | {#- source: https://www.mozilla.org/media/MPL/2.0/index.txt #} 2 | Mozilla Public License Version 2.0 3 | ================================== 4 | 5 | 1. Definitions 6 | -------------- 7 | 8 | 1.1. "Contributor" 9 | means each individual or legal entity that creates, contributes to 10 | the creation of, or owns Covered Software. 11 | 12 | 1.2. "Contributor Version" 13 | means the combination of the Contributions of others (if any) used 14 | by a Contributor and that particular Contributor's Contribution. 15 | 16 | 1.3. "Contribution" 17 | means Covered Software of a particular Contributor. 18 | 19 | 1.4. "Covered Software" 20 | means Source Code Form to which the initial Contributor has attached 21 | the notice in Exhibit A, the Executable Form of such Source Code 22 | Form, and Modifications of such Source Code Form, in each case 23 | including portions thereof. 24 | 25 | 1.5. "Incompatible With Secondary Licenses" 26 | means 27 | 28 | (a) that the initial Contributor has attached the notice described 29 | in Exhibit B to the Covered Software; or 30 | 31 | (b) that the Covered Software was made available under the terms of 32 | version 1.1 or earlier of the License, but not also under the 33 | terms of a Secondary License. 34 | 35 | 1.6. "Executable Form" 36 | means any form of the work other than Source Code Form. 37 | 38 | 1.7. "Larger Work" 39 | means a work that combines Covered Software with other material, in 40 | a separate file or files, that is not Covered Software. 41 | 42 | 1.8. "License" 43 | means this document. 44 | 45 | 1.9. "Licensable" 46 | means having the right to grant, to the maximum extent possible, 47 | whether at the time of the initial grant or subsequently, any and 48 | all of the rights conveyed by this License. 49 | 50 | 1.10. "Modifications" 51 | means any of the following: 52 | 53 | (a) any file in Source Code Form that results from an addition to, 54 | deletion from, or modification of the contents of Covered 55 | Software; or 56 | 57 | (b) any new file in Source Code Form that contains any Covered 58 | Software. 59 | 60 | 1.11. "Patent Claims" of a Contributor 61 | means any patent claim(s), including without limitation, method, 62 | process, and apparatus claims, in any patent Licensable by such 63 | Contributor that would be infringed, but for the grant of the 64 | License, by the making, using, selling, offering for sale, having 65 | made, import, or transfer of either its Contributions or its 66 | Contributor Version. 67 | 68 | 1.12. "Secondary License" 69 | means either the GNU General Public License, Version 2.0, the GNU 70 | Lesser General Public License, Version 2.1, the GNU Affero General 71 | Public License, Version 3.0, or any later versions of those 72 | licenses. 73 | 74 | 1.13. "Source Code Form" 75 | means the form of the work preferred for making modifications. 76 | 77 | 1.14. "You" (or "Your") 78 | means an individual or a legal entity exercising rights under this 79 | License. For legal entities, "You" includes any entity that 80 | controls, is controlled by, or is under common control with You. For 81 | purposes of this definition, "control" means (a) the power, direct 82 | or indirect, to cause the direction or management of such entity, 83 | whether by contract or otherwise, or (b) ownership of more than 84 | fifty percent (50%) of the outstanding shares or beneficial 85 | ownership of such entity. 86 | 87 | 2. License Grants and Conditions 88 | -------------------------------- 89 | 90 | 2.1. Grants 91 | 92 | Each Contributor hereby grants You a world-wide, royalty-free, 93 | non-exclusive license: 94 | 95 | (a) under intellectual property rights (other than patent or trademark) 96 | Licensable by such Contributor to use, reproduce, make available, 97 | modify, display, perform, distribute, and otherwise exploit its 98 | Contributions, either on an unmodified basis, with Modifications, or 99 | as part of a Larger Work; and 100 | 101 | (b) under Patent Claims of such Contributor to make, use, sell, offer 102 | for sale, have made, import, and otherwise transfer either its 103 | Contributions or its Contributor Version. 104 | 105 | 2.2. Effective Date 106 | 107 | The licenses granted in Section 2.1 with respect to any Contribution 108 | become effective for each Contribution on the date the Contributor first 109 | distributes such Contribution. 110 | 111 | 2.3. Limitations on Grant Scope 112 | 113 | The licenses granted in this Section 2 are the only rights granted under 114 | this License. No additional rights or licenses will be implied from the 115 | distribution or licensing of Covered Software under this License. 116 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 117 | Contributor: 118 | 119 | (a) for any code that a Contributor has removed from Covered Software; 120 | or 121 | 122 | (b) for infringements caused by: (i) Your and any other third party's 123 | modifications of Covered Software, or (ii) the combination of its 124 | Contributions with other software (except as part of its Contributor 125 | Version); or 126 | 127 | (c) under Patent Claims infringed by Covered Software in the absence of 128 | its Contributions. 129 | 130 | This License does not grant any rights in the trademarks, service marks, 131 | or logos of any Contributor (except as may be necessary to comply with 132 | the notice requirements in Section 3.4). 133 | 134 | 2.4. Subsequent Licenses 135 | 136 | No Contributor makes additional grants as a result of Your choice to 137 | distribute the Covered Software under a subsequent version of this 138 | License (see Section 10.2) or under the terms of a Secondary License (if 139 | permitted under the terms of Section 3.3). 140 | 141 | 2.5. Representation 142 | 143 | Each Contributor represents that the Contributor believes its 144 | Contributions are its original creation(s) or it has sufficient rights 145 | to grant the rights to its Contributions conveyed by this License. 146 | 147 | 2.6. Fair Use 148 | 149 | This License is not intended to limit any rights You have under 150 | applicable copyright doctrines of fair use, fair dealing, or other 151 | equivalents. 152 | 153 | 2.7. Conditions 154 | 155 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 156 | in Section 2.1. 157 | 158 | 3. Responsibilities 159 | ------------------- 160 | 161 | 3.1. Distribution of Source Form 162 | 163 | All distribution of Covered Software in Source Code Form, including any 164 | Modifications that You create or to which You contribute, must be under 165 | the terms of this License. You must inform recipients that the Source 166 | Code Form of the Covered Software is governed by the terms of this 167 | License, and how they can obtain a copy of this License. You may not 168 | attempt to alter or restrict the recipients' rights in the Source Code 169 | Form. 170 | 171 | 3.2. Distribution of Executable Form 172 | 173 | If You distribute Covered Software in Executable Form then: 174 | 175 | (a) such Covered Software must also be made available in Source Code 176 | Form, as described in Section 3.1, and You must inform recipients of 177 | the Executable Form how they can obtain a copy of such Source Code 178 | Form by reasonable means in a timely manner, at a charge no more 179 | than the cost of distribution to the recipient; and 180 | 181 | (b) You may distribute such Executable Form under the terms of this 182 | License, or sublicense it under different terms, provided that the 183 | license for the Executable Form does not attempt to limit or alter 184 | the recipients' rights in the Source Code Form under this License. 185 | 186 | 3.3. Distribution of a Larger Work 187 | 188 | You may create and distribute a Larger Work under terms of Your choice, 189 | provided that You also comply with the requirements of this License for 190 | the Covered Software. If the Larger Work is a combination of Covered 191 | Software with a work governed by one or more Secondary Licenses, and the 192 | Covered Software is not Incompatible With Secondary Licenses, this 193 | License permits You to additionally distribute such Covered Software 194 | under the terms of such Secondary License(s), so that the recipient of 195 | the Larger Work may, at their option, further distribute the Covered 196 | Software under the terms of either this License or such Secondary 197 | License(s). 198 | 199 | 3.4. Notices 200 | 201 | You may not remove or alter the substance of any license notices 202 | (including copyright notices, patent notices, disclaimers of warranty, 203 | or limitations of liability) contained within the Source Code Form of 204 | the Covered Software, except that You may alter any license notices to 205 | the extent required to remedy known factual inaccuracies. 206 | 207 | 3.5. Application of Additional Terms 208 | 209 | You may choose to offer, and to charge a fee for, warranty, support, 210 | indemnity or liability obligations to one or more recipients of Covered 211 | Software. However, You may do so only on Your own behalf, and not on 212 | behalf of any Contributor. You must make it absolutely clear that any 213 | such warranty, support, indemnity, or liability obligation is offered by 214 | You alone, and You hereby agree to indemnify every Contributor for any 215 | liability incurred by such Contributor as a result of warranty, support, 216 | indemnity or liability terms You offer. You may include additional 217 | disclaimers of warranty and limitations of liability specific to any 218 | jurisdiction. 219 | 220 | 4. Inability to Comply Due to Statute or Regulation 221 | --------------------------------------------------- 222 | 223 | If it is impossible for You to comply with any of the terms of this 224 | License with respect to some or all of the Covered Software due to 225 | statute, judicial order, or regulation then You must: (a) comply with 226 | the terms of this License to the maximum extent possible; and (b) 227 | describe the limitations and the code they affect. Such description must 228 | be placed in a text file included with all distributions of the Covered 229 | Software under this License. Except to the extent prohibited by statute 230 | or regulation, such description must be sufficiently detailed for a 231 | recipient of ordinary skill to be able to understand it. 232 | 233 | 5. Termination 234 | -------------- 235 | 236 | 5.1. The rights granted under this License will terminate automatically 237 | if You fail to comply with any of its terms. However, if You become 238 | compliant, then the rights granted under this License from a particular 239 | Contributor are reinstated (a) provisionally, unless and until such 240 | Contributor explicitly and finally terminates Your grants, and (b) on an 241 | ongoing basis, if such Contributor fails to notify You of the 242 | non-compliance by some reasonable means prior to 60 days after You have 243 | come back into compliance. Moreover, Your grants from a particular 244 | Contributor are reinstated on an ongoing basis if such Contributor 245 | notifies You of the non-compliance by some reasonable means, this is the 246 | first time You have received notice of non-compliance with this License 247 | from such Contributor, and You become compliant prior to 30 days after 248 | Your receipt of the notice. 249 | 250 | 5.2. If You initiate litigation against any entity by asserting a patent 251 | infringement claim (excluding declaratory judgment actions, 252 | counter-claims, and cross-claims) alleging that a Contributor Version 253 | directly or indirectly infringes any patent, then the rights granted to 254 | You by any and all Contributors for the Covered Software under Section 255 | 2.1 of this License shall terminate. 256 | 257 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 258 | end user license agreements (excluding distributors and resellers) which 259 | have been validly granted by You or Your distributors under this License 260 | prior to termination shall survive termination. 261 | 262 | ************************************************************************ 263 | * * 264 | * 6. Disclaimer of Warranty * 265 | * ------------------------- * 266 | * * 267 | * Covered Software is provided under this License on an "as is" * 268 | * basis, without warranty of any kind, either expressed, implied, or * 269 | * statutory, including, without limitation, warranties that the * 270 | * Covered Software is free of defects, merchantable, fit for a * 271 | * particular purpose or non-infringing. The entire risk as to the * 272 | * quality and performance of the Covered Software is with You. * 273 | * Should any Covered Software prove defective in any respect, You * 274 | * (not any Contributor) assume the cost of any necessary servicing, * 275 | * repair, or correction. This disclaimer of warranty constitutes an * 276 | * essential part of this License. No use of any Covered Software is * 277 | * authorized under this License except under this disclaimer. * 278 | * * 279 | ************************************************************************ 280 | 281 | ************************************************************************ 282 | * * 283 | * 7. Limitation of Liability * 284 | * -------------------------- * 285 | * * 286 | * Under no circumstances and under no legal theory, whether tort * 287 | * (including negligence), contract, or otherwise, shall any * 288 | * Contributor, or anyone who distributes Covered Software as * 289 | * permitted above, be liable to You for any direct, indirect, * 290 | * special, incidental, or consequential damages of any character * 291 | * including, without limitation, damages for lost profits, loss of * 292 | * goodwill, work stoppage, computer failure or malfunction, or any * 293 | * and all other commercial damages or losses, even if such party * 294 | * shall have been informed of the possibility of such damages. This * 295 | * limitation of liability shall not apply to liability for death or * 296 | * personal injury resulting from such party's negligence to the * 297 | * extent applicable law prohibits such limitation. Some * 298 | * jurisdictions do not allow the exclusion or limitation of * 299 | * incidental or consequential damages, so this exclusion and * 300 | * limitation may not apply to You. * 301 | * * 302 | ************************************************************************ 303 | 304 | 8. Litigation 305 | ------------- 306 | 307 | Any litigation relating to this License may be brought only in the 308 | courts of a jurisdiction where the defendant maintains its principal 309 | place of business and such litigation shall be governed by laws of that 310 | jurisdiction, without reference to its conflict-of-law provisions. 311 | Nothing in this Section shall prevent a party's ability to bring 312 | cross-claims or counter-claims. 313 | 314 | 9. Miscellaneous 315 | ---------------- 316 | 317 | This License represents the complete agreement concerning the subject 318 | matter hereof. If any provision of this License is held to be 319 | unenforceable, such provision shall be reformed only to the extent 320 | necessary to make it enforceable. Any law or regulation which provides 321 | that the language of a contract shall be construed against the drafter 322 | shall not be used to construe this License against a Contributor. 323 | 324 | 10. Versions of the License 325 | --------------------------- 326 | 327 | 10.1. New Versions 328 | 329 | Mozilla Foundation is the license steward. Except as provided in Section 330 | 10.3, no one other than the license steward has the right to modify or 331 | publish new versions of this License. Each version will be given a 332 | distinguishing version number. 333 | 334 | 10.2. Effect of New Versions 335 | 336 | You may distribute the Covered Software under the terms of the version 337 | of the License under which You originally received the Covered Software, 338 | or under the terms of any subsequent version published by the license 339 | steward. 340 | 341 | 10.3. Modified Versions 342 | 343 | If you create software not governed by this License, and you want to 344 | create a new license for such software, you may create and use a 345 | modified version of this License if you rename the license and remove 346 | any references to the name of the license steward (except to note that 347 | such modified license differs from this License). 348 | 349 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 350 | Licenses 351 | 352 | If You choose to distribute Source Code Form that is Incompatible With 353 | Secondary Licenses under the terms of this version of the License, the 354 | notice described in Exhibit B of this License must be attached. 355 | 356 | Exhibit A - Source Code Form License Notice 357 | ------------------------------------------- 358 | 359 | This Source Code Form is subject to the terms of the Mozilla Public 360 | License, v. 2.0. If a copy of the MPL was not distributed with this 361 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 362 | 363 | If it is not possible or desirable to put the notice in a particular 364 | file, then You may include the notice in a location (such as a LICENSE 365 | file in a relevant directory) where a recipient would be likely to look 366 | for such a notice. 367 | 368 | You may add additional accurate notices of copyright ownership. 369 | 370 | Exhibit B - "Incompatible With Secondary Licenses" Notice 371 | --------------------------------------------------------- 372 | 373 | This Source Code Form is "Incompatible With Secondary Licenses", as 374 | defined by the Mozilla Public License, v. 2.0. 375 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/mkdocs.yml: -------------------------------------------------------------------------------- 1 | --- 2 | site_name: "{{cookiecutter.project_name}}" 3 | theme: 4 | name: material 5 | # palette: 6 | # scheme: slate 7 | # primary: cyan 8 | features: 9 | - content.tabs.link 10 | plugins: 11 | - search 12 | - mermaid2 13 | - mknotebooks: 14 | execute: false 15 | - mermaid2: 16 | version: 10.9.0 17 | nav: 18 | # - Home: home.md 19 | - Index: index.md 20 | - About: about.md 21 | site_url: https://{{cookiecutter.github_org}}.github.io/{{cookiecutter.project_name}} 22 | repo_url: https://github.com/{{cookiecutter.github_org}}/{{cookiecutter.project_name}} 23 | markdown_extensions: 24 | - tables 25 | extra_javascript: 26 | - https://unpkg.com/tablesort@5.3.0/dist/tablesort.min.js 27 | - javascripts/tablesort.js 28 | 29 | # Uncomment this block to enable use of Google Analytics. 30 | # Replace the property value with your own ID. 31 | # extra: 32 | # analytics: 33 | # provider: google 34 | # property: G-XXXXXXXXXX 35 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/project.Makefile: -------------------------------------------------------------------------------- 1 | ## Add your own custom Makefile targets here 2 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/project.justfile: -------------------------------------------------------------------------------- 1 | ## Add your own just recipes here. This is imported by the main justfile. 2 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/project/excel/{{cookiecutter.__project_slug}}.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linkml/linkml-project-cookiecutter/494e28e5496acc76558c07c95dea62d2db05081c/{{cookiecutter.project_name}}/project/excel/{{cookiecutter.__project_slug}}.xlsx -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/project/graphql/{{cookiecutter.__project_slug}}.graphql: -------------------------------------------------------------------------------- 1 | type Address 2 | { 3 | street: String 4 | city: String 5 | postalCode: String 6 | } 7 | 8 | type FamilialRelationship 9 | { 10 | startedAtTime: Date 11 | endedAtTime: Date 12 | relatedTo: String 13 | type: FamilialRelationshipType! 14 | relatedTo: Person! 15 | } 16 | 17 | interface HasAliases 18 | { 19 | aliases: [String] 20 | } 21 | 22 | type NamedThing 23 | { 24 | id: String! 25 | name: String 26 | description: String 27 | image: String 28 | } 29 | 30 | type Organization implements HasAliases 31 | { 32 | id: String! 33 | name: String 34 | description: String 35 | image: String 36 | missionStatement: String 37 | foundingDate: String 38 | aliases: [String] 39 | } 40 | 41 | type Person implements HasAliases 42 | { 43 | id: String! 44 | name: String 45 | description: String 46 | image: String 47 | primaryEmail: String 48 | birthDate: String 49 | ageInYears: Integer 50 | currentAddress: Address 51 | hasFamilialRelationships: [FamilialRelationship] 52 | aliases: [String] 53 | } 54 | 55 | type Registry 56 | { 57 | persons: [Person] 58 | organizations: [Organization] 59 | } 60 | 61 | type Relationship 62 | { 63 | startedAtTime: Date 64 | endedAtTime: Date 65 | relatedTo: String 66 | type: String 67 | } 68 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/project/jsonld/{{cookiecutter.__project_slug}}.context.jsonld: -------------------------------------------------------------------------------- 1 | { 2 | "_comments": "Auto generated from {{cookiecutter.__project_slug}}.yaml by jsonldcontextgen.py version: 0.1.1\n Generation date: 2022-09-06T10:01:44\n Schema: my_datamodel\n metamodel version: 1.7.0\n model version: None\n \n id: https://w3id.org/my_org/my_datamodel\n description: Enter a detailed description of your project here\n license: https://creativecommons.org/publicdomain/zero/1.0/\n ", 3 | "@context": { 4 | "PATO": { 5 | "@id": "http://purl.obolibrary.org/obo/PATO_", 6 | "@prefix": true 7 | }, 8 | "biolink": "https://w3id.org/biolink/", 9 | "famrel": "http://example.org/famrel/", 10 | "linkml": "https://w3id.org/linkml/", 11 | "my_datamodel": { 12 | "@id": "https://w3id.org/my_org/my_datamodel", 13 | "@prefix": true 14 | }, 15 | "prov": "http://www.w3.org/ns/prov#", 16 | "schema": "http://schema.org/", 17 | "@vocab": "https://w3id.org/my_org/my_datamodel", 18 | "age_in_years": { 19 | "@type": "xsd:integer" 20 | }, 21 | "birth_date": { 22 | "@id": "schema:birthDate" 23 | }, 24 | "current_address": { 25 | "@type": "@id" 26 | }, 27 | "description": { 28 | "@id": "schema:description" 29 | }, 30 | "employed_at": { 31 | "@type": "@id" 32 | }, 33 | "ended_at_time": { 34 | "@type": "xsd:date", 35 | "@id": "prov:endedAtTime" 36 | }, 37 | "has_familial_relationships": { 38 | "@type": "@id" 39 | }, 40 | "id": "@id", 41 | "image": { 42 | "@id": "schema:image" 43 | }, 44 | "is_current": { 45 | "@type": "xsd:boolean" 46 | }, 47 | "name": { 48 | "@id": "schema:name" 49 | }, 50 | "primary_email": { 51 | "@id": "schema:email" 52 | }, 53 | "organizations": { 54 | "@type": "@id" 55 | }, 56 | "persons": { 57 | "@type": "@id" 58 | }, 59 | "related_to": { 60 | "@type": "@id" 61 | }, 62 | "started_at_time": { 63 | "@type": "xsd:date", 64 | "@id": "prov:startedAtTime" 65 | }, 66 | "Address": { 67 | "@id": "schema:PostalAddress" 68 | }, 69 | "Organization": { 70 | "@id": "schema:Organization" 71 | }, 72 | "Person": { 73 | "@id": "schema:Person" 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/project/jsonld/{{cookiecutter.__project_slug}}.jsonld: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my_datamodel", 3 | "description": "Enter a detailed description of your project here", 4 | "title": "My Datamodel", 5 | "see_also": [ 6 | "https://example.org/" 7 | ], 8 | "id": "https://w3id.org/my_org/my_datamodel", 9 | "imports": [ 10 | "linkml:types" 11 | ], 12 | "license": "https://creativecommons.org/publicdomain/zero/1.0/", 13 | "prefixes": [ 14 | { 15 | "prefix_prefix": "my_datamodel", 16 | "prefix_reference": "https://w3id.org/my_org/my_datamodel" 17 | }, 18 | { 19 | "prefix_prefix": "linkml", 20 | "prefix_reference": "https://w3id.org/linkml/" 21 | }, 22 | { 23 | "prefix_prefix": "biolink", 24 | "prefix_reference": "https://w3id.org/biolink/" 25 | }, 26 | { 27 | "prefix_prefix": "schema", 28 | "prefix_reference": "http://schema.org/" 29 | }, 30 | { 31 | "prefix_prefix": "PATO", 32 | "prefix_reference": "http://purl.obolibrary.org/obo/PATO_" 33 | }, 34 | { 35 | "prefix_prefix": "famrel", 36 | "prefix_reference": "http://example.org/famrel/" 37 | } 38 | ], 39 | "default_curi_maps": [ 40 | "semweb_context" 41 | ], 42 | "default_prefix": "my_datamodel", 43 | "default_range": "string", 44 | "types": [ 45 | { 46 | "name": "string", 47 | "definition_uri": "https://w3id.org/linkml/String", 48 | "description": "A character string", 49 | "from_schema": "https://w3id.org/linkml/types", 50 | "imported_from": "linkml:types", 51 | "base": "str", 52 | "uri": "http://www.w3.org/2001/XMLSchema#string", 53 | "@type": "TypeDefinition" 54 | }, 55 | { 56 | "name": "integer", 57 | "definition_uri": "https://w3id.org/linkml/Integer", 58 | "description": "An integer", 59 | "from_schema": "https://w3id.org/linkml/types", 60 | "imported_from": "linkml:types", 61 | "base": "int", 62 | "uri": "http://www.w3.org/2001/XMLSchema#integer", 63 | "@type": "TypeDefinition" 64 | }, 65 | { 66 | "name": "boolean", 67 | "definition_uri": "https://w3id.org/linkml/Boolean", 68 | "description": "A binary (true or false) value", 69 | "from_schema": "https://w3id.org/linkml/types", 70 | "imported_from": "linkml:types", 71 | "base": "Bool", 72 | "uri": "http://www.w3.org/2001/XMLSchema#boolean", 73 | "repr": "bool", 74 | "@type": "TypeDefinition" 75 | }, 76 | { 77 | "name": "float", 78 | "definition_uri": "https://w3id.org/linkml/Float", 79 | "description": "A real number that conforms to the xsd:float specification", 80 | "from_schema": "https://w3id.org/linkml/types", 81 | "imported_from": "linkml:types", 82 | "base": "float", 83 | "uri": "http://www.w3.org/2001/XMLSchema#float", 84 | "@type": "TypeDefinition" 85 | }, 86 | { 87 | "name": "double", 88 | "definition_uri": "https://w3id.org/linkml/Double", 89 | "description": "A real number that conforms to the xsd:double specification", 90 | "from_schema": "https://w3id.org/linkml/types", 91 | "imported_from": "linkml:types", 92 | "base": "float", 93 | "uri": "http://www.w3.org/2001/XMLSchema#double", 94 | "@type": "TypeDefinition" 95 | }, 96 | { 97 | "name": "decimal", 98 | "definition_uri": "https://w3id.org/linkml/Decimal", 99 | "description": "A real number with arbitrary precision that conforms to the xsd:decimal specification", 100 | "from_schema": "https://w3id.org/linkml/types", 101 | "imported_from": "linkml:types", 102 | "base": "Decimal", 103 | "uri": "http://www.w3.org/2001/XMLSchema#decimal", 104 | "@type": "TypeDefinition" 105 | }, 106 | { 107 | "name": "time", 108 | "definition_uri": "https://w3id.org/linkml/Time", 109 | "description": "A time object represents a (local) time of day, independent of any particular day", 110 | "notes": [ 111 | "URI is dateTime because OWL reasoners do not work with straight date or time" 112 | ], 113 | "from_schema": "https://w3id.org/linkml/types", 114 | "imported_from": "linkml:types", 115 | "base": "XSDTime", 116 | "uri": "http://www.w3.org/2001/XMLSchema#dateTime", 117 | "repr": "str", 118 | "@type": "TypeDefinition" 119 | }, 120 | { 121 | "name": "date", 122 | "definition_uri": "https://w3id.org/linkml/Date", 123 | "description": "a date (year, month and day) in an idealized calendar", 124 | "notes": [ 125 | "URI is dateTime because OWL reasoners don't work with straight date or time" 126 | ], 127 | "from_schema": "https://w3id.org/linkml/types", 128 | "imported_from": "linkml:types", 129 | "base": "XSDDate", 130 | "uri": "http://www.w3.org/2001/XMLSchema#date", 131 | "repr": "str", 132 | "@type": "TypeDefinition" 133 | }, 134 | { 135 | "name": "datetime", 136 | "definition_uri": "https://w3id.org/linkml/Datetime", 137 | "description": "The combination of a date and time", 138 | "from_schema": "https://w3id.org/linkml/types", 139 | "imported_from": "linkml:types", 140 | "base": "XSDDateTime", 141 | "uri": "http://www.w3.org/2001/XMLSchema#dateTime", 142 | "repr": "str", 143 | "@type": "TypeDefinition" 144 | }, 145 | { 146 | "name": "date_or_datetime", 147 | "definition_uri": "https://w3id.org/linkml/DateOrDatetime", 148 | "description": "Either a date or a datetime", 149 | "from_schema": "https://w3id.org/linkml/types", 150 | "imported_from": "linkml:types", 151 | "base": "str", 152 | "uri": "https://w3id.org/linkml/DateOrDatetime", 153 | "repr": "str", 154 | "@type": "TypeDefinition" 155 | }, 156 | { 157 | "name": "uriorcurie", 158 | "definition_uri": "https://w3id.org/linkml/Uriorcurie", 159 | "description": "a URI or a CURIE", 160 | "from_schema": "https://w3id.org/linkml/types", 161 | "imported_from": "linkml:types", 162 | "base": "URIorCURIE", 163 | "uri": "http://www.w3.org/2001/XMLSchema#anyURI", 164 | "repr": "str", 165 | "@type": "TypeDefinition" 166 | }, 167 | { 168 | "name": "uri", 169 | "definition_uri": "https://w3id.org/linkml/Uri", 170 | "description": "a complete URI", 171 | "from_schema": "https://w3id.org/linkml/types", 172 | "imported_from": "linkml:types", 173 | "base": "URI", 174 | "uri": "http://www.w3.org/2001/XMLSchema#anyURI", 175 | "repr": "str", 176 | "@type": "TypeDefinition" 177 | }, 178 | { 179 | "name": "ncname", 180 | "definition_uri": "https://w3id.org/linkml/Ncname", 181 | "description": "Prefix part of CURIE", 182 | "from_schema": "https://w3id.org/linkml/types", 183 | "imported_from": "linkml:types", 184 | "base": "NCName", 185 | "uri": "http://www.w3.org/2001/XMLSchema#string", 186 | "repr": "str", 187 | "@type": "TypeDefinition" 188 | }, 189 | { 190 | "name": "objectidentifier", 191 | "definition_uri": "https://w3id.org/linkml/Objectidentifier", 192 | "description": "A URI or CURIE that represents an object in the model.", 193 | "comments": [ 194 | "Used for inheritance and type checking" 195 | ], 196 | "from_schema": "https://w3id.org/linkml/types", 197 | "imported_from": "linkml:types", 198 | "base": "ElementIdentifier", 199 | "uri": "http://www.w3.org/ns/shex#iri", 200 | "repr": "str", 201 | "@type": "TypeDefinition" 202 | }, 203 | { 204 | "name": "nodeidentifier", 205 | "definition_uri": "https://w3id.org/linkml/Nodeidentifier", 206 | "description": "A URI, CURIE or BNODE that represents a node in a model.", 207 | "from_schema": "https://w3id.org/linkml/types", 208 | "imported_from": "linkml:types", 209 | "base": "NodeIdentifier", 210 | "uri": "http://www.w3.org/ns/shex#nonLiteral", 211 | "repr": "str", 212 | "@type": "TypeDefinition" 213 | } 214 | ], 215 | "enums": [ 216 | { 217 | "name": "PersonStatus", 218 | "definition_uri": "https://w3id.org/my_org/my_datamodelPersonStatus", 219 | "from_schema": "https://w3id.org/my_org/my_datamodel", 220 | "permissible_values": [ 221 | { 222 | "text": "ALIVE", 223 | "description": "the person is living", 224 | "meaning": "PATO:0001421" 225 | }, 226 | { 227 | "text": "DEAD", 228 | "description": "the person is deceased", 229 | "meaning": "PATO:0001422" 230 | }, 231 | { 232 | "text": "UNKNOWN", 233 | "description": "the vital status is not known", 234 | "todos": [ 235 | "map this to an ontology" 236 | ] 237 | } 238 | ] 239 | }, 240 | { 241 | "name": "FamilialRelationshipType", 242 | "definition_uri": "https://w3id.org/my_org/my_datamodelFamilialRelationshipType", 243 | "from_schema": "https://w3id.org/my_org/my_datamodel", 244 | "permissible_values": [ 245 | { 246 | "text": "SIBLING_OF", 247 | "meaning": "famrel:01" 248 | }, 249 | { 250 | "text": "PARENT_OF", 251 | "meaning": "famrel:02" 252 | }, 253 | { 254 | "text": "CHILD_OF", 255 | "meaning": "famrel:01" 256 | } 257 | ] 258 | } 259 | ], 260 | "slots": [ 261 | { 262 | "name": "id", 263 | "definition_uri": "https://w3id.org/my_org/my_datamodelid", 264 | "from_schema": "https://w3id.org/my_org/my_datamodel", 265 | "mappings": [ 266 | "http://schema.org/identifier" 267 | ], 268 | "slot_uri": "http://schema.org/identifier", 269 | "identifier": true, 270 | "owner": "NamedThing", 271 | "domain_of": [ 272 | "NamedThing" 273 | ], 274 | "range": "string", 275 | "required": true, 276 | "@type": "SlotDefinition" 277 | }, 278 | { 279 | "name": "name", 280 | "definition_uri": "https://w3id.org/my_org/my_datamodelname", 281 | "from_schema": "https://w3id.org/my_org/my_datamodel", 282 | "mappings": [ 283 | "http://schema.org/name" 284 | ], 285 | "slot_uri": "http://schema.org/name", 286 | "owner": "NamedThing", 287 | "domain_of": [ 288 | "NamedThing" 289 | ], 290 | "range": "string", 291 | "@type": "SlotDefinition" 292 | }, 293 | { 294 | "name": "description", 295 | "definition_uri": "https://w3id.org/my_org/my_datamodeldescription", 296 | "from_schema": "https://w3id.org/my_org/my_datamodel", 297 | "mappings": [ 298 | "http://schema.org/description" 299 | ], 300 | "slot_uri": "http://schema.org/description", 301 | "owner": "NamedThing", 302 | "domain_of": [ 303 | "NamedThing" 304 | ], 305 | "range": "string", 306 | "@type": "SlotDefinition" 307 | }, 308 | { 309 | "name": "image", 310 | "definition_uri": "https://w3id.org/my_org/my_datamodelimage", 311 | "from_schema": "https://w3id.org/my_org/my_datamodel", 312 | "mappings": [ 313 | "http://schema.org/image" 314 | ], 315 | "slot_uri": "http://schema.org/image", 316 | "owner": "NamedThing", 317 | "domain_of": [ 318 | "NamedThing" 319 | ], 320 | "range": "string", 321 | "@type": "SlotDefinition" 322 | }, 323 | { 324 | "name": "primary_email", 325 | "definition_uri": "https://w3id.org/my_org/my_datamodelprimary_email", 326 | "from_schema": "https://w3id.org/my_org/my_datamodel", 327 | "mappings": [ 328 | "http://schema.org/email" 329 | ], 330 | "slot_uri": "http://schema.org/email", 331 | "owner": "Person", 332 | "domain_of": [ 333 | "Person" 334 | ], 335 | "range": "string", 336 | "@type": "SlotDefinition" 337 | }, 338 | { 339 | "name": "birth_date", 340 | "definition_uri": "https://w3id.org/my_org/my_datamodelbirth_date", 341 | "from_schema": "https://w3id.org/my_org/my_datamodel", 342 | "mappings": [ 343 | "http://schema.org/birthDate" 344 | ], 345 | "slot_uri": "http://schema.org/birthDate", 346 | "owner": "Person", 347 | "domain_of": [ 348 | "Person" 349 | ], 350 | "range": "string", 351 | "@type": "SlotDefinition" 352 | }, 353 | { 354 | "name": "employed_at", 355 | "definition_uri": "https://w3id.org/my_org/my_datamodelemployed_at", 356 | "from_schema": "https://w3id.org/my_org/my_datamodel", 357 | "slot_uri": "https://w3id.org/my_org/my_datamodelemployed_at", 358 | "range": "Organization", 359 | "@type": "SlotDefinition" 360 | }, 361 | { 362 | "name": "is_current", 363 | "definition_uri": "https://w3id.org/my_org/my_datamodelis_current", 364 | "from_schema": "https://w3id.org/my_org/my_datamodel", 365 | "slot_uri": "https://w3id.org/my_org/my_datamodelis_current", 366 | "range": "boolean", 367 | "@type": "SlotDefinition" 368 | }, 369 | { 370 | "name": "has_familial_relationships", 371 | "definition_uri": "https://w3id.org/my_org/my_datamodelhas_familial_relationships", 372 | "from_schema": "https://w3id.org/my_org/my_datamodel", 373 | "slot_uri": "https://w3id.org/my_org/my_datamodelhas_familial_relationships", 374 | "multivalued": true, 375 | "owner": "Person", 376 | "domain_of": [ 377 | "Person" 378 | ], 379 | "range": "FamilialRelationship", 380 | "inlined": true, 381 | "inlined_as_list": true, 382 | "@type": "SlotDefinition" 383 | }, 384 | { 385 | "name": "current_address", 386 | "definition_uri": "https://w3id.org/my_org/my_datamodelcurrent_address", 387 | "description": "The address at which a person currently lives", 388 | "from_schema": "https://w3id.org/my_org/my_datamodel", 389 | "slot_uri": "https://w3id.org/my_org/my_datamodelcurrent_address", 390 | "owner": "Person", 391 | "domain_of": [ 392 | "Person" 393 | ], 394 | "range": "Address", 395 | "inlined": true, 396 | "@type": "SlotDefinition" 397 | }, 398 | { 399 | "name": "age_in_years", 400 | "definition_uri": "https://w3id.org/my_org/my_datamodelage_in_years", 401 | "from_schema": "https://w3id.org/my_org/my_datamodel", 402 | "slot_uri": "https://w3id.org/my_org/my_datamodelage_in_years", 403 | "owner": "Person", 404 | "domain_of": [ 405 | "Person" 406 | ], 407 | "range": "integer", 408 | "minimum_value": 0, 409 | "maximum_value": 999, 410 | "@type": "SlotDefinition" 411 | }, 412 | { 413 | "name": "related_to", 414 | "definition_uri": "https://w3id.org/my_org/my_datamodelrelated_to", 415 | "from_schema": "https://w3id.org/my_org/my_datamodel", 416 | "slot_uri": "https://w3id.org/my_org/my_datamodelrelated_to", 417 | "owner": "Relationship", 418 | "domain_of": [ 419 | "Relationship" 420 | ], 421 | "range": "string", 422 | "@type": "SlotDefinition" 423 | }, 424 | { 425 | "name": "type", 426 | "definition_uri": "https://w3id.org/my_org/my_datamodeltype", 427 | "from_schema": "https://w3id.org/my_org/my_datamodel", 428 | "slot_uri": "https://w3id.org/my_org/my_datamodeltype", 429 | "owner": "Relationship", 430 | "domain_of": [ 431 | "Relationship" 432 | ], 433 | "range": "string", 434 | "@type": "SlotDefinition" 435 | }, 436 | { 437 | "name": "street", 438 | "definition_uri": "https://w3id.org/my_org/my_datamodelstreet", 439 | "from_schema": "https://w3id.org/my_org/my_datamodel", 440 | "slot_uri": "https://w3id.org/my_org/my_datamodelstreet", 441 | "owner": "Address", 442 | "domain_of": [ 443 | "Address" 444 | ], 445 | "range": "string", 446 | "@type": "SlotDefinition" 447 | }, 448 | { 449 | "name": "city", 450 | "definition_uri": "https://w3id.org/my_org/my_datamodelcity", 451 | "from_schema": "https://w3id.org/my_org/my_datamodel", 452 | "slot_uri": "https://w3id.org/my_org/my_datamodelcity", 453 | "owner": "Address", 454 | "domain_of": [ 455 | "Address" 456 | ], 457 | "range": "string", 458 | "@type": "SlotDefinition" 459 | }, 460 | { 461 | "name": "mission_statement", 462 | "definition_uri": "https://w3id.org/my_org/my_datamodelmission_statement", 463 | "from_schema": "https://w3id.org/my_org/my_datamodel", 464 | "slot_uri": "https://w3id.org/my_org/my_datamodelmission_statement", 465 | "owner": "Organization", 466 | "domain_of": [ 467 | "Organization" 468 | ], 469 | "range": "string", 470 | "@type": "SlotDefinition" 471 | }, 472 | { 473 | "name": "founding_date", 474 | "definition_uri": "https://w3id.org/my_org/my_datamodelfounding_date", 475 | "from_schema": "https://w3id.org/my_org/my_datamodel", 476 | "slot_uri": "https://w3id.org/my_org/my_datamodelfounding_date", 477 | "owner": "Organization", 478 | "domain_of": [ 479 | "Organization" 480 | ], 481 | "range": "string", 482 | "@type": "SlotDefinition" 483 | }, 484 | { 485 | "name": "postal_code", 486 | "definition_uri": "https://w3id.org/my_org/my_datamodelpostal_code", 487 | "from_schema": "https://w3id.org/my_org/my_datamodel", 488 | "slot_uri": "https://w3id.org/my_org/my_datamodelpostal_code", 489 | "owner": "Address", 490 | "domain_of": [ 491 | "Address" 492 | ], 493 | "range": "string", 494 | "@type": "SlotDefinition" 495 | }, 496 | { 497 | "name": "started_at_time", 498 | "definition_uri": "https://w3id.org/my_org/my_datamodelstarted_at_time", 499 | "from_schema": "https://w3id.org/my_org/my_datamodel", 500 | "mappings": [ 501 | "http://www.w3.org/ns/prov#startedAtTime" 502 | ], 503 | "slot_uri": "http://www.w3.org/ns/prov#startedAtTime", 504 | "owner": "Relationship", 505 | "domain_of": [ 506 | "Relationship" 507 | ], 508 | "range": "date", 509 | "@type": "SlotDefinition" 510 | }, 511 | { 512 | "name": "ended_at_time", 513 | "definition_uri": "https://w3id.org/my_org/my_datamodelended_at_time", 514 | "from_schema": "https://w3id.org/my_org/my_datamodel", 515 | "mappings": [ 516 | "http://www.w3.org/ns/prov#endedAtTime" 517 | ], 518 | "slot_uri": "http://www.w3.org/ns/prov#endedAtTime", 519 | "owner": "Relationship", 520 | "domain_of": [ 521 | "Relationship" 522 | ], 523 | "range": "date", 524 | "@type": "SlotDefinition" 525 | }, 526 | { 527 | "name": "registry__persons", 528 | "from_schema": "https://w3id.org/my_org/my_datamodel", 529 | "slot_uri": "https://w3id.org/my_org/my_datamodelpersons", 530 | "multivalued": true, 531 | "alias": "persons", 532 | "owner": "Registry", 533 | "domain_of": [ 534 | "Registry" 535 | ], 536 | "range": "Person", 537 | "inlined": true, 538 | "inlined_as_list": true, 539 | "@type": "SlotDefinition" 540 | }, 541 | { 542 | "name": "registry__organizations", 543 | "from_schema": "https://w3id.org/my_org/my_datamodel", 544 | "slot_uri": "https://w3id.org/my_org/my_datamodelorganizations", 545 | "multivalued": true, 546 | "alias": "organizations", 547 | "owner": "Registry", 548 | "domain_of": [ 549 | "Registry" 550 | ], 551 | "range": "Organization", 552 | "inlined": true, 553 | "inlined_as_list": true, 554 | "@type": "SlotDefinition" 555 | }, 556 | { 557 | "name": "hasAliases__aliases", 558 | "from_schema": "https://w3id.org/my_org/my_datamodel", 559 | "exact_mappings": [ 560 | "http://schema.org/alternateName" 561 | ], 562 | "slot_uri": "https://w3id.org/my_org/my_datamodelaliases", 563 | "multivalued": true, 564 | "alias": "aliases", 565 | "owner": "HasAliases", 566 | "domain_of": [ 567 | "HasAliases" 568 | ], 569 | "range": "string", 570 | "@type": "SlotDefinition" 571 | }, 572 | { 573 | "name": "related_to", 574 | "from_schema": "https://w3id.org/my_org/my_datamodel", 575 | "slot_uri": "https://w3id.org/my_org/my_datamodelrelated_to", 576 | "range": "Person", 577 | "required": true, 578 | "@type": "SlotDefinition" 579 | }, 580 | { 581 | "name": "Person_primary_email", 582 | "definition_uri": "https://w3id.org/my_org/my_datamodelprimary_email", 583 | "from_schema": "https://w3id.org/my_org/my_datamodel", 584 | "mappings": [ 585 | "http://schema.org/email" 586 | ], 587 | "is_a": "primary_email", 588 | "domain": "Person", 589 | "slot_uri": "http://schema.org/email", 590 | "alias": "primary_email", 591 | "owner": "Person", 592 | "domain_of": [ 593 | "Person" 594 | ], 595 | "is_usage_slot": true, 596 | "usage_slot_name": "primary_email", 597 | "range": "string", 598 | "pattern": "^\\S+@[\\S+\\.]+\\S+", 599 | "@type": "SlotDefinition" 600 | }, 601 | { 602 | "name": "FamilialRelationship_type", 603 | "definition_uri": "https://w3id.org/my_org/my_datamodeltype", 604 | "from_schema": "https://w3id.org/my_org/my_datamodel", 605 | "is_a": "type", 606 | "domain": "FamilialRelationship", 607 | "slot_uri": "https://w3id.org/my_org/my_datamodeltype", 608 | "alias": "type", 609 | "owner": "FamilialRelationship", 610 | "domain_of": [ 611 | "FamilialRelationship" 612 | ], 613 | "is_usage_slot": true, 614 | "usage_slot_name": "type", 615 | "range": "FamilialRelationshipType", 616 | "required": true, 617 | "@type": "SlotDefinition" 618 | }, 619 | { 620 | "name": "FamilialRelationship_related_to", 621 | "from_schema": "https://w3id.org/my_org/my_datamodel", 622 | "is_a": "related_to", 623 | "domain": "FamilialRelationship", 624 | "slot_uri": "https://w3id.org/my_org/my_datamodelrelated_to", 625 | "alias": "related to", 626 | "owner": "FamilialRelationship", 627 | "domain_of": [ 628 | "FamilialRelationship" 629 | ], 630 | "is_usage_slot": true, 631 | "usage_slot_name": "related to", 632 | "range": "Person", 633 | "required": true, 634 | "@type": "SlotDefinition" 635 | } 636 | ], 637 | "classes": [ 638 | { 639 | "name": "Registry", 640 | "definition_uri": "https://w3id.org/my_org/my_datamodelRegistry", 641 | "description": "Top level data container", 642 | "from_schema": "https://w3id.org/my_org/my_datamodel", 643 | "slots": [ 644 | "registry__persons", 645 | "registry__organizations" 646 | ], 647 | "slot_usage": {}, 648 | "attributes": [ 649 | { 650 | "name": "persons", 651 | "multivalued": true, 652 | "range": "Person", 653 | "inlined": true, 654 | "inlined_as_list": true, 655 | "@type": "SlotDefinition" 656 | }, 657 | { 658 | "name": "organizations", 659 | "multivalued": true, 660 | "range": "Organization", 661 | "inlined": true, 662 | "inlined_as_list": true, 663 | "@type": "SlotDefinition" 664 | } 665 | ], 666 | "class_uri": "https://w3id.org/my_org/my_datamodelRegistry", 667 | "tree_root": true, 668 | "@type": "ClassDefinition" 669 | }, 670 | { 671 | "name": "NamedThing", 672 | "definition_uri": "https://w3id.org/my_org/my_datamodelNamedThing", 673 | "description": "A generic grouping for any identifiable entity", 674 | "from_schema": "https://w3id.org/my_org/my_datamodel", 675 | "close_mappings": [ 676 | "schema:Thing" 677 | ], 678 | "slots": [ 679 | "id", 680 | "name", 681 | "description", 682 | "image" 683 | ], 684 | "slot_usage": {}, 685 | "class_uri": "https://w3id.org/my_org/my_datamodelNamedThing", 686 | "@type": "ClassDefinition" 687 | }, 688 | { 689 | "name": "Person", 690 | "definition_uri": "https://w3id.org/my_org/my_datamodelPerson", 691 | "description": "A person (alive, dead, undead, or fictional).", 692 | "from_schema": "https://w3id.org/my_org/my_datamodel", 693 | "mappings": [ 694 | "schema:Person" 695 | ], 696 | "is_a": "NamedThing", 697 | "mixins": [ 698 | "HasAliases" 699 | ], 700 | "slots": [ 701 | "id", 702 | "name", 703 | "description", 704 | "image", 705 | "Person_primary_email", 706 | "birth_date", 707 | "age_in_years", 708 | "current_address", 709 | "has_familial_relationships", 710 | "hasAliases__aliases" 711 | ], 712 | "slot_usage": {}, 713 | "class_uri": "http://schema.org/Person", 714 | "@type": "ClassDefinition" 715 | }, 716 | { 717 | "name": "HasAliases", 718 | "definition_uri": "https://w3id.org/my_org/my_datamodelHasAliases", 719 | "description": "A mixin applied to any class that can have aliases/alternateNames", 720 | "from_schema": "https://w3id.org/my_org/my_datamodel", 721 | "mixin": true, 722 | "slots": [ 723 | "hasAliases__aliases" 724 | ], 725 | "slot_usage": {}, 726 | "attributes": [ 727 | { 728 | "name": "aliases", 729 | "exact_mappings": [ 730 | "schema:alternateName" 731 | ], 732 | "multivalued": true, 733 | "@type": "SlotDefinition" 734 | } 735 | ], 736 | "class_uri": "https://w3id.org/my_org/my_datamodelHasAliases", 737 | "@type": "ClassDefinition" 738 | }, 739 | { 740 | "name": "Organization", 741 | "definition_uri": "https://w3id.org/my_org/my_datamodelOrganization", 742 | "description": "An organization such as a company or university", 743 | "from_schema": "https://w3id.org/my_org/my_datamodel", 744 | "mappings": [ 745 | "schema:Organization" 746 | ], 747 | "is_a": "NamedThing", 748 | "mixins": [ 749 | "HasAliases" 750 | ], 751 | "slots": [ 752 | "id", 753 | "name", 754 | "description", 755 | "image", 756 | "mission_statement", 757 | "founding_date", 758 | "hasAliases__aliases" 759 | ], 760 | "slot_usage": {}, 761 | "class_uri": "http://schema.org/Organization", 762 | "@type": "ClassDefinition" 763 | }, 764 | { 765 | "name": "Address", 766 | "definition_uri": "https://w3id.org/my_org/my_datamodelAddress", 767 | "from_schema": "https://w3id.org/my_org/my_datamodel", 768 | "mappings": [ 769 | "schema:PostalAddress" 770 | ], 771 | "slots": [ 772 | "street", 773 | "city", 774 | "postal_code" 775 | ], 776 | "slot_usage": {}, 777 | "class_uri": "http://schema.org/PostalAddress", 778 | "@type": "ClassDefinition" 779 | }, 780 | { 781 | "name": "Relationship", 782 | "definition_uri": "https://w3id.org/my_org/my_datamodelRelationship", 783 | "from_schema": "https://w3id.org/my_org/my_datamodel", 784 | "slots": [ 785 | "started_at_time", 786 | "ended_at_time", 787 | "related_to", 788 | "type" 789 | ], 790 | "slot_usage": {}, 791 | "class_uri": "https://w3id.org/my_org/my_datamodelRelationship", 792 | "@type": "ClassDefinition" 793 | }, 794 | { 795 | "name": "FamilialRelationship", 796 | "definition_uri": "https://w3id.org/my_org/my_datamodelFamilialRelationship", 797 | "from_schema": "https://w3id.org/my_org/my_datamodel", 798 | "is_a": "Relationship", 799 | "slots": [ 800 | "started_at_time", 801 | "ended_at_time", 802 | "related_to", 803 | "FamilialRelationship_type", 804 | "FamilialRelationship_related_to" 805 | ], 806 | "slot_usage": {}, 807 | "class_uri": "https://w3id.org/my_org/my_datamodelFamilialRelationship", 808 | "@type": "ClassDefinition" 809 | } 810 | ], 811 | "metamodel_version": "1.7.0", 812 | "source_file": "{{cookiecutter.__project_slug}}.yaml", 813 | "source_file_date": "2022-09-06T10:00:58", 814 | "source_file_size": 3771, 815 | "generation_date": "2022-09-06T10:01:45", 816 | "@type": "SchemaDefinition", 817 | "@context": [ 818 | "project/jsonld/{{cookiecutter.__project_slug}}.context.jsonld", 819 | "https://w3id.org/linkml/types.context.jsonld", 820 | { 821 | "@base": "https://w3id.org/my_org/my_datamodel" 822 | } 823 | ] 824 | } 825 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/project/jsonschema/{{cookiecutter.__project_slug}}.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$defs": { 3 | "Address": { 4 | "additionalProperties": false, 5 | "description": "", 6 | "properties": { 7 | "city": { 8 | "type": "string" 9 | }, 10 | "postal_code": { 11 | "type": "string" 12 | }, 13 | "street": { 14 | "type": "string" 15 | } 16 | }, 17 | "required": [], 18 | "title": "Address", 19 | "type": "object" 20 | }, 21 | "FamilialRelationship": { 22 | "additionalProperties": false, 23 | "description": "", 24 | "properties": { 25 | "ended_at_time": { 26 | "format": "date", 27 | "type": "string" 28 | }, 29 | "related_to": { 30 | "type": "string" 31 | }, 32 | "started_at_time": { 33 | "format": "date", 34 | "type": "string" 35 | }, 36 | "type": { 37 | "$ref": "#/$defs/FamilialRelationshipType" 38 | } 39 | }, 40 | "required": [ 41 | "type", 42 | "related_to" 43 | ], 44 | "title": "FamilialRelationship", 45 | "type": "object" 46 | }, 47 | "FamilialRelationshipType": { 48 | "description": "", 49 | "enum": [ 50 | "SIBLING_OF", 51 | "PARENT_OF", 52 | "CHILD_OF" 53 | ], 54 | "title": "FamilialRelationshipType", 55 | "type": "string" 56 | }, 57 | "NamedThing": { 58 | "additionalProperties": false, 59 | "description": "A generic grouping for any identifiable entity", 60 | "properties": { 61 | "description": { 62 | "type": "string" 63 | }, 64 | "id": { 65 | "type": "string" 66 | }, 67 | "image": { 68 | "type": "string" 69 | }, 70 | "name": { 71 | "type": "string" 72 | } 73 | }, 74 | "required": [ 75 | "id" 76 | ], 77 | "title": "NamedThing", 78 | "type": "object" 79 | }, 80 | "Organization": { 81 | "additionalProperties": false, 82 | "description": "An organization such as a company or university", 83 | "properties": { 84 | "aliases": { 85 | "items": { 86 | "type": "string" 87 | }, 88 | "type": "array" 89 | }, 90 | "description": { 91 | "type": "string" 92 | }, 93 | "founding_date": { 94 | "type": "string" 95 | }, 96 | "id": { 97 | "type": "string" 98 | }, 99 | "image": { 100 | "type": "string" 101 | }, 102 | "mission_statement": { 103 | "type": "string" 104 | }, 105 | "name": { 106 | "type": "string" 107 | } 108 | }, 109 | "required": [ 110 | "id" 111 | ], 112 | "title": "Organization", 113 | "type": "object" 114 | }, 115 | "Person": { 116 | "additionalProperties": false, 117 | "description": "A person (alive, dead, undead, or fictional).", 118 | "properties": { 119 | "age_in_years": { 120 | "maximum": 999, 121 | "minimum": 0, 122 | "type": "integer" 123 | }, 124 | "aliases": { 125 | "items": { 126 | "type": "string" 127 | }, 128 | "type": "array" 129 | }, 130 | "birth_date": { 131 | "type": "string" 132 | }, 133 | "current_address": { 134 | "$ref": "#/$defs/Address", 135 | "description": "The address at which a person currently lives" 136 | }, 137 | "description": { 138 | "type": "string" 139 | }, 140 | "has_familial_relationships": { 141 | "items": { 142 | "$ref": "#/$defs/FamilialRelationship" 143 | }, 144 | "type": "array" 145 | }, 146 | "id": { 147 | "type": "string" 148 | }, 149 | "image": { 150 | "type": "string" 151 | }, 152 | "name": { 153 | "type": "string" 154 | }, 155 | "primary_email": { 156 | "pattern": "^\\S+@[\\S+\\.]+\\S+", 157 | "type": "string" 158 | } 159 | }, 160 | "required": [ 161 | "id" 162 | ], 163 | "title": "Person", 164 | "type": "object" 165 | }, 166 | "PersonStatus": { 167 | "description": "", 168 | "enum": [ 169 | "ALIVE", 170 | "DEAD", 171 | "UNKNOWN" 172 | ], 173 | "title": "PersonStatus", 174 | "type": "string" 175 | }, 176 | "Registry": { 177 | "additionalProperties": false, 178 | "description": "Top level data container", 179 | "properties": { 180 | "organizations": { 181 | "items": { 182 | "$ref": "#/$defs/Organization" 183 | }, 184 | "type": "array" 185 | }, 186 | "persons": { 187 | "items": { 188 | "$ref": "#/$defs/Person" 189 | }, 190 | "type": "array" 191 | } 192 | }, 193 | "required": [], 194 | "title": "Registry", 195 | "type": "object" 196 | }, 197 | "Relationship": { 198 | "additionalProperties": false, 199 | "description": "", 200 | "properties": { 201 | "ended_at_time": { 202 | "format": "date", 203 | "type": "string" 204 | }, 205 | "related_to": { 206 | "type": "string" 207 | }, 208 | "started_at_time": { 209 | "format": "date", 210 | "type": "string" 211 | }, 212 | "type": { 213 | "type": "string" 214 | } 215 | }, 216 | "required": [], 217 | "title": "Relationship", 218 | "type": "object" 219 | } 220 | }, 221 | "$id": "https://w3id.org/my_org/my_datamodel", 222 | "$schema": "http://json-schema.org/draft-07/schema#", 223 | "additionalProperties": true, 224 | "metamodel_version": "1.7.0", 225 | "properties": { 226 | "organizations": { 227 | "items": { 228 | "$ref": "#/$defs/Organization" 229 | }, 230 | "type": "array" 231 | }, 232 | "persons": { 233 | "items": { 234 | "$ref": "#/$defs/Person" 235 | }, 236 | "type": "array" 237 | } 238 | }, 239 | "required": [], 240 | "title": "my_datamodel", 241 | "type": "object", 242 | "version": null 243 | } 244 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/project/owl/{{cookiecutter.__project_slug}}.owl.ttl: -------------------------------------------------------------------------------- 1 | @prefix IAO: . 2 | @prefix PATO: . 3 | @prefix dcterms: . 4 | @prefix famrel: . 5 | @prefix linkml: . 6 | @prefix my_datamodel: . 7 | @prefix owl: . 8 | @prefix rdf: . 9 | @prefix rdfs: . 10 | @prefix schema: . 11 | @prefix skos: . 12 | @prefix xsd: . 13 | 14 | linkml:SubsetDefinition a owl:Class ; 15 | rdfs:label "subset_definition" . 16 | 17 | linkml:TypeDefinition a owl:Class ; 18 | rdfs:label "type_definition" . 19 | 20 | linkml:topValue a owl:DatatypeProperty ; 21 | rdfs:label "value" . 22 | 23 | my_datamodel: a owl:Ontology ; 24 | rdfs:label "my_datamodel" ; 25 | IAO:0000700 my_datamodel:Address, 26 | my_datamodel:HasAliases, 27 | my_datamodel:NamedThing, 28 | my_datamodel:Registry, 29 | my_datamodel:Relationship ; 30 | dcterms:license "https://creativecommons.org/publicdomain/zero/1.0/" ; 31 | dcterms:title "My Datamodel" ; 32 | rdfs:seeAlso "https://example.org/" ; 33 | linkml:generation_date "2022-09-06T10:01:46" ; 34 | linkml:metamodel_version "1.7.0" ; 35 | linkml:source_file "{{cookiecutter.__project_slug}}.yaml" ; 36 | linkml:source_file_date "2022-09-06T10:00:58" ; 37 | linkml:source_file_size 3771 . 38 | 39 | my_datamodel:employed_at a owl:ObjectProperty, 40 | linkml:SlotDefinition ; 41 | rdfs:label "employed_at" ; 42 | rdfs:range my_datamodel:Organization . 43 | 44 | my_datamodel:is_current a owl:ObjectProperty, 45 | linkml:SlotDefinition ; 46 | rdfs:label "is_current" ; 47 | rdfs:range linkml:Boolean . 48 | 49 | my_datamodel:Registry a owl:Class, 50 | linkml:ClassDefinition ; 51 | rdfs:label "Registry" ; 52 | rdfs:subClassOf [ a owl:Restriction ; 53 | owl:allValuesFrom my_datamodel:Person ; 54 | owl:onProperty my_datamodel:persons ], 55 | [ a owl:Restriction ; 56 | owl:allValuesFrom my_datamodel:Organization ; 57 | owl:onProperty my_datamodel:organizations ] ; 58 | skos:definition "Top level data container" . 59 | 60 | my_datamodel:age_in_years a owl:ObjectProperty, 61 | linkml:SlotDefinition ; 62 | rdfs:label "age_in_years" ; 63 | rdfs:range linkml:Integer . 64 | 65 | my_datamodel:city a owl:ObjectProperty, 66 | linkml:SlotDefinition ; 67 | rdfs:label "city" ; 68 | rdfs:range linkml:String . 69 | 70 | my_datamodel:current_address a owl:ObjectProperty, 71 | linkml:SlotDefinition ; 72 | rdfs:label "current_address" ; 73 | rdfs:range my_datamodel:Address ; 74 | skos:definition "The address at which a person currently lives" . 75 | 76 | my_datamodel:founding_date a owl:ObjectProperty, 77 | linkml:SlotDefinition ; 78 | rdfs:label "founding_date" ; 79 | rdfs:range linkml:String . 80 | 81 | my_datamodel:has_familial_relationships a owl:ObjectProperty, 82 | linkml:SlotDefinition ; 83 | rdfs:label "has_familial_relationships" ; 84 | rdfs:range my_datamodel:FamilialRelationship . 85 | 86 | my_datamodel:mission_statement a owl:ObjectProperty, 87 | linkml:SlotDefinition ; 88 | rdfs:label "mission_statement" ; 89 | rdfs:range linkml:String . 90 | 91 | my_datamodel:organizations a owl:ObjectProperty, 92 | linkml:SlotDefinition ; 93 | rdfs:label "organizations" ; 94 | rdfs:range my_datamodel:Organization . 95 | 96 | my_datamodel:persons a owl:ObjectProperty, 97 | linkml:SlotDefinition ; 98 | rdfs:label "persons" ; 99 | rdfs:range my_datamodel:Person . 100 | 101 | my_datamodel:postal_code a owl:ObjectProperty, 102 | linkml:SlotDefinition ; 103 | rdfs:label "postal_code" ; 104 | rdfs:range linkml:String . 105 | 106 | my_datamodel:street a owl:ObjectProperty, 107 | linkml:SlotDefinition ; 108 | rdfs:label "street" ; 109 | rdfs:range linkml:String . 110 | 111 | famrel:02 a owl:Class, 112 | my_datamodel:FamilialRelationshipType ; 113 | rdfs:label "PARENT_OF" . 114 | 115 | PATO:0001421 a owl:Class, 116 | my_datamodel:PersonStatus ; 117 | rdfs:label "ALIVE" . 118 | 119 | PATO:0001422 a owl:Class, 120 | my_datamodel:PersonStatus ; 121 | rdfs:label "DEAD" . 122 | 123 | schema:birthDate a owl:ObjectProperty, 124 | linkml:SlotDefinition ; 125 | rdfs:label "birth_date" ; 126 | rdfs:range linkml:String ; 127 | skos:exactMatch schema:birthDate . 128 | 129 | schema:description a owl:ObjectProperty, 130 | linkml:SlotDefinition ; 131 | rdfs:label "description" ; 132 | rdfs:range linkml:String ; 133 | skos:exactMatch schema:description . 134 | 135 | schema:email a owl:ObjectProperty, 136 | linkml:SlotDefinition ; 137 | rdfs:label "primary_email" ; 138 | rdfs:range linkml:String ; 139 | skos:exactMatch schema:email . 140 | 141 | schema:identifier a owl:ObjectProperty, 142 | linkml:SlotDefinition ; 143 | rdfs:label "id" ; 144 | rdfs:range linkml:String ; 145 | skos:exactMatch schema:identifier . 146 | 147 | schema:image a owl:ObjectProperty, 148 | linkml:SlotDefinition ; 149 | rdfs:label "image" ; 150 | rdfs:range linkml:String ; 151 | skos:exactMatch schema:image . 152 | 153 | schema:name a owl:ObjectProperty, 154 | linkml:SlotDefinition ; 155 | rdfs:label "name" ; 156 | rdfs:range linkml:String ; 157 | skos:exactMatch schema:name . 158 | 159 | a owl:ObjectProperty, 160 | linkml:SlotDefinition ; 161 | rdfs:label "ended_at_time" ; 162 | rdfs:range linkml:Date ; 163 | skos:exactMatch . 164 | 165 | a owl:ObjectProperty, 166 | linkml:SlotDefinition ; 167 | rdfs:label "started_at_time" ; 168 | rdfs:range linkml:Date ; 169 | skos:exactMatch . 170 | 171 | my_datamodel:FamilialRelationship a owl:Class, 172 | linkml:ClassDefinition ; 173 | rdfs:label "FamilialRelationship" ; 174 | rdfs:subClassOf [ a owl:Restriction ; 175 | owl:onClass my_datamodel:FamilialRelationshipType ; 176 | owl:onProperty my_datamodel:type ; 177 | owl:qualifiedCardinality 1 ], 178 | [ a owl:Restriction ; 179 | owl:onClass my_datamodel:Person ; 180 | owl:onProperty my_datamodel:related_to ; 181 | owl:qualifiedCardinality 1 ], 182 | my_datamodel:Relationship . 183 | 184 | a owl:Class, 185 | my_datamodel:PersonStatus ; 186 | rdfs:label "UNKNOWN" . 187 | 188 | my_datamodel:Relationship a owl:Class, 189 | linkml:ClassDefinition ; 190 | rdfs:label "Relationship" ; 191 | rdfs:subClassOf [ a owl:Restriction ; 192 | owl:maxQualifiedCardinality 1 ; 193 | owl:onClass linkml:String ; 194 | owl:onProperty my_datamodel:related_to ], 195 | [ a owl:Restriction ; 196 | owl:maxQualifiedCardinality 1 ; 197 | owl:onClass linkml:String ; 198 | owl:onProperty my_datamodel:type ], 199 | [ a owl:Restriction ; 200 | owl:maxQualifiedCardinality 1 ; 201 | owl:onClass linkml:Date ; 202 | owl:onProperty ], 203 | [ a owl:Restriction ; 204 | owl:maxQualifiedCardinality 1 ; 205 | owl:onClass linkml:Date ; 206 | owl:onProperty ] . 207 | 208 | my_datamodel:related_to a owl:ObjectProperty, 209 | linkml:SlotDefinition . 210 | 211 | my_datamodel:type a owl:ObjectProperty, 212 | linkml:SlotDefinition ; 213 | rdfs:label "type" ; 214 | rdfs:range linkml:String . 215 | 216 | famrel:01 a owl:Class, 217 | my_datamodel:FamilialRelationshipType ; 218 | rdfs:label "CHILD_OF", 219 | "SIBLING_OF" . 220 | 221 | my_datamodel:Address a owl:Class, 222 | linkml:ClassDefinition ; 223 | rdfs:label "Address" ; 224 | rdfs:subClassOf [ a owl:Restriction ; 225 | owl:maxQualifiedCardinality 1 ; 226 | owl:onClass linkml:String ; 227 | owl:onProperty my_datamodel:city ], 228 | [ a owl:Restriction ; 229 | owl:maxQualifiedCardinality 1 ; 230 | owl:onClass linkml:String ; 231 | owl:onProperty my_datamodel:street ], 232 | [ a owl:Restriction ; 233 | owl:maxQualifiedCardinality 1 ; 234 | owl:onClass linkml:String ; 235 | owl:onProperty my_datamodel:postal_code ] ; 236 | skos:exactMatch schema:PostalAddress . 237 | 238 | my_datamodel:FamilialRelationshipType a owl:Class, 239 | linkml:EnumDefinition ; 240 | rdfs:label "FamilialRelationshipType" ; 241 | owl:unionOf ( famrel:01 famrel:02 famrel:01 ) ; 242 | linkml:permissible_values famrel:01, 243 | famrel:02 . 244 | 245 | my_datamodel:HasAliases a owl:Class, 246 | linkml:ClassDefinition ; 247 | rdfs:label "HasAliases" ; 248 | rdfs:subClassOf [ a owl:Restriction ; 249 | owl:allValuesFrom linkml:String ; 250 | owl:onProperty my_datamodel:aliases ], 251 | linkml:mixin ; 252 | skos:definition "A mixin applied to any class that can have aliases/alternateNames" . 253 | 254 | my_datamodel:NamedThing a owl:Class, 255 | linkml:ClassDefinition ; 256 | rdfs:label "NamedThing" ; 257 | rdfs:subClassOf [ a owl:Restriction ; 258 | owl:maxQualifiedCardinality 1 ; 259 | owl:onClass linkml:String ; 260 | owl:onProperty schema:description ], 261 | [ a owl:Restriction ; 262 | owl:maxQualifiedCardinality 1 ; 263 | owl:onClass linkml:String ; 264 | owl:onProperty schema:name ], 265 | [ a owl:Restriction ; 266 | owl:maxQualifiedCardinality 1 ; 267 | owl:onClass linkml:String ; 268 | owl:onProperty schema:image ], 269 | [ a owl:Restriction ; 270 | owl:onClass linkml:String ; 271 | owl:onProperty schema:identifier ; 272 | owl:qualifiedCardinality 1 ] ; 273 | skos:closeMatch schema:Thing ; 274 | skos:definition "A generic grouping for any identifiable entity" . 275 | 276 | my_datamodel:Organization a owl:Class, 277 | linkml:ClassDefinition ; 278 | rdfs:label "Organization" ; 279 | rdfs:subClassOf [ a owl:Restriction ; 280 | owl:maxQualifiedCardinality 1 ; 281 | owl:onClass linkml:String ; 282 | owl:onProperty my_datamodel:mission_statement ], 283 | [ a owl:Restriction ; 284 | owl:maxQualifiedCardinality 1 ; 285 | owl:onClass linkml:String ; 286 | owl:onProperty my_datamodel:founding_date ], 287 | [ a owl:Restriction ; 288 | owl:allValuesFrom linkml:String ; 289 | owl:onProperty my_datamodel:aliases ], 290 | my_datamodel:HasAliases, 291 | my_datamodel:NamedThing ; 292 | skos:definition "An organization such as a company or university" ; 293 | skos:exactMatch schema:Organization . 294 | 295 | my_datamodel:Person a owl:Class, 296 | linkml:ClassDefinition ; 297 | rdfs:label "Person" ; 298 | rdfs:subClassOf [ a owl:Restriction ; 299 | owl:allValuesFrom linkml:String ; 300 | owl:onProperty my_datamodel:aliases ], 301 | [ a owl:Restriction ; 302 | owl:allValuesFrom my_datamodel:FamilialRelationship ; 303 | owl:onProperty my_datamodel:has_familial_relationships ], 304 | [ a owl:Restriction ; 305 | owl:maxQualifiedCardinality 1 ; 306 | owl:onClass linkml:Integer ; 307 | owl:onProperty my_datamodel:age_in_years ], 308 | [ a owl:Restriction ; 309 | owl:maxQualifiedCardinality 1 ; 310 | owl:onClass my_datamodel:Address ; 311 | owl:onProperty my_datamodel:current_address ], 312 | [ a owl:Restriction ; 313 | owl:maxQualifiedCardinality 1 ; 314 | owl:onClass linkml:String ; 315 | owl:onProperty schema:birthDate ], 316 | [ a owl:Restriction ; 317 | owl:maxQualifiedCardinality 1 ; 318 | owl:onClass linkml:String ; 319 | owl:onProperty schema:email ], 320 | my_datamodel:HasAliases, 321 | my_datamodel:NamedThing ; 322 | skos:definition "A person (alive, dead, undead, or fictional)." ; 323 | skos:exactMatch schema:Person . 324 | 325 | my_datamodel:PersonStatus a owl:Class, 326 | linkml:EnumDefinition ; 327 | rdfs:label "PersonStatus" ; 328 | owl:unionOf ( PATO:0001421 PATO:0001422 ) ; 329 | linkml:permissible_values PATO:0001421, 330 | PATO:0001422, 331 | . 332 | 333 | my_datamodel:aliases a owl:ObjectProperty, 334 | linkml:SlotDefinition ; 335 | rdfs:label "aliases" ; 336 | rdfs:range linkml:String ; 337 | skos:exactMatch schema:alternateName . 338 | 339 | linkml:ClassDefinition a owl:Class ; 340 | rdfs:label "class_definition" . 341 | 342 | linkml:SlotDefinition a owl:Class ; 343 | rdfs:label "slot_definition" . 344 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/project/prefixmap/{{cookiecutter.__project_slug}}.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | { 3 | "PATO": "http://purl.obolibrary.org/obo/PATO_", 4 | "biolink": "https://w3id.org/biolink/", 5 | "famrel": "http://example.org/famrel/", 6 | "linkml": "https://w3id.org/linkml/", 7 | "my_datamodel": "https://w3id.org/my_org/my_datamodel", 8 | "prov": "http://www.w3.org/ns/prov#", 9 | "schema": "http://schema.org/", 10 | "Address": { 11 | "@id": "schema:PostalAddress" 12 | }, 13 | "Organization": { 14 | "@id": "schema:Organization" 15 | }, 16 | "Person": { 17 | "@id": "schema:Person" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/project/protobuf/{{cookiecutter.__project_slug}}.proto: -------------------------------------------------------------------------------- 1 | message Address 2 | { 3 | string street = 0 4 | string city = 0 5 | string postalCode = 0 6 | } 7 | message FamilialRelationship 8 | { 9 | date startedAtTime = 0 10 | date endedAtTime = 0 11 | string relatedTo = 0 12 | familialRelationshipType type = 0 13 | person relatedTo = 0 14 | } 15 | // A generic grouping for any identifiable entity 16 | message NamedThing 17 | { 18 | string id = 0 19 | string name = 0 20 | string description = 0 21 | string image = 0 22 | } 23 | // An organization such as a company or university 24 | message Organization 25 | { 26 | string id = 0 27 | string name = 0 28 | string description = 0 29 | string image = 0 30 | string missionStatement = 0 31 | string foundingDate = 0 32 | repeated string aliases = 0 33 | } 34 | // A person (alive, dead, undead, or fictional). 35 | message Person 36 | { 37 | string id = 0 38 | string name = 0 39 | string description = 0 40 | string image = 0 41 | string primaryEmail = 0 42 | string birthDate = 0 43 | integer ageInYears = 0 44 | address currentAddress = 0 45 | repeated familialRelationship hasFamilialRelationships = 0 46 | repeated string aliases = 0 47 | } 48 | // Top level data container 49 | message Registry 50 | { 51 | repeated person persons = 0 52 | repeated organization organizations = 0 53 | } 54 | message Relationship 55 | { 56 | date startedAtTime = 0 57 | date endedAtTime = 0 58 | string relatedTo = 0 59 | string type = 0 60 | } 61 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/project/shacl/{{cookiecutter.__project_slug}}.shacl.ttl: -------------------------------------------------------------------------------- 1 | @prefix famrel: . 2 | @prefix my_datamodel: . 3 | @prefix rdf: . 4 | @prefix schema: . 5 | @prefix sh: . 6 | @prefix xsd: . 7 | 8 | my_datamodel:HasAliases a sh:NodeShape ; 9 | sh:closed true ; 10 | sh:description "A mixin applied to any class that can have aliases/alternateNames" ; 11 | sh:ignoredProperties ( rdf:type ) ; 12 | sh:property [ sh:order 0 ; 13 | sh:path my_datamodel:aliases ] ; 14 | sh:targetClass my_datamodel:HasAliases . 15 | 16 | my_datamodel:NamedThing a sh:NodeShape ; 17 | sh:closed true ; 18 | sh:description "A generic grouping for any identifiable entity" ; 19 | sh:ignoredProperties ( rdf:type ) ; 20 | sh:property [ sh:maxCount 1 ; 21 | sh:order 0 ; 22 | sh:path schema:identifier ], 23 | [ sh:maxCount 1 ; 24 | sh:order 1 ; 25 | sh:path schema:name ], 26 | [ sh:maxCount 1 ; 27 | sh:order 3 ; 28 | sh:path schema:image ], 29 | [ sh:maxCount 1 ; 30 | sh:order 2 ; 31 | sh:path schema:description ] ; 32 | sh:targetClass my_datamodel:NamedThing . 33 | 34 | my_datamodel:Registry a sh:NodeShape ; 35 | sh:closed true ; 36 | sh:description "Top level data container" ; 37 | sh:ignoredProperties ( rdf:type ) ; 38 | sh:property [ sh:class schema:Person ; 39 | sh:nodeKind sh:IRI ; 40 | sh:order 0 ; 41 | sh:path my_datamodel:persons ], 42 | [ sh:class schema:Organization ; 43 | sh:nodeKind sh:IRI ; 44 | sh:order 1 ; 45 | sh:path my_datamodel:organizations ] ; 46 | sh:targetClass my_datamodel:Registry . 47 | 48 | my_datamodel:Relationship a sh:NodeShape ; 49 | sh:closed true ; 50 | sh:ignoredProperties ( rdf:type ) ; 51 | sh:property [ sh:maxCount 1 ; 52 | sh:order 0 ; 53 | sh:path ], 54 | [ sh:maxCount 1 ; 55 | sh:order 3 ; 56 | sh:path my_datamodel:type ], 57 | [ sh:maxCount 1 ; 58 | sh:order 2 ; 59 | sh:path my_datamodel:related_to ], 60 | [ sh:maxCount 1 ; 61 | sh:order 1 ; 62 | sh:path ] ; 63 | sh:targetClass my_datamodel:Relationship . 64 | 65 | schema:Organization a sh:NodeShape ; 66 | sh:closed true ; 67 | sh:description "An organization such as a company or university" ; 68 | sh:ignoredProperties ( rdf:type ) ; 69 | sh:property [ sh:maxCount 1 ; 70 | sh:order 1 ; 71 | sh:path my_datamodel:founding_date ], 72 | [ sh:maxCount 1 ; 73 | sh:order 5 ; 74 | sh:path schema:description ], 75 | [ sh:order 2 ; 76 | sh:path my_datamodel:aliases ], 77 | [ sh:maxCount 1 ; 78 | sh:order 6 ; 79 | sh:path schema:image ], 80 | [ sh:maxCount 1 ; 81 | sh:order 0 ; 82 | sh:path my_datamodel:mission_statement ], 83 | [ sh:maxCount 1 ; 84 | sh:order 3 ; 85 | sh:path schema:identifier ], 86 | [ sh:maxCount 1 ; 87 | sh:order 4 ; 88 | sh:path schema:name ] ; 89 | sh:targetClass schema:Organization . 90 | 91 | schema:Person a sh:NodeShape ; 92 | sh:closed true ; 93 | sh:description "A person (alive, dead, undead, or fictional)." ; 94 | sh:ignoredProperties ( rdf:type ) ; 95 | sh:property [ sh:maxCount 1 ; 96 | sh:order 6 ; 97 | sh:path schema:identifier ], 98 | [ sh:maxCount 1 ; 99 | sh:order 8 ; 100 | sh:path schema:description ], 101 | [ sh:maxCount 1 ; 102 | sh:order 9 ; 103 | sh:path schema:image ], 104 | [ sh:maxCount 1 ; 105 | sh:order 0 ; 106 | sh:path schema:email ; 107 | sh:pattern "^\\S+@[\\S+\\.]+\\S+" ], 108 | [ sh:maxCount 1 ; 109 | sh:maxInclusive 999 ; 110 | sh:minInclusive 0 ; 111 | sh:order 2 ; 112 | sh:path my_datamodel:age_in_years ], 113 | [ sh:class schema:PostalAddress ; 114 | sh:description "The address at which a person currently lives" ; 115 | sh:maxCount 1 ; 116 | sh:nodeKind sh:BlankNode ; 117 | sh:order 3 ; 118 | sh:path my_datamodel:current_address ], 119 | [ sh:class my_datamodel:FamilialRelationship ; 120 | sh:nodeKind sh:BlankNode ; 121 | sh:order 4 ; 122 | sh:path my_datamodel:has_familial_relationships ], 123 | [ sh:maxCount 1 ; 124 | sh:order 1 ; 125 | sh:path schema:birthDate ], 126 | [ sh:maxCount 1 ; 127 | sh:order 7 ; 128 | sh:path schema:name ], 129 | [ sh:order 5 ; 130 | sh:path my_datamodel:aliases ] ; 131 | sh:targetClass schema:Person . 132 | 133 | schema:PostalAddress a sh:NodeShape ; 134 | sh:closed true ; 135 | sh:ignoredProperties ( rdf:type ) ; 136 | sh:property [ sh:maxCount 1 ; 137 | sh:order 1 ; 138 | sh:path my_datamodel:city ], 139 | [ sh:maxCount 1 ; 140 | sh:order 2 ; 141 | sh:path my_datamodel:postal_code ], 142 | [ sh:maxCount 1 ; 143 | sh:order 0 ; 144 | sh:path my_datamodel:street ] ; 145 | sh:targetClass schema:PostalAddress . 146 | 147 | my_datamodel:FamilialRelationship a sh:NodeShape ; 148 | sh:closed true ; 149 | sh:ignoredProperties ( rdf:type ) ; 150 | sh:property [ sh:maxCount 1 ; 151 | sh:order 1 ; 152 | sh:path ], 153 | [ sh:maxCount 1 ; 154 | sh:order 0 ; 155 | sh:path ], 156 | [ sh:in ( famrel:01 famrel:02 famrel:01 ) ; 157 | sh:maxCount 1 ; 158 | sh:minCount 1 ; 159 | sh:order 3 ; 160 | sh:path my_datamodel:type ], 161 | [ sh:maxCount 1 ; 162 | sh:order 2 ; 163 | sh:path my_datamodel:related_to ] ; 164 | sh:targetClass my_datamodel:FamilialRelationship . 165 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/project/shex/{{cookiecutter.__project_slug}}.shex: -------------------------------------------------------------------------------- 1 | BASE 2 | PREFIX rdf: 3 | PREFIX xsd: 4 | PREFIX linkml: 5 | PREFIX schema: 6 | PREFIX prov: 7 | 8 | 9 | linkml:String xsd:string 10 | 11 | linkml:Integer xsd:integer 12 | 13 | linkml:Boolean xsd:boolean 14 | 15 | linkml:Float xsd:float 16 | 17 | linkml:Double xsd:double 18 | 19 | linkml:Decimal xsd:decimal 20 | 21 | linkml:Time xsd:dateTime 22 | 23 | linkml:Date xsd:date 24 | 25 | linkml:Datetime xsd:dateTime 26 | 27 | linkml:DateOrDatetime linkml:DateOrDatetime 28 | 29 | linkml:Uriorcurie IRI 30 | 31 | linkml:Uri IRI 32 | 33 | linkml:Ncname xsd:string 34 | 35 | linkml:Objectidentifier IRI 36 | 37 | linkml:Nodeidentifier NONLITERAL 38 | 39 | CLOSED { 40 | ( $ ( @linkml:String ? ; 41 | @linkml:String ? ; 42 | @linkml:String ? 43 | ) ; 44 | rdf:type [ schema:PostalAddress ] ? 45 | ) 46 | } 47 | 48 | CLOSED { 49 | ( $ ( & ; 50 | rdf:type [ ] ? ; 51 | @ ; 52 | @ 53 | ) ; 54 | rdf:type [ ] ? 55 | ) 56 | } 57 | 58 | { 59 | ( $ @linkml:String * ; 60 | rdf:type [ ] ? 61 | ) 62 | } 63 | 64 | ( 65 | CLOSED { 66 | ( $ ( schema:name @linkml:String ? ; 67 | schema:description @linkml:String ? ; 68 | schema:image @linkml:String ? 69 | ) ; 70 | rdf:type [ ] 71 | ) 72 | } OR @ OR @ 73 | ) 74 | 75 | CLOSED { 76 | ( $ ( & ; 77 | rdf:type [ ] ? ; 78 | & ; 79 | rdf:type [ ] ? ; 80 | @linkml:String ? ; 81 | @linkml:String ? ; 82 | @linkml:String * 83 | ) ; 84 | rdf:type [ schema:Organization ] 85 | ) 86 | } 87 | 88 | CLOSED { 89 | ( $ ( & ; 90 | rdf:type [ ] ? ; 91 | & ; 92 | rdf:type [ ] ? ; 93 | schema:email @linkml:String ? ; 94 | schema:birthDate @linkml:String ? ; 95 | @linkml:Integer ? ; 96 | @ ? ; 97 | 98 | @ * ; 99 | @linkml:String * 100 | ) ; 101 | rdf:type [ schema:Person ] 102 | ) 103 | } 104 | 105 | CLOSED { 106 | ( $ ( 107 | @ * ; 108 | @ * 109 | ) ; 110 | rdf:type [ ] ? 111 | ) 112 | } 113 | 114 | ( 115 | CLOSED { 116 | ( $ ( prov:startedAtTime @linkml:Date ? ; 117 | prov:endedAtTime @linkml:Date ? ; 118 | @linkml:String ? ; 119 | @linkml:String ? 120 | ) ; 121 | rdf:type [ ] ? 122 | ) 123 | } OR @ 124 | ) 125 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/project/sqlschema/{{cookiecutter.__project_slug}}.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE "Address" ( 2 | street TEXT, 3 | city TEXT, 4 | postal_code TEXT, 5 | PRIMARY KEY (street, city, postal_code) 6 | ); 7 | 8 | CREATE TABLE "NamedThing" ( 9 | id TEXT NOT NULL, 10 | name TEXT, 11 | description TEXT, 12 | image TEXT, 13 | PRIMARY KEY (id) 14 | ); 15 | 16 | CREATE TABLE "Organization" ( 17 | id TEXT NOT NULL, 18 | name TEXT, 19 | description TEXT, 20 | image TEXT, 21 | mission_statement TEXT, 22 | founding_date TEXT, 23 | PRIMARY KEY (id) 24 | ); 25 | 26 | CREATE TABLE "Person" ( 27 | id TEXT NOT NULL, 28 | name TEXT, 29 | description TEXT, 30 | image TEXT, 31 | primary_email TEXT, 32 | birth_date TEXT, 33 | age_in_years INTEGER, 34 | current_address TEXT, 35 | PRIMARY KEY (id) 36 | ); 37 | 38 | CREATE TABLE "Registry" ( 39 | persons TEXT, 40 | organizations TEXT, 41 | PRIMARY KEY (persons, organizations) 42 | ); 43 | 44 | CREATE TABLE "Relationship" ( 45 | started_at_time DATE, 46 | ended_at_time DATE, 47 | related_to TEXT, 48 | type TEXT, 49 | PRIMARY KEY (started_at_time, ended_at_time, related_to, type) 50 | ); 51 | 52 | CREATE TABLE "FamilialRelationship" ( 53 | started_at_time DATE, 54 | ended_at_time DATE, 55 | related_to TEXT NOT NULL, 56 | type VARCHAR(10) NOT NULL, 57 | "Person_id" TEXT, 58 | PRIMARY KEY (started_at_time, ended_at_time, related_to, type, "Person_id"), 59 | FOREIGN KEY(related_to) REFERENCES "Person" (id), 60 | FOREIGN KEY("Person_id") REFERENCES "Person" (id) 61 | ); 62 | 63 | CREATE TABLE "Organization_aliases" ( 64 | backref_id TEXT, 65 | aliases TEXT, 66 | PRIMARY KEY (backref_id, aliases), 67 | FOREIGN KEY(backref_id) REFERENCES "Organization" (id) 68 | ); 69 | 70 | CREATE TABLE "Person_aliases" ( 71 | backref_id TEXT, 72 | aliases TEXT, 73 | PRIMARY KEY (backref_id, aliases), 74 | FOREIGN KEY(backref_id) REFERENCES "Person" (id) 75 | ); 76 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning"] 3 | build-backend = "poetry_dynamic_versioning.backend" 4 | 5 | [project] 6 | name = "{{cookiecutter.__project_slug}}" 7 | description = "{{cookiecutter.project_description}}" 8 | authors = [ 9 | {name = "{{cookiecutter.full_name}}", email = "{{cookiecutter.email}}"}, 10 | ] 11 | license = "{{cookiecutter.license}}" 12 | readme = "README.md" 13 | include = ["README.md", "src/{{cookiecutter.__project_slug}}/schema", "project"] 14 | 15 | requires-python = ">=3.9,<4.0" 16 | 17 | dynamic = ["version"] 18 | 19 | dependencies = [ 20 | "linkml-runtime >=1.1.24", 21 | ] 22 | 23 | [tool.poetry] 24 | requires-poetry = ">=2.0" 25 | version = "0.0.0" 26 | 27 | [tool.poetry.requires-plugins] 28 | poetry-dynamic-versioning = ">=1.5.2" 29 | 30 | [tool.poetry-dynamic-versioning] 31 | enable = true 32 | vcs = "git" 33 | style = "pep440" 34 | 35 | [tool.poetry.group.dev.dependencies] 36 | linkml = ">=1.3.5" 37 | mkdocs-material = ">=8.2.8" 38 | mkdocs-mermaid2-plugin = ">=1.1.1" 39 | schemasheets = ">=0.1.14" 40 | jupyter = ">=1.0.0" 41 | mknotebooks = ">= 0.8.0" 42 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/src/data/examples/invalid/{{cookiecutter.main_schema_class}}-001.yaml: -------------------------------------------------------------------------------- 1 | # Example for an invalid data object 2 | --- 3 | id: "001" 4 | name: foo bar 5 | primary_email: not-an-email-address 6 | age_in_years: 33 7 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/src/data/examples/valid/{{cookiecutter.main_schema_class}}-001.yaml: -------------------------------------------------------------------------------- 1 | # Example for a valid data object 2 | --- 3 | id: "001" 4 | name: foo bar 5 | primary_email: foo.bar@example.com 6 | age_in_years: 33 7 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/src/docs/files/about.md: -------------------------------------------------------------------------------- 1 | # {{cookiecutter.project_name}} 2 | 3 | {{cookiecutter.project_description}} 4 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/src/docs/templates/README.md: -------------------------------------------------------------------------------- 1 | Use this folder to store templates to modify the generated documentation. The templates are written in Jinja2 and are used to generate the HTML documentation for the schema. 2 | 3 | The default templates are stored in the linkml repository at https://github.com/linkml/linkml/tree/main/linkml/generators/docgen. If you want to use these as a starting point, you can copy them into this folder and modify them as needed. -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/src/{{cookiecutter.__project_slug}}/_version.py: -------------------------------------------------------------------------------- 1 | from importlib.metadata import version, PackageNotFoundError 2 | 3 | try: 4 | __version__ = version(__name__) 5 | except PackageNotFoundError: 6 | # package not installed 7 | __version__ = "0.0.0" 8 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/src/{{cookiecutter.__project_slug}}/datamodel/__init__.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from .{{cookiecutter.__project_slug}} import * 3 | 4 | THIS_PATH = Path(__file__).parent 5 | 6 | SCHEMA_DIRECTORY = THIS_PATH.parent / "schema" 7 | MAIN_SCHEMA_PATH = SCHEMA_DIRECTORY / "{{cookiecutter.__project_slug}}.yaml" 8 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/src/{{cookiecutter.__project_slug}}/datamodel/{{cookiecutter.__project_slug}}.py: -------------------------------------------------------------------------------- 1 | # Auto generated from {{cookiecutter.__project_slug}}.yaml by pythongen.py version: 0.9.0 2 | # Generation date: 2022-09-06T10:01:50 3 | # Schema: my_datamodel 4 | # 5 | # id: https://w3id.org/my_org/my_datamodel 6 | # description: Enter a detailed description of your project here 7 | # license: https://creativecommons.org/publicdomain/zero/1.0/ 8 | 9 | import dataclasses 10 | import re 11 | from jsonasobj2 import as_dict 12 | from typing import Optional, List, Union, Dict, ClassVar, Any 13 | from dataclasses import dataclass 14 | from linkml_runtime.linkml_model.meta import EnumDefinition, PermissibleValue 15 | 16 | from linkml_runtime.utils.slot import Slot 17 | from linkml_runtime.utils.metamodelcore import empty_list, empty_dict 18 | from linkml_runtime.utils.yamlutils import YAMLRoot, extended_str 19 | from linkml_runtime.utils.dataclass_extensions_376 import dataclasses_init_fn_with_kwargs 20 | from linkml_runtime.utils.enumerations import EnumDefinitionImpl 21 | from rdflib import URIRef 22 | from linkml_runtime.utils.curienamespace import CurieNamespace 23 | from linkml_runtime.utils.metamodelcore import Bool, XSDDate 24 | 25 | metamodel_version = "1.7.0" 26 | version = None 27 | 28 | # Overwrite dataclasses _init_fn to add **kwargs in __init__ 29 | dataclasses._init_fn = dataclasses_init_fn_with_kwargs 30 | 31 | # Namespaces 32 | PATO = CurieNamespace('PATO', 33 | 'http://purl.obolibrary.org/obo/PATO_') 34 | BIOLINK = CurieNamespace('biolink', 35 | 'https://w3id.org/biolink/') 36 | FAMREL = CurieNamespace('famrel', 37 | 'http://example.org/famrel/') 38 | LINKML = CurieNamespace('linkml', 39 | 'https://w3id.org/linkml/') 40 | MY_DATAMODEL = CurieNamespace('my_datamodel', 41 | 'https://w3id.org/my_org/my_datamodel') 42 | PROV = CurieNamespace('prov', 43 | 'http://www.w3.org/ns/prov#') 44 | SCHEMA = CurieNamespace('schema', 45 | 'http://schema.org/') 46 | DEFAULT_ = MY_DATAMODEL 47 | 48 | # Types 49 | 50 | 51 | # Class references 52 | class NamedThingId(extended_str): 53 | pass 54 | 55 | 56 | class PersonId(NamedThingId): 57 | pass 58 | 59 | 60 | class OrganizationId(NamedThingId): 61 | pass 62 | 63 | 64 | @dataclass 65 | class Registry(YAMLRoot): 66 | """ 67 | Top level data container 68 | """ 69 | _inherited_slots: ClassVar[List[str]] = [] 70 | 71 | class_class_uri: ClassVar[URIRef] = MY_DATAMODEL.Registry 72 | class_class_curie: ClassVar[str] = "my_datamodel:Registry" 73 | class_name: ClassVar[str] = "Registry" 74 | class_model_uri: ClassVar[URIRef] = MY_DATAMODEL.Registry 75 | 76 | persons: Optional[Union[ 77 | Dict[Union[str, PersonId], Union[dict, "Person"]], 78 | List[Union[dict, "Person"]] 79 | ]] = empty_dict() 80 | 81 | organizations: Optional[Union[ 82 | Dict[Union[str, OrganizationId], Union[dict, "Organization"]], 83 | List[Union[dict, "Organization"]] 84 | ]] = empty_dict() 85 | 86 | def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]): 87 | self._normalize_inlined_as_list( 88 | slot_name="persons", 89 | slot_type=Person, 90 | key_name="id", 91 | keyed=True 92 | ) 93 | 94 | self._normalize_inlined_as_list( 95 | slot_name="organizations", 96 | slot_type=Organization, 97 | key_name="id", 98 | keyed=True 99 | ) 100 | 101 | super().__post_init__(**kwargs) 102 | 103 | 104 | @dataclass 105 | class NamedThing(YAMLRoot): 106 | """ 107 | A generic grouping for any identifiable entity 108 | """ 109 | _inherited_slots: ClassVar[List[str]] = [] 110 | 111 | class_class_uri: ClassVar[URIRef] = MY_DATAMODEL.NamedThing 112 | class_class_curie: ClassVar[str] = "my_datamodel:NamedThing" 113 | class_name: ClassVar[str] = "NamedThing" 114 | class_model_uri: ClassVar[URIRef] = MY_DATAMODEL.NamedThing 115 | 116 | id: Union[str, NamedThingId] = None 117 | name: Optional[str] = None 118 | description: Optional[str] = None 119 | image: Optional[str] = None 120 | 121 | def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]): 122 | if self._is_empty(self.id): 123 | self.MissingRequiredField("id") 124 | if not isinstance(self.id, NamedThingId): 125 | self.id = NamedThingId(self.id) 126 | 127 | if self.name is not None and not isinstance(self.name, str): 128 | self.name = str(self.name) 129 | 130 | if self.description is not None \ 131 | and not isinstance(self.description, str): 132 | self.description = str(self.description) 133 | 134 | if self.image is not None and not isinstance(self.image, str): 135 | self.image = str(self.image) 136 | 137 | super().__post_init__(**kwargs) 138 | 139 | 140 | @dataclass 141 | class Person(NamedThing): 142 | """ 143 | A person (alive, dead, undead, or fictional). 144 | """ 145 | _inherited_slots: ClassVar[List[str]] = [] 146 | 147 | class_class_uri: ClassVar[URIRef] = SCHEMA.Person 148 | class_class_curie: ClassVar[str] = "schema:Person" 149 | class_name: ClassVar[str] = "Person" 150 | class_model_uri: ClassVar[URIRef] = MY_DATAMODEL.Person 151 | 152 | id: Union[str, PersonId] = None 153 | primary_email: Optional[str] = None 154 | birth_date: Optional[str] = None 155 | age_in_years: Optional[int] = None 156 | current_address: Optional[Union[dict, "Address"]] = None 157 | has_familial_relationships: Optional[Union[ 158 | Union[dict, "FamilialRelationship"], 159 | List[Union[dict, "FamilialRelationship"]] 160 | ]] = empty_list() 161 | aliases: Optional[Union[str, List[str]]] = empty_list() 162 | 163 | def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]): 164 | if self._is_empty(self.id): 165 | self.MissingRequiredField("id") 166 | if not isinstance(self.id, PersonId): 167 | self.id = PersonId(self.id) 168 | 169 | if self.primary_email is not None \ 170 | and not isinstance(self.primary_email, str): 171 | self.primary_email = str(self.primary_email) 172 | 173 | if self.birth_date is not None \ 174 | and not isinstance(self.birth_date, str): 175 | self.birth_date = str(self.birth_date) 176 | 177 | if self.age_in_years is not None \ 178 | and not isinstance(self.age_in_years, int): 179 | self.age_in_years = int(self.age_in_years) 180 | 181 | if self.current_address is not None \ 182 | and not isinstance(self.current_address, Address): 183 | self.current_address = Address(**as_dict(self.current_address)) 184 | 185 | if not isinstance(self.has_familial_relationships, list): 186 | self.has_familial_relationships = [self.has_familial_relationships] \ 187 | if self.has_familial_relationships is not None \ 188 | else [] 189 | self.has_familial_relationships = [ 190 | v if isinstance(v, FamilialRelationship) 191 | else FamilialRelationship(**as_dict(v)) 192 | for v in self.has_familial_relationships] 193 | 194 | if not isinstance(self.aliases, list): 195 | self.aliases = [self.aliases] if self.aliases is not None else [] 196 | self.aliases = [v if isinstance(v, str) else str(v) 197 | for v in self.aliases] 198 | 199 | super().__post_init__(**kwargs) 200 | 201 | 202 | @dataclass 203 | class HasAliases(YAMLRoot): 204 | """ 205 | A mixin applied to any class that can have aliases/alternateNames 206 | """ 207 | _inherited_slots: ClassVar[List[str]] = [] 208 | 209 | class_class_uri: ClassVar[URIRef] = MY_DATAMODEL.HasAliases 210 | class_class_curie: ClassVar[str] = "my_datamodel:HasAliases" 211 | class_name: ClassVar[str] = "HasAliases" 212 | class_model_uri: ClassVar[URIRef] = MY_DATAMODEL.HasAliases 213 | 214 | aliases: Optional[Union[str, List[str]]] = empty_list() 215 | 216 | def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]): 217 | if not isinstance(self.aliases, list): 218 | self.aliases = [self.aliases] if self.aliases is not None else [] 219 | self.aliases = [v if isinstance(v, str) else str(v) 220 | for v in self.aliases] 221 | 222 | super().__post_init__(**kwargs) 223 | 224 | 225 | @dataclass 226 | class Organization(NamedThing): 227 | """ 228 | An organization such as a company or university 229 | """ 230 | _inherited_slots: ClassVar[List[str]] = [] 231 | 232 | class_class_uri: ClassVar[URIRef] = SCHEMA.Organization 233 | class_class_curie: ClassVar[str] = "schema:Organization" 234 | class_name: ClassVar[str] = "Organization" 235 | class_model_uri: ClassVar[URIRef] = MY_DATAMODEL.Organization 236 | 237 | id: Union[str, OrganizationId] = None 238 | mission_statement: Optional[str] = None 239 | founding_date: Optional[str] = None 240 | aliases: Optional[Union[str, List[str]]] = empty_list() 241 | 242 | def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]): 243 | if self._is_empty(self.id): 244 | self.MissingRequiredField("id") 245 | if not isinstance(self.id, OrganizationId): 246 | self.id = OrganizationId(self.id) 247 | 248 | if self.mission_statement is not None \ 249 | and not isinstance(self.mission_statement, str): 250 | self.mission_statement = str(self.mission_statement) 251 | 252 | if self.founding_date is not None \ 253 | and not isinstance(self.founding_date, str): 254 | self.founding_date = str(self.founding_date) 255 | 256 | if not isinstance(self.aliases, list): 257 | self.aliases = [self.aliases] if self.aliases is not None else [] 258 | self.aliases = [v if isinstance(v, str) else str(v) 259 | for v in self.aliases] 260 | 261 | super().__post_init__(**kwargs) 262 | 263 | 264 | @dataclass 265 | class Address(YAMLRoot): 266 | _inherited_slots: ClassVar[List[str]] = [] 267 | 268 | class_class_uri: ClassVar[URIRef] = SCHEMA.PostalAddress 269 | class_class_curie: ClassVar[str] = "schema:PostalAddress" 270 | class_name: ClassVar[str] = "Address" 271 | class_model_uri: ClassVar[URIRef] = MY_DATAMODEL.Address 272 | 273 | street: Optional[str] = None 274 | city: Optional[str] = None 275 | postal_code: Optional[str] = None 276 | 277 | def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]): 278 | if self.street is not None and not isinstance(self.street, str): 279 | self.street = str(self.street) 280 | 281 | if self.city is not None and not isinstance(self.city, str): 282 | self.city = str(self.city) 283 | 284 | if self.postal_code is not None \ 285 | and not isinstance(self.postal_code, str): 286 | self.postal_code = str(self.postal_code) 287 | 288 | super().__post_init__(**kwargs) 289 | 290 | 291 | @dataclass 292 | class Relationship(YAMLRoot): 293 | _inherited_slots: ClassVar[List[str]] = [] 294 | 295 | class_class_uri: ClassVar[URIRef] = MY_DATAMODEL.Relationship 296 | class_class_curie: ClassVar[str] = "my_datamodel:Relationship" 297 | class_name: ClassVar[str] = "Relationship" 298 | class_model_uri: ClassVar[URIRef] = MY_DATAMODEL.Relationship 299 | 300 | started_at_time: Optional[Union[str, XSDDate]] = None 301 | ended_at_time: Optional[Union[str, XSDDate]] = None 302 | related_to: Optional[str] = None 303 | type: Optional[str] = None 304 | 305 | def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]): 306 | if self.started_at_time is not None \ 307 | and not isinstance(self.started_at_time, XSDDate): 308 | self.started_at_time = XSDDate(self.started_at_time) 309 | 310 | if self.ended_at_time is not None \ 311 | and not isinstance(self.ended_at_time, XSDDate): 312 | self.ended_at_time = XSDDate(self.ended_at_time) 313 | 314 | if self.related_to is not None \ 315 | and not isinstance(self.related_to, str): 316 | self.related_to = str(self.related_to) 317 | 318 | if self.type is not None and not isinstance(self.type, str): 319 | self.type = str(self.type) 320 | 321 | super().__post_init__(**kwargs) 322 | 323 | 324 | @dataclass 325 | class FamilialRelationship(Relationship): 326 | _inherited_slots: ClassVar[List[str]] = [] 327 | 328 | class_class_uri: ClassVar[URIRef] = MY_DATAMODEL.FamilialRelationship 329 | class_class_curie: ClassVar[str] = "my_datamodel:FamilialRelationship" 330 | class_name: ClassVar[str] = "FamilialRelationship" 331 | class_model_uri: ClassVar[URIRef] = MY_DATAMODEL.FamilialRelationship 332 | 333 | type: Union[str, "FamilialRelationshipType"] = None 334 | related_to: Union[str, PersonId] = None 335 | 336 | def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]): 337 | if self._is_empty(self.type): 338 | self.MissingRequiredField("type") 339 | if not isinstance(self.type, FamilialRelationshipType): 340 | self.type = FamilialRelationshipType(self.type) 341 | 342 | if self._is_empty(self.related_to): 343 | self.MissingRequiredField("related_to") 344 | if not isinstance(self.related_to, PersonId): 345 | self.related_to = PersonId(self.related_to) 346 | 347 | super().__post_init__(**kwargs) 348 | 349 | 350 | # Enumerations 351 | class PersonStatus(EnumDefinitionImpl): 352 | 353 | ALIVE = PermissibleValue(text="ALIVE", 354 | description="the person is living", 355 | meaning=PATO["0001421"]) 356 | DEAD = PermissibleValue(text="DEAD", 357 | description="the person is deceased", 358 | meaning=PATO["0001422"]) 359 | UNKNOWN = PermissibleValue(text="UNKNOWN", 360 | description="the vital status is not known") 361 | 362 | _defn = EnumDefinition( 363 | name="PersonStatus", 364 | ) 365 | 366 | 367 | class FamilialRelationshipType(EnumDefinitionImpl): 368 | 369 | SIBLING_OF = PermissibleValue(text="SIBLING_OF", 370 | meaning=FAMREL["01"]) 371 | PARENT_OF = PermissibleValue(text="PARENT_OF", 372 | meaning=FAMREL["02"]) 373 | CHILD_OF = PermissibleValue(text="CHILD_OF", 374 | meaning=FAMREL["01"]) 375 | 376 | _defn = EnumDefinition( 377 | name="FamilialRelationshipType", 378 | ) 379 | 380 | 381 | # Slots 382 | class slots: 383 | pass 384 | 385 | 386 | slots.id = Slot( 387 | uri=SCHEMA.identifier, 388 | name="id", 389 | curie=SCHEMA.curie('identifier'), 390 | model_uri=MY_DATAMODEL.id, 391 | domain=None, 392 | range=URIRef 393 | ) 394 | 395 | slots.name = Slot( 396 | uri=SCHEMA.name, 397 | name="name", 398 | curie=SCHEMA.curie('name'), 399 | model_uri=MY_DATAMODEL.name, 400 | domain=None, 401 | range=Optional[str] 402 | ) 403 | 404 | slots.description = Slot( 405 | uri=SCHEMA.description, 406 | name="description", 407 | curie=SCHEMA.curie('description'), 408 | model_uri=MY_DATAMODEL.description, 409 | domain=None, 410 | range=Optional[str] 411 | ) 412 | 413 | slots.image = Slot( 414 | uri=SCHEMA.image, 415 | name="image", 416 | curie=SCHEMA.curie('image'), 417 | model_uri=MY_DATAMODEL.image, 418 | domain=None, 419 | range=Optional[str] 420 | ) 421 | 422 | slots.primary_email = Slot( 423 | uri=SCHEMA.email, 424 | name="primary_email", 425 | curie=SCHEMA.curie('email'), 426 | model_uri=MY_DATAMODEL.primary_email, 427 | domain=None, 428 | range=Optional[str] 429 | ) 430 | 431 | slots.birth_date = Slot( 432 | uri=SCHEMA.birthDate, 433 | name="birth_date", 434 | curie=SCHEMA.curie('birthDate'), 435 | model_uri=MY_DATAMODEL.birth_date, 436 | domain=None, 437 | range=Optional[str] 438 | ) 439 | 440 | slots.employed_at = Slot( 441 | uri=MY_DATAMODEL.employed_at, 442 | name="employed_at", 443 | curie=MY_DATAMODEL.curie('employed_at'), 444 | model_uri=MY_DATAMODEL.employed_at, 445 | domain=None, 446 | range=Optional[Union[str, OrganizationId]] 447 | ) 448 | 449 | slots.is_current = Slot( 450 | uri=MY_DATAMODEL.is_current, 451 | name="is_current", 452 | curie=MY_DATAMODEL.curie('is_current'), 453 | model_uri=MY_DATAMODEL.is_current, 454 | domain=None, 455 | range=Optional[Union[bool, Bool]] 456 | ) 457 | 458 | slots.has_familial_relationships = Slot( 459 | uri=MY_DATAMODEL.has_familial_relationships, 460 | name="has_familial_relationships", 461 | curie=MY_DATAMODEL.curie('has_familial_relationships'), 462 | model_uri=MY_DATAMODEL.has_familial_relationships, 463 | domain=None, 464 | range=Optional[Union[ 465 | Union[dict, FamilialRelationship], 466 | List[Union[dict, FamilialRelationship]] 467 | ]] 468 | ) 469 | 470 | slots.current_address = Slot( 471 | uri=MY_DATAMODEL.current_address, name="current_address", 472 | curie=MY_DATAMODEL.curie('current_address'), 473 | model_uri=MY_DATAMODEL.current_address, domain=None, 474 | range=Optional[Union[dict, Address]] 475 | ) 476 | 477 | slots.age_in_years = Slot( 478 | uri=MY_DATAMODEL.age_in_years, name="age_in_years", 479 | curie=MY_DATAMODEL.curie('age_in_years'), 480 | model_uri=MY_DATAMODEL.age_in_years, domain=None, range=Optional[int] 481 | ) 482 | 483 | slots.related_to = Slot( 484 | uri=MY_DATAMODEL.related_to, 485 | name="related_to", 486 | curie=MY_DATAMODEL.curie('related_to'), 487 | model_uri=MY_DATAMODEL.related_to, 488 | domain=None, 489 | range=Optional[str] 490 | ) 491 | 492 | slots.type = Slot( 493 | uri=MY_DATAMODEL.type, 494 | name="type", 495 | curie=MY_DATAMODEL.curie('type'), 496 | model_uri=MY_DATAMODEL.type, 497 | domain=None, 498 | range=Optional[str] 499 | ) 500 | 501 | slots.street = Slot( 502 | uri=MY_DATAMODEL.street, 503 | name="street", 504 | curie=MY_DATAMODEL.curie('street'), 505 | model_uri=MY_DATAMODEL.street, 506 | domain=None, 507 | range=Optional[str] 508 | ) 509 | 510 | slots.city = Slot( 511 | uri=MY_DATAMODEL.city, 512 | name="city", 513 | curie=MY_DATAMODEL.curie('city'), 514 | model_uri=MY_DATAMODEL.city, 515 | domain=None, 516 | range=Optional[str] 517 | ) 518 | 519 | slots.mission_statement = Slot( 520 | uri=MY_DATAMODEL.mission_statement, 521 | name="mission_statement", 522 | curie=MY_DATAMODEL.curie('mission_statement'), 523 | model_uri=MY_DATAMODEL.mission_statement, 524 | domain=None, 525 | range=Optional[str] 526 | ) 527 | 528 | slots.founding_date = Slot( 529 | uri=MY_DATAMODEL.founding_date, 530 | name="founding_date", 531 | curie=MY_DATAMODEL.curie('founding_date'), 532 | model_uri=MY_DATAMODEL.founding_date, 533 | domain=None, 534 | range=Optional[str] 535 | ) 536 | 537 | slots.postal_code = Slot( 538 | uri=MY_DATAMODEL.postal_code, 539 | name="postal_code", 540 | curie=MY_DATAMODEL.curie('postal_code'), 541 | model_uri=MY_DATAMODEL.postal_code, 542 | domain=None, 543 | range=Optional[str] 544 | ) 545 | 546 | slots.started_at_time = Slot( 547 | uri=PROV.startedAtTime, 548 | name="started_at_time", 549 | curie=PROV.curie('startedAtTime'), 550 | model_uri=MY_DATAMODEL.started_at_time, 551 | domain=None, 552 | range=Optional[Union[str, XSDDate]] 553 | ) 554 | 555 | slots.ended_at_time = Slot( 556 | uri=PROV.endedAtTime, 557 | name="ended_at_time", 558 | curie=PROV.curie('endedAtTime'), 559 | model_uri=MY_DATAMODEL.ended_at_time, 560 | domain=None, 561 | range=Optional[Union[str, XSDDate]] 562 | ) 563 | 564 | slots.registry__persons = Slot( 565 | uri=MY_DATAMODEL.persons, 566 | name="registry__persons", 567 | curie=MY_DATAMODEL.curie('persons'), 568 | model_uri=MY_DATAMODEL.registry__persons, 569 | domain=None, 570 | range=Optional[Union[ 571 | Dict[Union[str, PersonId], Union[dict, Person]], 572 | List[Union[dict, Person]] 573 | ]] 574 | ) 575 | 576 | slots.registry__organizations = Slot( 577 | uri=MY_DATAMODEL.organizations, 578 | name="registry__organizations", 579 | curie=MY_DATAMODEL.curie('organizations'), 580 | model_uri=MY_DATAMODEL.registry__organizations, 581 | domain=None, 582 | range=Optional[Union[ 583 | Dict[Union[str, OrganizationId], Union[dict, Organization]], 584 | List[Union[dict, Organization]] 585 | ]] 586 | ) 587 | 588 | slots.hasAliases__aliases = Slot( 589 | uri=MY_DATAMODEL.aliases, 590 | name="hasAliases__aliases", 591 | curie=MY_DATAMODEL.curie('aliases'), 592 | model_uri=MY_DATAMODEL.hasAliases__aliases, 593 | domain=None, 594 | range=Optional[Union[str, List[str]]] 595 | ) 596 | 597 | slots.related_to = Slot( 598 | uri=MY_DATAMODEL.related_to, 599 | name="related to", 600 | curie=MY_DATAMODEL.curie('related_to'), 601 | model_uri=MY_DATAMODEL.related_to, 602 | domain=None, 603 | range=Union[str, PersonId] 604 | ) 605 | 606 | slots.Person_primary_email = Slot( 607 | uri=SCHEMA.email, 608 | name="Person_primary_email", 609 | curie=SCHEMA.curie('email'), 610 | model_uri=MY_DATAMODEL.Person_primary_email, 611 | domain=Person, 612 | range=Optional[str], 613 | pattern=re.compile(r'^\S+@[\S+\.]+\S+') 614 | ) 615 | 616 | slots.FamilialRelationship_type = Slot( 617 | uri=MY_DATAMODEL.type, 618 | name="FamilialRelationship_type", 619 | curie=MY_DATAMODEL.curie('type'), 620 | model_uri=MY_DATAMODEL.FamilialRelationship_type, 621 | domain=FamilialRelationship, 622 | range=Union[str, "FamilialRelationshipType"] 623 | ) 624 | 625 | slots.FamilialRelationship_related_to = Slot( 626 | uri=MY_DATAMODEL.related_to, 627 | name="FamilialRelationship_related to", 628 | curie=MY_DATAMODEL.curie('related_to'), 629 | model_uri=MY_DATAMODEL.FamilialRelationship_related_to, 630 | domain=FamilialRelationship, 631 | range=Union[str, PersonId] 632 | ) 633 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/src/{{cookiecutter.__project_slug}}/schema/{{cookiecutter.__project_slug}}.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | id: https://w3id.org/{{cookiecutter.github_org}}/{{cookiecutter.project_name}} 3 | name: {{cookiecutter.project_name}} 4 | title: {{cookiecutter.project_name}} 5 | description: |- 6 | {{cookiecutter.project_description}} 7 | license: {{cookiecutter.license}} 8 | see_also: 9 | - https://{{cookiecutter.github_org}}.github.io/{{cookiecutter.project_name}} 10 | 11 | prefixes: 12 | {{cookiecutter.__project_slug}}: https://w3id.org/{{cookiecutter.github_org}}/{{cookiecutter.project_name}}/ 13 | linkml: https://w3id.org/linkml/ 14 | biolink: https://w3id.org/biolink/ 15 | schema: http://schema.org/ 16 | PATO: http://purl.obolibrary.org/obo/PATO_ 17 | example: https://example.org/ 18 | default_prefix: {{cookiecutter.__project_slug}} 19 | default_range: string 20 | 21 | imports: 22 | - linkml:types 23 | {%- if cookiecutter.use_schemasheets == "Yes" %} 24 | - {{cookiecutter.__google_sheet_module}} 25 | {%- else %} 26 | 27 | classes: 28 | 29 | NamedThing: 30 | description: >- 31 | A generic grouping for any identifiable entity 32 | slots: 33 | - id 34 | - name 35 | - description 36 | class_uri: schema:Thing 37 | 38 | {{cookiecutter.main_schema_class}}: 39 | is_a: NamedThing 40 | description: >- 41 | Represents a {{cookiecutter.main_schema_class}} 42 | slots: 43 | - primary_email 44 | - birth_date 45 | - age_in_years 46 | - vital_status 47 | slot_usage: 48 | primary_email: 49 | pattern: "^\\S+@[\\S+\\.]+\\S+" 50 | 51 | {{cookiecutter.main_schema_class}}Collection: 52 | tree_root: true 53 | description: >- 54 | A holder for {{cookiecutter.main_schema_class}} objects 55 | attributes: 56 | entries: 57 | range: {{cookiecutter.main_schema_class}} 58 | multivalued: true 59 | inlined: true 60 | 61 | slots: 62 | id: 63 | identifier: true 64 | slot_uri: schema:identifier 65 | range: uriorcurie 66 | description: A unique identifier for a thing 67 | name: 68 | slot_uri: schema:name 69 | description: A human-readable name for a thing 70 | description: 71 | slot_uri: schema:description 72 | description: A human-readable description for a thing 73 | primary_email: 74 | slot_uri: schema:email 75 | description: The main email address of a person 76 | birth_date: 77 | slot_uri: schema:birthDate 78 | range: date 79 | description: Date on which a person is born 80 | age_in_years: 81 | range: integer 82 | description: Number of years since birth 83 | vital_status: 84 | range: PersonStatus 85 | description: living or dead status 86 | 87 | enums: 88 | PersonStatus: 89 | permissible_values: 90 | ALIVE: 91 | description: the person is living 92 | meaning: PATO:0001421 93 | DEAD: 94 | description: the person is deceased 95 | meaning: PATO:0001422 96 | UNKNOWN: 97 | description: the vital status is not known 98 | todos: 99 | - map this to an ontology 100 | {%- endif %} 101 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/tablesort.js: -------------------------------------------------------------------------------- 1 | document$.subscribe(function() { 2 | var tables = document.querySelectorAll("article table:not([class])") 3 | tables.forEach(function(table) { 4 | new Tablesort(table) 5 | }) 6 | }) -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/tests/__init__.py: -------------------------------------------------------------------------------- 1 | """Tests for {{cookiecutter.project_name}}.""" 2 | -------------------------------------------------------------------------------- /{{cookiecutter.project_name}}/tests/test_data.py: -------------------------------------------------------------------------------- 1 | """Data test.""" 2 | import os 3 | import glob 4 | import unittest 5 | 6 | from linkml_runtime.loaders import yaml_loader 7 | from {{cookiecutter.__project_slug}}.datamodel.{{cookiecutter.__project_slug}} import {{cookiecutter.main_schema_class}}Collection 8 | 9 | ROOT = os.path.join(os.path.dirname(__file__), '..') 10 | DATA_DIR = os.path.join(ROOT, "src", "data", "examples") 11 | 12 | EXAMPLE_FILES = glob.glob(os.path.join(DATA_DIR, '*.yaml')) 13 | 14 | 15 | class TestData(unittest.TestCase): 16 | """Test data and datamodel.""" 17 | 18 | def test_data(self): 19 | """Data test.""" 20 | for path in EXAMPLE_FILES: 21 | obj = yaml_loader.load(path, target_class={{cookiecutter.main_schema_class}}Collection) 22 | assert obj 23 | --------------------------------------------------------------------------------