├── .clang-format ├── .github ├── dependabot.yml └── workflows │ └── tests.yml ├── .gitignore ├── .pre-commit-config.yaml ├── LICENSE ├── README.md ├── copier.yml ├── extensions └── context.py ├── noxfile.py ├── pyproject.toml ├── requirements.txt ├── scripts └── update-projects.py ├── template ├── .github │ └── workflows │ │ └── tests.yml.jinja ├── .gitignore ├── .pre-commit-config.yaml ├── CODE_OF_CONDUCT.md.jinja ├── CONTRIBUTING.md.jinja ├── LICENSE.jinja ├── README.md.jinja ├── noxfile.py.jinja ├── pyproject.toml.jinja ├── readthedocs.yaml ├── setup.py.jinja ├── src │ ├── {%if enable_pybind11%}lib{%endif%} │ │ └── main.cpp.jinja │ └── {{python_package_import_name}} │ │ └── __init__.py.jinja ├── tests │ └── .gitkeep ├── {% if documentation_enable %}docs{% endif %} │ ├── .gitignore │ ├── Makefile.jinja │ ├── _static │ │ ├── README.md │ │ └── logo.svg │ ├── conf.py.jinja │ ├── index.md.jinja │ └── license.md.jinja ├── {%if enable_mypy%}mypy.ini{%endif%} ├── {%if enable_pybind11%}.clang-format{%endif%} ├── {%if enable_pybind11%}CMakeLists.txt{%endif%}.jinja ├── {%if enable_pybind11%}MANIFEST.in{%endif%} └── {{_copier_conf.answers_file}}.jinja └── tests ├── test_basic.py └── test_compiled.py /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | ColumnLimit: 99 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "pip" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | tags: 8 | - "*" 9 | pull_request: 10 | 11 | jobs: 12 | tests: 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | nox-session: 17 | - tests 18 | - docs 19 | - compiled 20 | - generated 21 | - build 22 | - lint 23 | old: [false] 24 | include: 25 | - nox-session: tests 26 | old: true 27 | - nox-session: compiled 28 | old: true 29 | - nox-session: build 30 | old: true 31 | 32 | steps: 33 | - name: Checkout 34 | uses: actions/checkout@v2 35 | with: 36 | fetch-depth: 0 37 | - name: Configure git 38 | run: | 39 | git config --global user.email "gh-actions" 40 | git config --global user.name "gh-actions" 41 | git config --global init.defaultBranch main 42 | - name: Configure Python 3.7 43 | if: ${{ matrix.old }} 44 | uses: actions/setup-python@v4 45 | with: 46 | python-version: "3.7" 47 | - name: Configure Python 3.10 48 | if: ${{ !matrix.old }} 49 | uses: actions/setup-python@v4 50 | with: 51 | python-version: "3.10" 52 | - name: Cache pip packages 53 | uses: actions/cache@v3 54 | with: 55 | path: ~/.cache/pip 56 | key: pip-${{ matrix.nox-session }}-${{ matrix.old }}-${{ hashFiles('**/requirements.txt') }}-${{ hashFiles('**/noxfile.py') }} 57 | restore-keys: | 58 | pip-${{ matrix.nox-session }}-${{ matrix.old }} 59 | - name: Cache nox session files 60 | uses: actions/cache@v3 61 | with: 62 | path: .nox 63 | key: nox-${{ matrix.nox-session }}-${{ matrix.old }}-${{ hashFiles('noxfile.py') }} 64 | restore-keys: | 65 | nox-${{ matrix.nox-session }}-${{ matrix.old }}- 66 | - name: Cache pre-commit environments 67 | if: ${{ matrix.nox-session == 'lint' || matrix.nox-session == 'generated' }} 68 | uses: actions/cache@v3 69 | with: 70 | path: ~/.cache/pre-commit 71 | key: pre-commit-${{ matrix.nox-session }}-${{ matrix.old }}-${{ hashFiles('.pre-commit-config.yaml') }} 72 | restore-keys: | 73 | pre-commit-${{ matrix.nox-session }}-${{ matrix.old }}- 74 | - name: Install dependencies 75 | run: | 76 | python -m pip install -U pip 77 | python -m pip install -U nox plumbum 78 | - name: Optionally install old version of setuptools and pip 79 | if: ${{ matrix.old }} 80 | run: python -m pip install pip==21.1.3 setuptools==57.4.0 81 | - name: Run tests 82 | run: python -m nox --non-interactive -s ${{ matrix.nox-session }} 83 | env: 84 | SYSTEM_SITE_PACKAGES: ${{ matrix.old }} 85 | 86 | update-projects: 87 | if: ${{ startsWith(github.ref, 'refs/tags/') }} 88 | needs: tests 89 | runs-on: ubuntu-latest 90 | steps: 91 | - name: Checkout 92 | uses: actions/checkout@v2 93 | with: 94 | fetch-depth: 0 95 | - name: Configure Python 96 | uses: actions/setup-python@v4 97 | with: 98 | python-version: "3.10" 99 | - name: Cache pip packages 100 | uses: actions/cache@v3 101 | with: 102 | path: ~/.cache/pip 103 | key: pip-update-${{ hashFiles('**/requirements.txt') }} 104 | restore-keys: | 105 | pip-update- 106 | - name: Install dependencies 107 | run: | 108 | python -m pip install -U pip 109 | python -m pip install -r requirements.txt 110 | - name: Update projects 111 | run: python scripts/update-projects.py 112 | env: 113 | GITHUB_PAT: ${{ secrets.GH_PAT }} 114 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .mypy_cache 2 | .pytest_cache 3 | .vscode 4 | .nox 5 | demo.generated 6 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.1.0 4 | hooks: 5 | - id: trailing-whitespace 6 | - id: end-of-file-fixer 7 | exclude_types: [json, binary] 8 | - repo: https://github.com/PyCQA/isort 9 | rev: "5.10.1" 10 | hooks: 11 | - id: isort 12 | additional_dependencies: [toml] 13 | - repo: https://github.com/psf/black 14 | rev: "22.6.0" 15 | hooks: 16 | - id: black-jupyter 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Warning:** Not yet ready for general use. 2 | 3 | This is a [Copier](https://copier.readthedocs.io) template for a Python project 4 | that I'm hoping to use to centralize the packaging infrastructure for a lot of 5 | my projects. 6 | -------------------------------------------------------------------------------- /copier.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Dan Foreman-Mackey 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | _min_copier_version: "6.0.0" 16 | _envops: 17 | autoescape: false 18 | block_end_string: "%}" 19 | block_start_string: "{%" 20 | comment_end_string: "#}" 21 | comment_start_string: "{#" 22 | keep_trailing_newline: true 23 | variable_end_string: "}}" 24 | variable_start_string: "{{" 25 | _subdirectory: template 26 | _templates_suffix: .jinja 27 | _jinja_extensions: 28 | - copier_templates_extensions.TemplateExtensionLoader 29 | - extensions/context.py:ContextUpdater 30 | _skip_if_exists: 31 | - README.md 32 | - src/**/*.py 33 | - src/**/*.cpp 34 | - tests/**/*.py 35 | - docs/index.md 36 | - docs/_static/**/* 37 | _tasks: 38 | - rm tests/.gitkeep 39 | - git init 40 | - git add . 41 | - pre-commit run --all-files || pre-commit run --all-files 42 | 43 | # ------------------------ # 44 | # General project settings # 45 | # ------------------------ # 46 | 47 | project_name: 48 | type: str 49 | help: Your project name 50 | 51 | project_description: 52 | type: str 53 | help: Your project description 54 | 55 | author_fullname: 56 | type: str 57 | help: Your full name 58 | default: "Dan Foreman-Mackey" 59 | 60 | author_email: 61 | type: str 62 | help: Your email 63 | default: "foreman.mackey@gmail.com" 64 | 65 | copyright_holder: 66 | type: str 67 | help: The name of the person/entity holding the copyright 68 | default: "{{ author_fullname }}" 69 | 70 | copyright_year: 71 | type: str 72 | help: The copyright year 73 | default: "2022" 74 | 75 | copyright_license: 76 | type: str 77 | help: Your project's license 78 | default: Apache 79 | choices: 80 | - Apache 81 | - MIT 82 | - BSD 83 | 84 | code_of_conduct_email: 85 | type: str 86 | help: The email contact for code of conduct inquiries 87 | default: "{{ author_email }}" 88 | 89 | # ------------- # 90 | # Project flags # 91 | # ------------- # 92 | 93 | project_line_length: 94 | type: int 95 | help: The line length to be used with auto formatting 96 | default: 79 97 | 98 | enable_mypy: 99 | type: bool 100 | help: Use mypy for typing support 101 | default: no 102 | 103 | enable_pybind11: 104 | type: bool 105 | help: Enable pybind11 for Python bindings 106 | default: no 107 | 108 | enable_windows: 109 | type: bool 110 | help: Enable testing and building on Windows 111 | default: yes 112 | 113 | # --------------- # 114 | # Repository info # 115 | # --------------- # 116 | 117 | repository_namespace: 118 | type: str 119 | help: Your repository namespace on GitHub 120 | default: "{{ author_username }}" 121 | 122 | repository_name: 123 | type: str 124 | help: Your repository name on GitHub 125 | default: "{{ project_name|lower|replace('_', '-')|replace(' ', '-') }}" 126 | 127 | # ------------------- # 128 | # Documentation setup # 129 | # ------------------- # 130 | 131 | documentation_enable: 132 | type: bool 133 | help: Include docs using sphinx 134 | default: no 135 | 136 | readthedocs_project_name: 137 | type: str 138 | help: The subdomain on readthedocs where the documentation is hosted (optionally) 139 | default: "{{ project_name|lower|replace('_', '-')|replace(' ', '-') }}" 140 | 141 | documentation_url: 142 | type: str 143 | help: The URL for the documentation 144 | default: "https://{{ readthedocs_project_name }}.readthedocs.io" 145 | 146 | documentation_sphinx_theme: 147 | type: str 148 | help: The name of the Sphinx theme to use 149 | default: "sphinx_book_theme" 150 | 151 | documentation_build_type: 152 | type: str 153 | help: The type of Sphinx build to use 154 | default: "dirhtml" 155 | 156 | documentation_logo_filename: 157 | type: str 158 | help: The filename of the image to use for the logo 159 | default: "logo.svg" 160 | 161 | documentation_favicon_filename: 162 | type: str 163 | help: The filename of the image to use for the favicon 164 | default: "{{ documentation_logo_filename }}" 165 | 166 | documentation_enable_execution: 167 | type: bool 168 | help: Enable execution of Jupyter notebooks as pages 169 | default: yes 170 | 171 | documentation_enable_binder: 172 | type: bool 173 | help: Enable the Binder integration 174 | default: "{{ documentation_enable_execution }}" 175 | 176 | documentation_enable_colab: 177 | type: bool 178 | help: Enable the Google Colab integration 179 | default: "{{ documentation_enable_execution }}" 180 | 181 | documentation_execution_dependencies: 182 | type: str 183 | help: A comma-separated and quoted list of dependencies required to build the documentation 184 | default: "" 185 | 186 | documentation_execution_excludepatterns: 187 | type: str 188 | help: Comma separated and quoted list of patterns to exclude from notebook execution 189 | default: "" 190 | 191 | # ------------------------ # 192 | # Python-specific settings # 193 | # ------------------------ # 194 | 195 | python_package_distribution_name: 196 | type: str 197 | help: Your Python package distribution name (for `pip install NAME`) 198 | default: "{{ project_name|lower|replace('_', '-')|replace(' ', '-') }}" 199 | 200 | python_package_import_name: 201 | type: str 202 | help: Your Python package import name (for `import NAME` in Python code) 203 | default: "{{ project_name|lower|replace('-', '_')|replace(' ', '_') }}" 204 | 205 | project_development_status: 206 | type: str 207 | help: The development status of the project, to be listed on PyPI 208 | default: "beta" 209 | choices: 210 | - alpha 211 | - beta 212 | - stable 213 | - mature 214 | - inactive 215 | 216 | python_min_version: 217 | type: int 218 | help: The minimum Python (minor) version tested by the project 219 | default: 7 220 | 221 | python_max_version: 222 | type: int 223 | help: The maximum Python (minor) version tested by the project 224 | default: 10 225 | 226 | python_formal_min_version: 227 | type: int 228 | help: The formal minimum Python (minor) version required for the project 229 | default: "{{ python_min_version }}" 230 | 231 | python_test_dependencies: 232 | type: str 233 | help: A comma-separated and quoted list of dependencies required for testing; pytest is already included 234 | default: "" 235 | 236 | python_optional_dependencies: 237 | type: str 238 | help: A pipe-separated list of optional dependencies; these will verbatim be added as lines to pyproject.toml 239 | default: "" 240 | 241 | # ----------------------- # 242 | # GitHub Actions settings # 243 | # ----------------------- # 244 | 245 | python_nox_sessions: 246 | type: str 247 | help: A comma-separated list of nox sessions to be tested on all Python versions 248 | default: '"tests"' 249 | 250 | general_nox_sessions: 251 | type: str 252 | help: A comma-separated list of nox sessions to be tested on the most recent Python version 253 | default: '"lint"' 254 | -------------------------------------------------------------------------------- /extensions/context.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Dan Foreman-Mackey 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from datetime import datetime 16 | 17 | from copier_templates_extensions import ContextHook 18 | 19 | 20 | class ContextUpdater(ContextHook): 21 | def hook(self, context): 22 | try: 23 | start_year = int(context["copyright_year"]) 24 | except ValueError: 25 | return {"copyright_range": context["copyright_year"]} 26 | end_year = datetime.now().year 27 | if start_year >= end_year: 28 | return {"copyright_range": f"{start_year}"} 29 | return {"copyright_range": f"{start_year}-{end_year}"} 30 | -------------------------------------------------------------------------------- /noxfile.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Dan Foreman-Mackey 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import os 16 | from contextlib import contextmanager 17 | from pathlib import Path 18 | from tempfile import TemporaryDirectory 19 | 20 | import nox 21 | from plumbum import local 22 | 23 | cp = local["cp"] 24 | git = local["git"] 25 | rm = local["rm"] 26 | 27 | ACTIONLINT_URL = "https://raw.githubusercontent.com/rhysd/actionlint/v1.6.15/scripts/download-actionlint.bash" 28 | 29 | nox_session = nox.session( 30 | venv_params=["--system-site-packages"] 31 | if os.environ.get("SYSTEM_SITE_PACKAGES", None) == "true" 32 | else None 33 | ) 34 | 35 | 36 | def generate_in(session, target, *args): 37 | session.install("-r", "requirements.txt") 38 | all_files = git("ls-tree", "--name-only", "HEAD").splitlines() 39 | # First copy the template to a temporary directory and install from there 40 | with TemporaryDirectory() as template: 41 | for file in all_files: 42 | cp("-r", file, template) 43 | 44 | # Tag a 'test' release in this temporary directory 45 | with local.cwd(template): 46 | git("init", ".") 47 | git("add", ".") 48 | git( 49 | "commit", 50 | "--message=test", 51 | "--author=Test", 52 | "--no-verify", 53 | ) 54 | git("tag", "--force", "test") 55 | 56 | # Generate the copy from the temporary copy 57 | session.run( 58 | "copier", 59 | "-f", 60 | template, 61 | target, 62 | "-d", 63 | 'project_name="dfm test package"', 64 | *args 65 | ) 66 | 67 | # Set up the copy as a git repository for SCM purposes 68 | with local.cwd(target): 69 | git("init", ".") 70 | git("add", ".") 71 | 72 | 73 | @contextmanager 74 | def generate(session, *args): 75 | with TemporaryDirectory() as d: 76 | generate_in(session, d, *args) 77 | yield d 78 | 79 | 80 | @contextmanager 81 | def install(session, *args): 82 | with generate(session, *args) as d: 83 | with session.chdir(d): 84 | session.install( 85 | "--upgrade", 86 | "--upgrade-strategy", 87 | "eager", 88 | "--no-cache-dir", 89 | ".", 90 | silent=False, 91 | ) 92 | 93 | yield d 94 | 95 | 96 | @nox_session 97 | def tests(session): 98 | session.install("pytest") 99 | with install(session): 100 | session.run("pytest", "-v", "tests/test_basic.py") 101 | 102 | 103 | @nox_session 104 | def compiled(session): 105 | session.install("pytest") 106 | with install(session, "-d", "enable_pybind11=yes"): 107 | session.run("pytest", "-v", "tests/test_compiled.py") 108 | 109 | 110 | @nox_session 111 | def docs(session): 112 | with generate(session, "-d", "documentation_enable=yes") as d: 113 | with session.chdir(d): 114 | session.install(".[docs]") 115 | with session.chdir("docs"): 116 | session.run("make", external=True) 117 | 118 | 119 | @nox.session 120 | def setuptools(session): 121 | session.install("pytest") 122 | session.install("pip", "setuptools<58.3.0") # Old version used on RTDs 123 | session.install( 124 | *"mock==1.0.1 pillow==5.4.1 alabaster>=0.7,<0.8,!=0.7.5 commonmark==0.8.1 recommonmark==0.5.0 sphinx<2 sphinx-rtd-theme<0.5 readthedocs-sphinx-ext<2.2 jinja2<3.1.0 setuptools<58.3.0".split() 125 | ) 126 | session.run("pip", "--version") 127 | with install(session): 128 | session.run("pytest", "-v", "tests/test_basic.py") 129 | 130 | 131 | @nox.session 132 | def corner(session): 133 | session.install("pip", "setuptools<58.3.0") # Old version used on RTDs 134 | session.install( 135 | *"mock==1.0.1 pillow==5.4.1 alabaster>=0.7,<0.8,!=0.7.5 commonmark==0.8.1 recommonmark==0.5.0 sphinx<2 sphinx-rtd-theme<0.5 readthedocs-sphinx-ext<2.2 jinja2<3.1.0 setuptools<58.3.0".split() 136 | ) 137 | session.run("pip", "--version") 138 | with TemporaryDirectory() as d: 139 | git("clone", "https://github.com/dfm/corner.py", d) 140 | with local.cwd(d): 141 | git("checkout", "template") 142 | print(local["ls"]()) 143 | with session.chdir(d): 144 | session.install(".", silent=False) 145 | 146 | 147 | @nox.session 148 | def generated(session): 149 | # Install actionlint in the virtualenv 150 | with local.cwd(session._runner.venv.bin): 151 | cmd = local["curl"][ACTIONLINT_URL] | local["bash"] 152 | cmd() 153 | 154 | # Run the tests in the generated project 155 | session.install("nox") 156 | with generate(session) as d: 157 | 158 | with open(Path(d) / "tests" / "test_import.py", "w") as f: 159 | f.write( 160 | """ 161 | def test_import(): 162 | import dfm_test_package 163 | """ 164 | ) 165 | 166 | with session.chdir(d): 167 | session.run("actionlint", external="error") 168 | session.run("nox") 169 | 170 | 171 | @nox_session 172 | @nox.parametrize("compiled", [True, False]) 173 | def build(session, compiled): 174 | session.install("build", "twine") 175 | args = ("-d", "enable_pybind11=yes") if compiled else () 176 | with generate(session, *args) as d: 177 | with session.chdir(d): 178 | session.run("python", "-m", "build") 179 | session.run("python", "-m", "twine", "check", "--strict", "dist/*") 180 | 181 | with generate(session) as d: 182 | with session.chdir(d): 183 | session.run("python", "-m", "build") 184 | session.run("python", "-m", "twine", "check", "--strict", "dist/*") 185 | 186 | 187 | @nox.session 188 | def lint(session): 189 | session.install("pre-commit") 190 | session.run("pre-commit", "run", "--all-files") 191 | 192 | 193 | @nox.session 194 | def update_pre_commit(session): 195 | session.install("pre-commit") 196 | session.run( 197 | "pre-commit", "autoupdate", "-c", "template/.pre-commit-config.yaml" 198 | ) 199 | 200 | 201 | @nox.session 202 | def demo(session): 203 | rm("-rf", "demo.generated") 204 | generate_in(session, "demo.generated", *session.posargs) 205 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | line-length = 79 3 | 4 | [tool.isort] 5 | skip_glob = [] 6 | line_length = 79 7 | multi_line_output = 3 8 | include_trailing_comma = true 9 | force_grid_wrap = 0 10 | use_parentheses = true 11 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | nox==2022.11.21 2 | pre-commit==2.20.0 3 | copier==7.0.1 4 | copier-templates-extensions==0.3.0 5 | plumbum==1.8.0 6 | PyGithub==1.56 7 | -------------------------------------------------------------------------------- /scripts/update-projects.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Dan Foreman-Mackey 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import os 16 | import re 17 | from tempfile import TemporaryDirectory 18 | 19 | import github 20 | import plumbum 21 | from plumbum import local 22 | 23 | git = local["git"] 24 | python = local["python"] 25 | api = github.Github(os.environ["GITHUB_PAT"]) 26 | 27 | 28 | def search_repos(): 29 | done = set() 30 | for file in api.search_code('"gh:dfm/copier-python"'): 31 | if file.path != ".copier-answers.yml": 32 | continue 33 | repo = file.repository 34 | name = repo.full_name 35 | if name in done: 36 | continue 37 | done.add(name) 38 | update_repo(file.repository) 39 | 40 | 41 | def has_diff(*args): 42 | try: 43 | git("diff", "--quiet", *args, retcode=1) 44 | except plumbum.ProcessExecutionError: 45 | return False 46 | else: 47 | return True 48 | 49 | 50 | def is_dirty(): 51 | if git("status", "--porcelain", "-unormal").strip(): 52 | return True 53 | if has_diff(): 54 | return True 55 | if has_diff("--staged"): 56 | return True 57 | return False 58 | 59 | 60 | def update_branch(clone_url): 61 | with TemporaryDirectory() as d: 62 | clone_url = clone_url.replace( 63 | "https://", f"https://dfm:{os.environ['GITHUB_PAT']}@" 64 | ) 65 | git("clone", clone_url, d) 66 | with local.cwd(d): 67 | # Force update of the template 68 | result = python["-m", "copier", "--force", "update"].run() 69 | assert result[0] == 0 70 | copier_log = result[2] 71 | 72 | # Parse the log to find the updated version number 73 | versions = re.findall( 74 | "Updating to template version (.*)", copier_log 75 | ) 76 | if not versions: 77 | raise RuntimeError( 78 | f"Could not find version in copier log:\n{copier_log}" 79 | ) 80 | version = versions[0] 81 | 82 | if not is_dirty(): 83 | print("No changes.") 84 | return None 85 | 86 | # Check out the new branch 87 | branch = f"copier/{version}" 88 | git("checkout", "-b", branch) 89 | git("add", ".") 90 | git("config", "user.email", "dfm@dfm.io") 91 | git("config", "user.name", "Dan F-M") 92 | git( 93 | "commit", 94 | f"--message=Updating template to {version}\n\n{copier_log}", 95 | ) 96 | git("push", "--force", "origin", branch) 97 | return version, branch, copier_log 98 | 99 | 100 | def update_repo(repo): 101 | print(f"Updating {repo.full_name}...") 102 | if not repo.permissions.push: 103 | print("Don't have push access; skipping.") 104 | 105 | update = update_branch(repo.clone_url) 106 | if update is None: 107 | return 108 | version, branch, log = update 109 | 110 | try: 111 | repo.create_pull( 112 | title=f"[copier] Updating template to version {version}", 113 | body=f"""**This is an automated PR from https://github.com/dfm/copier-python** 114 | 115 | This updates the template to version {version}. If there are merge conflicts, 116 | they will be indicated with `*.rej` files that will be committed to this branch. 117 | In this case, the `lint` workflow will fail, and you will need to resolve these 118 | conflicts manually: 119 | 120 | ```bash 121 | git checkout -b {branch} origin/{branch} 122 | # Fix the conflicts and commit 123 | git push origin {branch} 124 | ``` 125 | 126 | Full update log below: 127 | 128 |
129 | Copier log 130 | 131 | ``` 132 | {log} 133 | ``` 134 |
135 | """, 136 | base=repo.default_branch, 137 | head=branch, 138 | ) 139 | except github.GithubException.GithubException: 140 | print("PR already exists; skipping.") 141 | 142 | 143 | if __name__ == "__main__": 144 | search_repos() 145 | -------------------------------------------------------------------------------- /template/.github/workflows/tests.yml.jinja: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | tags: 8 | - "*" 9 | pull_request: 10 | workflow_dispatch: 11 | inputs: 12 | prerelease: 13 | description: 'Run a pre-release, testing the build' 14 | required: false 15 | type: boolean 16 | default: false 17 | 18 | jobs: 19 | tests: 20 | runs-on: {{ '${{ matrix.os }}' }} 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | os: ["ubuntu-latest"] 25 | python-version: [{% for n in range(python_min_version, python_max_version) %}"3.{{n}}", {% endfor %}"3.{{python_max_version}}"] 26 | nox-session: [{{ python_nox_sessions }}] 27 | include: 28 | {% for s in python_nox_sessions.split(',') -%} 29 | - os: macos-latest 30 | python-version: "3.{{ python_max_version }}" 31 | nox-session: {{ s }} 32 | {% endfor %}{% if enable_windows %}{% for s in python_nox_sessions.split(',') -%} 33 | - os: windows-latest 34 | python-version: "3.{{ python_max_version }}" 35 | nox-session: {{ s }} 36 | {% endfor %}{% endif %}{% for s in general_nox_sessions.split(',') -%} 37 | - os: ubuntu-latest 38 | python-version: "3.{{ python_max_version }}" 39 | nox-session: {{ s }} 40 | {% endfor %} 41 | steps: 42 | - name: Checkout 43 | uses: actions/checkout@v3 44 | with: 45 | submodules: true 46 | fetch-depth: 0 47 | - name: Configure Python 48 | uses: actions/setup-python@v4 49 | with: 50 | python-version: {{ '${{ matrix.python-version }}' }} 51 | - name: Cache pip packages 52 | uses: actions/cache@v3 53 | with: 54 | path: ~/.cache/pip 55 | key: {{ "${{ runner.os }}-pip-${{ matrix.nox-session }}-${{ hashFiles('**/noxfile.py') }}" }} 56 | restore-keys: | 57 | {{ '${{ runner.os }}-pip-${{ matrix.nox-session }}-' }} 58 | - name: Cache nox session files 59 | uses: actions/cache@v3 60 | with: 61 | path: .nox 62 | key: {{ "${{ runner.os }}-nox-${{ matrix.nox-session }}-${{ hashFiles('**/noxfile.py') }}" }} 63 | restore-keys: | 64 | {{ '${{ runner.os }}-nox-${{ matrix.nox-session }}-' }} 65 | - name: Cache pre-commit environments 66 | if: {{ "${{ matrix.nox-session == 'lint' }}" }} 67 | uses: actions/cache@v3 68 | with: 69 | path: ~/.cache/pre-commit 70 | key: {{ "${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}" }} 71 | restore-keys: | 72 | {{ '${{ runner.os }}-pre-commit-' }} 73 | - name: Install nox 74 | run: | 75 | python -m pip install -U pip 76 | python -m pip install -U nox 77 | - name: Run tests 78 | run: python -m nox --non-interactive -s {{ '${{ matrix.nox-session }}' }} 79 | 80 | release: 81 | if: {{ '${{' }} inputs.prerelease || startsWith(github.ref, 'refs/tags/') {{ '}}' }} 82 | needs: tests 83 | uses: dfm/workflows/.github/workflows/python-release.yml@v0.1.0 84 | with: 85 | wheels: {{ enable_pybind11|lower }} 86 | enable-windows: {{ enable_windows|lower }} 87 | secrets: 88 | pypi-token: {{ '${{ secrets.pypi_password }}' }} 89 | -------------------------------------------------------------------------------- /template/.gitignore: -------------------------------------------------------------------------------- 1 | /src/*/version.py 2 | *.pyc 3 | __pycache__ 4 | *.egg-info 5 | _skbuild 6 | *.so 7 | .mypy_cache 8 | .tox 9 | .nox 10 | .coverage 11 | .coverage* 12 | dist 13 | build 14 | -------------------------------------------------------------------------------- /template/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: local 3 | hooks: 4 | - id: forbidden-files 5 | name: forbidden files 6 | entry: found copier update rejection files; review them and remove them 7 | language: fail 8 | files: "\\.rej$" 9 | - repo: https://github.com/pre-commit/pre-commit-hooks 10 | rev: "v4.3.0" 11 | hooks: 12 | - id: trailing-whitespace 13 | - id: end-of-file-fixer 14 | exclude_types: [json, binary] 15 | exclude: ".copier-answers.yml" 16 | - id: check-yaml 17 | - repo: https://github.com/PyCQA/isort 18 | rev: "5.10.1" 19 | hooks: 20 | - id: isort 21 | additional_dependencies: [toml] 22 | - repo: https://github.com/psf/black 23 | rev: "22.6.0" 24 | hooks: 25 | - id: black-jupyter 26 | - repo: https://github.com/kynan/nbstripout 27 | rev: "0.6.0" 28 | hooks: 29 | - id: nbstripout 30 | -------------------------------------------------------------------------------- /template/CODE_OF_CONDUCT.md.jinja: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, caste, color, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | - Demonstrating empathy and kindness toward other people 21 | - Being respectful of differing opinions, viewpoints, and experiences 22 | - Giving and gracefully accepting constructive feedback 23 | - Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | - Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | - The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | - Trolling, insulting or derogatory comments, and personal or political attacks 33 | - Public or private harassment 34 | - Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | - Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | {{ code_of_conduct_email }}. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | [https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0]. 120 | 121 | Community Impact Guidelines were inspired by 122 | [Mozilla's code of conduct enforcement ladder][mozilla coc]. 123 | 124 | For answers to common questions about this code of conduct, see the FAQ at 125 | [https://www.contributor-covenant.org/faq][faq]. Translations are available 126 | at [https://www.contributor-covenant.org/translations][translations]. 127 | 128 | [homepage]: https://www.contributor-covenant.org 129 | [v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html 130 | [mozilla coc]: https://github.com/mozilla/diversity 131 | [faq]: https://www.contributor-covenant.org/faq 132 | [translations]: https://www.contributor-covenant.org/translations 133 | -------------------------------------------------------------------------------- /template/CONTRIBUTING.md.jinja: -------------------------------------------------------------------------------- 1 | # Contributor Guide 2 | 3 | Thank you for your interest in improving this project. This project is 4 | open-source under the MIT License and welcomes contributions in the form of bug 5 | reports, feature requests, and pull requests. 6 | 7 | Here is a list of important resources for contributors: 8 | 9 | - [Source Code](https://github.com/{{ repository_namespace }}/{{ repository_name }}) 10 | - [Documentation]({{ documentation_url }}) 11 | - [Issue Tracker](https://github.com/{{ repository_namespace }}/{{ repository_name }}/issues) 12 | 13 | ## How to report a bug 14 | 15 | Report bugs on the [Issue Tracker](https://github.com/{{ repository_namespace }}/{{ repository_name }}/issues). 16 | 17 | When filing an issue, make sure to answer these questions: 18 | 19 | - Which operating system and Python version are you using? 20 | - Which version of this project are you using? 21 | - What did you do? 22 | - What did you expect to see? 23 | - What did you see instead? 24 | 25 | The best way to get your bug fixed is to provide a test case, and/or steps to 26 | reproduce the issue. In particular, please include a [Minimal, Reproducible 27 | Example](https://stackoverflow.com/help/minimal-reproducible-example). 28 | 29 | ## How to request a feature 30 | 31 | Feel free to request features on the [Issue 32 | Tracker](https://github.com/{{ repository_namespace }}/{{ repository_name }}/issues). 33 | 34 | ## How to set up your development environment 35 | 36 | TODO 37 | 38 | ## How to test the project 39 | 40 | ```bash 41 | python -m pip install nox 42 | python -m nox 43 | ``` 44 | 45 | ## How to submit changes 46 | 47 | Open a [Pull Request](https://github.com/{{ repository_namespace }}/{{ repository_name }}/pulls). 48 | -------------------------------------------------------------------------------- /template/LICENSE.jinja: -------------------------------------------------------------------------------- 1 | {%- if copyright_license == "Apache" %} 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 | {%- elif copyright_license == "MIT" %}MIT License 204 | 205 | Copyright (c) {{ copyright_range }} {{ copyright_holder }} 206 | 207 | Permission is hereby granted, free of charge, to any person obtaining a copy 208 | of this software and associated documentation files (the "Software"), to deal 209 | in the Software without restriction, including without limitation the rights 210 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 211 | copies of the Software, and to permit persons to whom the Software is 212 | furnished to do so, subject to the following conditions: 213 | 214 | The above copyright notice and this permission notice shall be included in all 215 | copies or substantial portions of the Software. 216 | 217 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 218 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 219 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 220 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 221 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 222 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 223 | SOFTWARE. 224 | {%- elif copyright_license == "BSD" %}BSD 2-Clause License 225 | 226 | Copyright (c) {{ copyright_range }} {{ copyright_holder }} 227 | 228 | Redistribution and use in source and binary forms, with or without 229 | modification, are permitted provided that the following conditions are met: 230 | 231 | 1. Redistributions of source code must retain the above copyright notice, this 232 | list of conditions and the following disclaimer. 233 | 234 | 2. Redistributions in binary form must reproduce the above copyright notice, 235 | this list of conditions and the following disclaimer in the documentation 236 | and/or other materials provided with the distribution. 237 | 238 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 239 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 240 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 241 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 242 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 243 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 244 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 245 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 246 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 247 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 248 | {% endif %} 249 | -------------------------------------------------------------------------------- /template/README.md.jinja: -------------------------------------------------------------------------------- 1 | # {{ project_name }} 2 | -------------------------------------------------------------------------------- /template/noxfile.py.jinja: -------------------------------------------------------------------------------- 1 | import nox 2 | {% for s in python_nox_sessions.split(',') + general_nox_sessions.split(',') -%} 3 | {% set session_name = s|replace("\"", "")|replace("'", "") %} 4 | 5 | @nox.session 6 | def {{session_name}}(session): 7 | {%- if session_name == "lint" %} 8 | session.install("pre-commit") 9 | session.run("pre-commit", "run", "--all-files") 10 | {%- elif session_name == "tests" %} 11 | session.install("-e", ".[test]") 12 | session.run("pytest", "-v", "tests") 13 | {%- else %} 14 | pass 15 | {%- endif %} 16 | {% endfor -%} 17 | -------------------------------------------------------------------------------- /template/pyproject.toml.jinja: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "{{ python_package_distribution_name }}" 3 | description = "{{ project_description }}" 4 | authors = [ 5 | { name="{{ author_fullname }}", email="{{ author_email }}" }, 6 | ] 7 | readme = "README.md" 8 | requires-python = ">=3.{{ python_formal_min_version }}" 9 | license = { text = "{% if copyright_license == "Apache" %}Apache License{% elif copyright_license == "MIT" %}MIT License{% elif copyright_license == "BSD" %}BSD 2-Clause License{% endif %}" } 10 | classifiers = [ 11 | "Operating System :: OS Independent", 12 | "Programming Language :: Python :: 3", 13 | {% if project_development_status == "alpha" -%} 14 | "Development Status :: 3 - Alpha", 15 | {%- elif project_development_status == "beta" -%} 16 | "Development Status :: 4 - Beta", 17 | {%- elif project_development_status == "stable" -%} 18 | "Development Status :: 5 - Production/Stable", 19 | {%- elif project_development_status == "mature" -%} 20 | "Development Status :: 6 - Mature", 21 | {%- elif project_development_status == "inactive" -%} 22 | "Development Status :: 7 - Inactive", 23 | {%- endif %} 24 | {% if copyright_license == "Apache" -%} 25 | "License :: OSI Approved :: Apache Software License", 26 | {%- elif copyright_license == "MIT" -%} 27 | "License :: OSI Approved :: MIT License", 28 | {%- elif copyright_license == "BSD" -%} 29 | "License :: OSI Approved :: BSD License", 30 | {%- endif %} 31 | ] 32 | dynamic = ["version"] 33 | dependencies = [ 34 | ] 35 | 36 | [project.urls] 37 | "Homepage" = "{{ documentation_url }}" 38 | "Source" = "https://github.com/{{ repository_namespace }}/{{ repository_name }}" 39 | "Bug Tracker" = "https://github.com/{{ repository_namespace }}/{{ repository_name }}/issues" 40 | 41 | [project.optional-dependencies] 42 | test = ["pytest", {{ python_test_dependencies }}] 43 | docs = ["sphinx>=3.3", "{{ documentation_sphinx_theme }}", {% if documentation_enable_execution %}"myst-nb", {% endif %}{% if documentation_execution_dependencies %}{{ documentation_execution_dependencies }}{% endif %}] 44 | {%- if python_optional_dependencies %} 45 | {%- set deps = python_optional_dependencies.split('|') -%} 46 | {%- for dep in deps %} 47 | {{ dep.strip() }} 48 | {%- endfor %} 49 | {%- endif %} 50 | 51 | [build-system] 52 | requires = [ 53 | "setuptools>=61.0", 54 | "wheel", 55 | "setuptools_scm", 56 | {%- if enable_pybind11 %} 57 | "pybind11>=2.6", 58 | "scikit-build", 59 | "cmake", 60 | "ninja; platform_system!='Windows'", 61 | {%- endif %} 62 | ] 63 | build-backend = "setuptools.build_meta" 64 | 65 | [tool.setuptools_scm] 66 | write_to = "src/{{ python_package_import_name }}/version.py" 67 | 68 | [tool.black] 69 | line-length = {{ project_line_length }} 70 | 71 | [tool.isort] 72 | skip_glob = [] 73 | line_length = {{ project_line_length }} 74 | multi_line_output = 3 75 | include_trailing_comma = true 76 | force_grid_wrap = 0 77 | use_parentheses = true 78 | known_first_party = ["{{ python_package_import_name }}"] 79 | 80 | [tool.coverage.run] 81 | parallel = true 82 | branch = true 83 | source = ["{{ python_package_import_name }}"] 84 | omit = [ 85 | "docs/*", 86 | "tests/*", 87 | "*/{{ python_package_import_name }}/version.py", 88 | ] 89 | 90 | [tool.coverage.paths] 91 | source = ["src", "*/site-packages"] 92 | 93 | [tool.coverage.report] 94 | show_missing = true 95 | -------------------------------------------------------------------------------- /template/readthedocs.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | submodules: 4 | include: all 5 | 6 | build: 7 | os: ubuntu-20.04 8 | apt_packages: 9 | - fonts-liberation 10 | tools: 11 | python: "3.10" 12 | 13 | python: 14 | install: 15 | - method: pip 16 | path: . 17 | extra_requirements: 18 | - docs 19 | 20 | sphinx: 21 | builder: dirhtml 22 | configuration: docs/conf.py 23 | fail_on_warning: true 24 | -------------------------------------------------------------------------------- /template/setup.py.jinja: -------------------------------------------------------------------------------- 1 | {% if enable_pybind11 -%} 2 | from skbuild import setup 3 | from setuptools import find_packages 4 | 5 | setup( 6 | name="{{ python_package_distribution_name }}", 7 | packages=find_packages(where="src"), 8 | package_dir={"": "src"}, 9 | cmake_install_dir="src/{{ python_package_import_name }}", 10 | include_package_data=True, 11 | ) 12 | {%- else -%} 13 | from setuptools import find_packages, setup 14 | 15 | setup( 16 | name="{{ python_package_distribution_name }}", 17 | packages=find_packages(where="src"), 18 | package_dir={"": "src"}, 19 | ) 20 | {%- endif %} 21 | -------------------------------------------------------------------------------- /template/src/{%if enable_pybind11%}lib{%endif%}/main.cpp.jinja: -------------------------------------------------------------------------------- 1 | {% if copyright_license == "Apache" -%} 2 | // Copyright {{ copyright_range }} {{ copyright_holder }} 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | {% endif %} 16 | 17 | #include 18 | 19 | namespace py = pybind11; 20 | 21 | PYBIND11_MODULE(_core, m) { 22 | m.doc() = R"pbdoc( 23 | An example pybind11 module 24 | )pbdoc"; 25 | } 26 | -------------------------------------------------------------------------------- /template/src/{{python_package_import_name}}/__init__.py.jinja: -------------------------------------------------------------------------------- 1 | {% if copyright_license == "Apache" -%} 2 | # Copyright {{ copyright_year }} {{ copyright_holder }} 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | {% endif -%} 17 | 18 | from {{python_package_import_name}}.version import version as __version__ 19 | -------------------------------------------------------------------------------- /template/tests/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dfm/copier-python/3deba11b3846599ea596eca6b6eea11efcf80bbc/template/tests/.gitkeep -------------------------------------------------------------------------------- /template/{% if documentation_enable %}docs{% endif %}/.gitignore: -------------------------------------------------------------------------------- 1 | _build 2 | -------------------------------------------------------------------------------- /template/{% if documentation_enable %}docs{% endif %}/Makefile.jinja: -------------------------------------------------------------------------------- 1 | default: {{ documentation_build_type }} 2 | 3 | SPHINXOPTS = -W --keep-going -n 4 | SPHINXBUILD = sphinx-build 5 | BUILDDIR = _build 6 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(SPHINXOPTS) . 7 | 8 | .PHONY: clean 9 | clean: 10 | rm -rf $(BUILDDIR)/* 11 | 12 | .PHONY: {{ documentation_build_type }} 13 | {{ documentation_build_type }}: 14 | $(SPHINXBUILD) -b {{ documentation_build_type }} $(ALLSPHINXOPTS) $(BUILDDIR)/{{ documentation_build_type }} 15 | @echo 16 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/{{ documentation_build_type }}." 17 | -------------------------------------------------------------------------------- /template/{% if documentation_enable %}docs{% endif %}/_static/README.md: -------------------------------------------------------------------------------- 1 | Default logo attribution: https://feathericons.com 2 | -------------------------------------------------------------------------------- /template/{% if documentation_enable %}docs{% endif %}/_static/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /template/{% if documentation_enable %}docs{% endif %}/conf.py.jinja: -------------------------------------------------------------------------------- 1 | import {{ python_package_import_name }} 2 | 3 | language = "en" 4 | master_doc = "index" 5 | 6 | extensions = [ 7 | "sphinx.ext.autodoc", 8 | "sphinx.ext.autosummary", 9 | "sphinx.ext.mathjax", 10 | "sphinx.ext.napoleon", 11 | "sphinx.ext.viewcode", 12 | {% if documentation_enable_execution %} 13 | "myst_nb", 14 | {% endif %} 15 | ] 16 | 17 | myst_enable_extensions = ["dollarmath", "colon_fence"] 18 | source_suffix = { 19 | ".rst": "restructuredtext", 20 | ".ipynb": "myst-nb", 21 | } 22 | templates_path = ["_templates"] 23 | 24 | # General information about the project. 25 | project = "{{ project_name }}" 26 | copyright = "{{ copyright_range }} {{ copyright_holder }}" 27 | version = {{ python_package_import_name }}.__version__ 28 | release = {{ python_package_import_name }}.__version__ 29 | 30 | exclude_patterns = ["_build"] 31 | html_theme = "{{ documentation_sphinx_theme }}" 32 | html_title = "{{ project_name }}" 33 | html_logo = "_static/{{ documentation_logo_filename }}" 34 | html_favicon = "_static/{{ documentation_favicon_filename }}" 35 | html_static_path = ["_static"] 36 | html_show_sourcelink = False 37 | html_theme_options = { 38 | "path_to_docs": "docs", 39 | "repository_url": "https://github.com/{{ repository_namespace }}/{{ repository_name }}", 40 | "repository_branch": "main", 41 | "launch_buttons": { 42 | {% if documentation_enable_binder %} 43 | "binderhub_url": "https://mybinder.org", 44 | "notebook_interface": "jupyterlab", 45 | {% endif %} 46 | {% if documentation_enable_colab %} 47 | "colab_url": "https://colab.research.google.com/", 48 | {% endif %} 49 | }, 50 | "use_edit_page_button": True, 51 | "use_issues_button": True, 52 | "use_repository_button": True, 53 | "use_download_button": True, 54 | } 55 | {% if documentation_enable_execution %} 56 | nb_execution_mode = "auto" 57 | nb_execution_excludepatterns = [{{ documentation_execution_excludepatterns }}] 58 | nb_execution_timeout = -1 59 | {% endif %} 60 | -------------------------------------------------------------------------------- /template/{% if documentation_enable %}docs{% endif %}/index.md.jinja: -------------------------------------------------------------------------------- 1 | # {{ project_name }} 2 | 3 | These are the docs for {{ project_name }}. 4 | 5 | ## Table of contents 6 | 7 | ```{toctree} 8 | :maxdepth: 2 9 | 10 | GitHub Repository 11 | ``` 12 | 13 | ## Authors & license 14 | 15 | ```{include} license.md 16 | ``` 17 | -------------------------------------------------------------------------------- /template/{% if documentation_enable %}docs{% endif %}/license.md.jinja: -------------------------------------------------------------------------------- 1 | Copyright {{ copyright_range }} {{ copyright_holder }} 2 | 3 | Licensed under the {{ copyright_license }} license (see `LICENSE`). 4 | See [the contribution graph](https://github.com/{{ repository_namespace }}/{{ repository_name }}/graphs/contributors) 5 | for the most up-to-date list of contributors. 6 | -------------------------------------------------------------------------------- /template/{%if enable_mypy%}mypy.ini{%endif%}: -------------------------------------------------------------------------------- 1 | [mypy] 2 | follow_imports = normal 3 | ignore_missing_imports = True 4 | check_untyped_defs = True 5 | disallow_any_generics = True 6 | disallow_incomplete_defs = True 7 | disallow_untyped_calls = True 8 | disallow_untyped_defs = True 9 | no_implicit_optional = True 10 | strict_optional = True 11 | warn_no_return = True 12 | warn_redundant_casts = True 13 | warn_unreachable = True 14 | warn_unused_ignores = True 15 | -------------------------------------------------------------------------------- /template/{%if enable_pybind11%}.clang-format{%endif%}: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | ColumnLimit: 99 3 | -------------------------------------------------------------------------------- /template/{%if enable_pybind11%}CMakeLists.txt{%endif%}.jinja: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15...3.22) 2 | 3 | project({{ python_package_import_name }} LANGUAGES C CXX) 4 | if(SKBUILD) 5 | execute_process( 6 | COMMAND "${PYTHON_EXECUTABLE}" -c 7 | "import pybind11; print(pybind11.get_cmake_dir())" 8 | OUTPUT_VARIABLE _tmp_dir 9 | OUTPUT_STRIP_TRAILING_WHITESPACE COMMAND_ECHO STDOUT) 10 | list(APPEND CMAKE_PREFIX_PATH "${_tmp_dir}") 11 | endif() 12 | 13 | find_package(pybind11 CONFIG REQUIRED) 14 | pybind11_add_module(_core MODULE src/lib/main.cpp) 15 | target_compile_definitions(_core PRIVATE VERSION_INFO=${PROJECT_VERSION}) 16 | install(TARGETS _core DESTINATION .) 17 | -------------------------------------------------------------------------------- /template/{%if enable_pybind11%}MANIFEST.in{%endif%}: -------------------------------------------------------------------------------- 1 | include CMakeLists.txt 2 | graft src/lib 3 | -------------------------------------------------------------------------------- /template/{{_copier_conf.answers_file}}.jinja: -------------------------------------------------------------------------------- 1 | {{_copier_answers|to_nice_yaml}} 2 | -------------------------------------------------------------------------------- /tests/test_basic.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Dan Foreman-Mackey 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | 16 | def test_import(): 17 | import dfm_test_package 18 | 19 | 20 | def test_version(): 21 | from dfm_test_package import __version__ 22 | 23 | assert isinstance(__version__, str) 24 | -------------------------------------------------------------------------------- /tests/test_compiled.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Dan Foreman-Mackey 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | 16 | def test_import(): 17 | import dfm_test_package._core 18 | --------------------------------------------------------------------------------