From 6517e3f90b973c164afa8f425988411603929af2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Collonval?= Date: Tue, 21 Mar 2023 11:21:46 +0100 Subject: [PATCH 1/6] First version --- .gitignore | 1 - cookiecutter.json | 14 ++--- copier.yml | 61 +++++++++++++++++++ hooks/post_gen_project.py | 55 ++++++----------- .../.github/workflows/build.yml | 28 ++++----- .../.github/workflows/check-release.yml | 2 +- .../.github/workflows/enforce-label.yml | 0 .../.github/workflows/prep-release.yml | 0 .../.github/workflows/publish-release.yml | 0 ...f has_binder %}binder-on-pr.yml{% endif %} | 0 ... %}update-integration-tests.yml{% endif %} | 0 .../{{python_name}}/.gitignore.jinja2 | 2 +- .../{{python_name}}}/.prettierignore | 2 +- .../{{python_name}}}/.yarnrc.yml | 0 .../{{python_name}}}/CHANGELOG.md | 0 .../{{python_name}}}/LICENSE | 2 +- .../{{python_name}}}/README.md | 44 ++++++------- .../{{python_name}}}/RELEASE.md | 2 +- template/{{python_name}}/install.json | 5 ++ .../{{python_name}}}/package.json | 50 +++++++-------- .../{{python_name}}}/pyproject.toml | 24 ++++---- .../{{python_name}}}/setup.py | 0 template/{{python_name}}/src/index.ts | 54 ++++++++++++++++ ...f kind == 'server' %}handler.ts{% endif %} | 2 +- .../{{python_name}}.spec.ts | 2 +- .../{{python_name}}}/style/base.css | 0 .../{{python_name}}}/style/index.css | 2 +- .../{{python_name}}}/style/index.js | 0 ... kind = 'theme' %}variables.css{% endif %} | 0 .../{{python_name}}}/tsconfig.json | 2 +- .../environment.yml | 6 +- .../postBuild | 8 +-- .../plugin.json | 8 +++ .../nb-config/{{python_name}}.json | 2 +- .../server-config/{{python_name}}.json | 2 +- .../{% if test %}babel.config.js{% endif %} | 0 .../{% if test %}conftest.py{% endif %} | 2 +- .../{% if test %}jest.config.js{% endif %} | 0 ...{% if test %}tsconfig.test.json{% endif %} | 0 .../README.md | 0 .../jupyter_server_test_config.py | 0 .../package.json | 4 +- .../playwright.config.js | 0 .../tests/{{python_name}}.spec.ts | 2 +- .../yarn.lock | 0 .../{{python_name}}}/__init__.py | 10 +-- ... kind == 'server' %}handlers.py{% endif %} | 4 +- .../{% if test %}tests{% endif %}/__init__.py | 1 + .../test_handlers.py | 13 ++++ {{cookiecutter.python_name}}/install.json | 5 -- .../schema/plugin.json | 8 --- {{cookiecutter.python_name}}/src/index.ts | 54 ---------------- .../tests/__init__.py | 1 - .../tests/test_handlers.py | 13 ---- 54 files changed, 267 insertions(+), 230 deletions(-) create mode 100644 copier.yml rename {{{cookiecutter.python_name}} => template/{{python_name}}}/.github/workflows/build.yml (77%) rename {{{cookiecutter.python_name}} => template/{{python_name}}}/.github/workflows/check-release.yml (88%) rename {{{cookiecutter.python_name}} => template/{{python_name}}}/.github/workflows/enforce-label.yml (100%) rename {{{cookiecutter.python_name}} => template/{{python_name}}}/.github/workflows/prep-release.yml (100%) rename {{{cookiecutter.python_name}} => template/{{python_name}}}/.github/workflows/publish-release.yml (100%) rename {{cookiecutter.python_name}}/.github/workflows/binder-on-pr.yml => template/{{python_name}}/.github/workflows/{% if has_binder %}binder-on-pr.yml{% endif %} (100%) rename {{cookiecutter.python_name}}/.github/workflows/update-integration-tests.yml => template/{{python_name}}/.github/workflows/{% if test %}update-integration-tests.yml{% endif %} (100%) rename {{cookiecutter.python_name}}/.gitignore => template/{{python_name}}/.gitignore.jinja2 (97%) rename {{{cookiecutter.python_name}} => template/{{python_name}}}/.prettierignore (69%) rename {{{cookiecutter.python_name}} => template/{{python_name}}}/.yarnrc.yml (100%) rename {{{cookiecutter.python_name}} => template/{{python_name}}}/CHANGELOG.md (100%) rename {{{cookiecutter.python_name}} => template/{{python_name}}}/LICENSE (95%) rename {{{cookiecutter.python_name}} => template/{{python_name}}}/README.md (68%) rename {{{cookiecutter.python_name}} => template/{{python_name}}}/RELEASE.md (97%) create mode 100644 template/{{python_name}}/install.json rename {{{cookiecutter.python_name}} => template/{{python_name}}}/package.json (74%) rename {{{cookiecutter.python_name}} => template/{{python_name}}}/pyproject.toml (70%) rename {{{cookiecutter.python_name}} => template/{{python_name}}}/setup.py (100%) create mode 100644 template/{{python_name}}/src/index.ts rename {{cookiecutter.python_name}}/src/handler.ts => template/{{python_name}}/src/{% if kind == 'server' %}handler.ts{% endif %} (93%) rename {{cookiecutter.python_name}}/src/__tests__/{{cookiecutter.python_name}}.spec.ts => template/{{python_name}}/src/{% if test %}__tests__{% endif %}/{{python_name}}.spec.ts (72%) rename {{{cookiecutter.python_name}} => template/{{python_name}}}/style/base.css (100%) rename {{{cookiecutter.python_name}} => template/{{python_name}}}/style/index.css (77%) rename {{{cookiecutter.python_name}} => template/{{python_name}}}/style/index.js (100%) rename {{cookiecutter.python_name}}/style/variables.css => template/{{python_name}}/style/{% if kind = 'theme' %}variables.css{% endif %} (100%) rename {{{cookiecutter.python_name}} => template/{{python_name}}}/tsconfig.json (86%) rename {{{cookiecutter.python_name}}/binder => template/{{python_name}}/{% if has_binder %}binder{% endif %}}/environment.yml (63%) rename {{{cookiecutter.python_name}}/binder => template/{{python_name}}/{% if has_binder %}binder{% endif %}}/postBuild (83%) create mode 100644 template/{{python_name}}/{% if has_settings %}schema{% endif %}/plugin.json rename {{cookiecutter.python_name}}/jupyter-config/nb-config/{{cookiecutter.python_name}}.json => template/{{python_name}}/{% if kind == 'server' %}jupyter-config{% endif %}/nb-config/{{python_name}}.json (57%) rename {{cookiecutter.python_name}}/jupyter-config/server-config/{{cookiecutter.python_name}}.json => template/{{python_name}}/{% if kind == 'server' %}jupyter-config{% endif %}/server-config/{{python_name}}.json (57%) rename {{cookiecutter.python_name}}/babel.config.js => template/{{python_name}}/{% if test %}babel.config.js{% endif %} (100%) rename {{cookiecutter.python_name}}/conftest.py => template/{{python_name}}/{% if test %}conftest.py{% endif %} (57%) rename {{cookiecutter.python_name}}/jest.config.js => template/{{python_name}}/{% if test %}jest.config.js{% endif %} (100%) rename {{cookiecutter.python_name}}/tsconfig.test.json => template/{{python_name}}/{% if test %}tsconfig.test.json{% endif %} (100%) rename {{{cookiecutter.python_name}}/ui-tests => template/{{python_name}}/{% if test %}ui-tests{% endif %}}/README.md (100%) rename {{{cookiecutter.python_name}}/ui-tests => template/{{python_name}}/{% if test %}ui-tests{% endif %}}/jupyter_server_test_config.py (100%) rename {{{cookiecutter.python_name}}/ui-tests => template/{{python_name}}/{% if test %}ui-tests{% endif %}}/package.json (69%) rename {{{cookiecutter.python_name}}/ui-tests => template/{{python_name}}/{% if test %}ui-tests{% endif %}}/playwright.config.js (100%) rename {{cookiecutter.python_name}}/ui-tests/tests/{{cookiecutter.python_name}}.spec.ts => template/{{python_name}}/{% if test %}ui-tests{% endif %}/tests/{{python_name}}.spec.ts (81%) rename {{{cookiecutter.python_name}}/ui-tests => template/{{python_name}}/{% if test %}ui-tests{% endif %}}/yarn.lock (100%) rename {{{cookiecutter.python_name}}/{{cookiecutter.python_name}} => template/{{python_name}}/{{python_name}}}/__init__.py (72%) rename {{cookiecutter.python_name}}/{{cookiecutter.python_name}}/handlers.py => template/{{python_name}}/{{python_name}}/{% if kind == 'server' %}handlers.py{% endif %} (74%) create mode 100644 template/{{python_name}}/{{python_name}}/{% if test %}tests{% endif %}/__init__.py create mode 100644 template/{{python_name}}/{{python_name}}/{% if test %}tests{% endif %}/test_handlers.py delete mode 100644 {{cookiecutter.python_name}}/install.json delete mode 100644 {{cookiecutter.python_name}}/schema/plugin.json delete mode 100644 {{cookiecutter.python_name}}/src/index.ts delete mode 100644 {{cookiecutter.python_name}}/{{cookiecutter.python_name}}/tests/__init__.py delete mode 100644 {{cookiecutter.python_name}}/{{cookiecutter.python_name}}/tests/test_handlers.py diff --git a/.gitignore b/.gitignore index 6011778a..6ef08784 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,6 @@ node_modules/ *.tsbuildinfo .eslintcache .stylelintcache -{{cookiecutter.python_name}}/static # Created by https://www.gitignore.io/api/python # Edit at https://www.gitignore.io/?templates=python diff --git a/cookiecutter.json b/cookiecutter.json index 550e9883..3389ff70 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -1,12 +1,6 @@ { - "kind": ["frontend", "server", "theme"], - "author_name": "My Name", - "author_email": "me@test.com", - "labextension_name": "{% if cookiecutter.kind == 'theme' %}mytheme{% else %}myextension{% endif %}", - "python_name": "{{ cookiecutter.labextension_name | replace('-', '_') }}", - "project_short_description": "A JupyterLab extension.", - "has_settings": "n", - "has_binder": "n", - "test": "y", - "repository": "https://github.com/github_username/{{ cookiecutter.labextension_name }}" + "_copy_without_render": [ + "copier.yml", + "template" + ] } diff --git a/copier.yml b/copier.yml new file mode 100644 index 00000000..8bfb4064 --- /dev/null +++ b/copier.yml @@ -0,0 +1,61 @@ +_min_copier_version: "6.2.0" +_subdirectory: template +_exclude: + - ".github" + - "hooks" + - "cookiecutter.json" + - "LICENSE" + - "README.md" + +kind: + type: str + help: What is your extension kind? + choices: + - frontend + - server + - theme + +author_name: + type: str + help: Author name? + placeholder: "My Name" + +author_email: + type: str + help: Author email? + placeholder: "me@test.com" + +labextension_name: + type: str + help: JavaScript extension name? + default: "{% if kind == 'theme' %}mytheme{% else %}myextension{% endif %}" + +python_name: + type: str + help: Python package name? + default: "{{ labextension_name | replace('-', '_') }}" + +project_short_description: + type: str + help: Extension short description + default: "A JupyterLab extension." + +has_settings: + type: bool + help: Does the extension have settings? + default: no + +has_binder: + type: bool + help: Do you want to set up a Binder example? + default: no + +test: + type: bool + help: Do you want to set up tests for the extension? + default: yes + +repository: + type: str + help: Git remote repository URL? + placeholder: https://github.com/github_username/my-extension diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 23435740..ad30e672 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -1,8 +1,10 @@ #!/usr/bin/env python +import sys from pathlib import Path +from subprocess import CalledProcessError, check_call PROJECT_DIRECTORY = Path.cwd() - +TEMPLATE_URI = "https://github.com/jupyterlab/extension-cookiecutter-ts.git" def remove_path(path: Path) -> None: """Remove the provided path. @@ -22,38 +24,19 @@ def remove_path(path: Path) -> None: if __name__ == "__main__": - if not "{{ cookiecutter.has_settings }}".lower().startswith("y"): - remove_path(PROJECT_DIRECTORY / "schema") - - if "{{ cookiecutter.kind }}".lower() == "theme": - for f in ( - "style/index.js", - "style/base.css" - ): - remove_path(PROJECT_DIRECTORY / f) - else: - remove_path(PROJECT_DIRECTORY / "style/variables.css") - - if not "{{ cookiecutter.kind }}".lower() == "server": - for f in ( - "{{ cookiecutter.python_name }}/handlers.py", - "src/handler.ts", - "jupyter-config", - "conftest.py", - "{{ cookiecutter.python_name }}/tests" - ): - remove_path(PROJECT_DIRECTORY / f) - - if not "{{ cookiecutter.has_binder }}".lower().startswith("y"): - remove_path(PROJECT_DIRECTORY / "binder") - remove_path(PROJECT_DIRECTORY / ".github/workflows/binder-on-pr.yml") - - if not "{{ cookiecutter.test }}".lower().startswith("y"): - remove_path(PROJECT_DIRECTORY / ".github" / "workflows" / "update-integration-tests.yml") - remove_path(PROJECT_DIRECTORY / "src" / "__tests__") - remove_path(PROJECT_DIRECTORY / "ui-tests") - remove_path(PROJECT_DIRECTORY / "{{ cookiecutter.python_name }}" / "tests") - remove_path(PROJECT_DIRECTORY / "babel.config.js") - remove_path(PROJECT_DIRECTORY / "conftest.py") - remove_path(PROJECT_DIRECTORY / "jest.config.js") - remove_path(PROJECT_DIRECTORY / "tsconfig.test.json") + remove_path(PROJECT_DIRECTORY / "template") + remove_path(PROJECT_DIRECTORY / "copier.yml") + + try: + import copier + except ImportError: + try: + check_call([sys.executable, "-m", "pip", "install", "copier>=6.2.0"]) + except CalledProcessError: + check_call([sys.executable, "-m", "pip", "install", "--pre", "copier>=6.2.0"]) + + from copier import run_copy + + extension_name = input("What is your extension name?") + module_name = extension_name.replace("-", "_") + run_copy(TEMPLATE_URI, PROJECT_DIRECTORY / module_name, data={ "labextension_name": extension_name, "python_name": module_name}) diff --git a/{{cookiecutter.python_name}}/.github/workflows/build.yml b/template/{{python_name}}/.github/workflows/build.yml similarity index 77% rename from {{cookiecutter.python_name}}/.github/workflows/build.yml rename to template/{{python_name}}/.github/workflows/build.yml index 80f85b4c..08df76c6 100644 --- a/{{cookiecutter.python_name}}/.github/workflows/build.yml +++ b/template/{{python_name}}/.github/workflows/build.yml @@ -25,7 +25,7 @@ jobs: set -eux jlpm jlpm run lint:check -{% if cookiecutter.test.lower().startswith('y') %} +{% if test.lower().startswith('y') %} - name: Test the extension run: | set -eux @@ -35,13 +35,13 @@ jobs: run: | set -eux python -m pip install .[test] -{% if cookiecutter.kind.lower() == 'server' %} - pytest -vv -r ap --cov {{ cookiecutter.python_name }} +{% if kind.lower() == 'server' %} + pytest -vv -r ap --cov {{ python_name }} jupyter server extension list - jupyter server extension list 2>&1 | grep -ie "{{ cookiecutter.python_name }}.*OK" + jupyter server extension list 2>&1 | grep -ie "{{ python_name }}.*OK" {% endif %} jupyter labextension list - jupyter labextension list 2>&1 | grep -ie "{{ cookiecutter.labextension_name }}.*OK" + jupyter labextension list 2>&1 | grep -ie "{{ labextension_name }}.*OK" python -m jupyterlab.browser_check - name: Package the extension @@ -50,13 +50,13 @@ jobs: pip install build python -m build - pip uninstall -y "{{ cookiecutter.python_name }}" jupyterlab + pip uninstall -y "{{ python_name }}" jupyterlab - name: Upload extension packages uses: actions/upload-artifact@v3 with: name: extension-artifacts - path: dist/{{ cookiecutter.python_name }}* + path: dist/{{ python_name }}* if-no-files-found: error test_isolated: @@ -81,16 +81,16 @@ jobs: sudo rm -rf $(which node) sudo rm -rf $(which node) - pip install "jupyterlab>=4.0.0b0,<5" {{ cookiecutter.python_name }}*.whl + pip install "jupyterlab>=4.0.0b0,<5" {{ python_name }}*.whl -{% if cookiecutter.kind.lower() == 'server' %} +{% if kind.lower() == 'server' %} jupyter server extension list - jupyter server extension list 2>&1 | grep -ie "{{ cookiecutter.python_name }}.*OK" + jupyter server extension list 2>&1 | grep -ie "{{ python_name }}.*OK" {% endif %} jupyter labextension list - jupyter labextension list 2>&1 | grep -ie "{{ cookiecutter.labextension_name }}.*OK" + jupyter labextension list 2>&1 | grep -ie "{{ labextension_name }}.*OK" python -m jupyterlab.browser_check --no-browser-test -{% if cookiecutter.test.lower().startswith('y') %} +{% if test %} integration-tests: name: Integration tests needs: build @@ -114,7 +114,7 @@ jobs: - name: Install the extension run: | set -eux - python -m pip install "jupyterlab>=4.0.0b0,<5" {{ cookiecutter.python_name }}*.whl + python -m pip install "jupyterlab>=4.0.0b0,<5" {{ python_name }}*.whl - name: Install dependencies working-directory: ui-tests @@ -142,7 +142,7 @@ jobs: if: always() uses: actions/upload-artifact@v3 with: - name: {{ cookiecutter.python_name }}-playwright-tests + name: {{ python_name }}-playwright-tests path: | ui-tests/test-results ui-tests/playwright-report{% endif %} diff --git a/{{cookiecutter.python_name}}/.github/workflows/check-release.yml b/template/{{python_name}}/.github/workflows/check-release.yml similarity index 88% rename from {{cookiecutter.python_name}}/.github/workflows/check-release.yml rename to template/{{python_name}}/.github/workflows/check-release.yml index ad19ee9d..9cf483a5 100644 --- a/{{cookiecutter.python_name}}/.github/workflows/check-release.yml +++ b/template/{{python_name}}/.github/workflows/check-release.yml @@ -25,5 +25,5 @@ jobs: - name: Upload Distributions uses: actions/upload-artifact@v3 with: - name: {{ cookiecutter.python_name }}-releaser-dist-${{ '{{ github.run_number }}' }} + name: {{ python_name }}-releaser-dist-${{ '{{ github.run_number }}' }} path: .jupyter_releaser_checkout/dist diff --git a/{{cookiecutter.python_name}}/.github/workflows/enforce-label.yml b/template/{{python_name}}/.github/workflows/enforce-label.yml similarity index 100% rename from {{cookiecutter.python_name}}/.github/workflows/enforce-label.yml rename to template/{{python_name}}/.github/workflows/enforce-label.yml diff --git a/{{cookiecutter.python_name}}/.github/workflows/prep-release.yml b/template/{{python_name}}/.github/workflows/prep-release.yml similarity index 100% rename from {{cookiecutter.python_name}}/.github/workflows/prep-release.yml rename to template/{{python_name}}/.github/workflows/prep-release.yml diff --git a/{{cookiecutter.python_name}}/.github/workflows/publish-release.yml b/template/{{python_name}}/.github/workflows/publish-release.yml similarity index 100% rename from {{cookiecutter.python_name}}/.github/workflows/publish-release.yml rename to template/{{python_name}}/.github/workflows/publish-release.yml diff --git a/{{cookiecutter.python_name}}/.github/workflows/binder-on-pr.yml b/template/{{python_name}}/.github/workflows/{% if has_binder %}binder-on-pr.yml{% endif %} similarity index 100% rename from {{cookiecutter.python_name}}/.github/workflows/binder-on-pr.yml rename to template/{{python_name}}/.github/workflows/{% if has_binder %}binder-on-pr.yml{% endif %} diff --git a/{{cookiecutter.python_name}}/.github/workflows/update-integration-tests.yml b/template/{{python_name}}/.github/workflows/{% if test %}update-integration-tests.yml{% endif %} similarity index 100% rename from {{cookiecutter.python_name}}/.github/workflows/update-integration-tests.yml rename to template/{{python_name}}/.github/workflows/{% if test %}update-integration-tests.yml{% endif %} diff --git a/{{cookiecutter.python_name}}/.gitignore b/template/{{python_name}}/.gitignore.jinja2 similarity index 97% rename from {{cookiecutter.python_name}}/.gitignore rename to template/{{python_name}}/.gitignore.jinja2 index 6b9aad4c..be835527 100644 --- a/{{cookiecutter.python_name}}/.gitignore +++ b/template/{{python_name}}/.gitignore.jinja2 @@ -7,7 +7,7 @@ node_modules/ *.egg-info/ .ipynb_checkpoints *.tsbuildinfo -{{cookiecutter.python_name}}/labextension +{{python_name}}/labextension # Version file is handled by hatchling {{cookiecutter.python_name}}/_version.py {% if cookiecutter.test.lower().startswith('y') %} diff --git a/{{cookiecutter.python_name}}/.prettierignore b/template/{{python_name}}/.prettierignore similarity index 69% rename from {{cookiecutter.python_name}}/.prettierignore rename to template/{{python_name}}/.prettierignore index 1df93abe..fca8202d 100644 --- a/{{cookiecutter.python_name}}/.prettierignore +++ b/template/{{python_name}}/.prettierignore @@ -3,4 +3,4 @@ node_modules **/lib **/package.json !/package.json -{{cookiecutter.python_name}} +{{python_name}} diff --git a/{{cookiecutter.python_name}}/.yarnrc.yml b/template/{{python_name}}/.yarnrc.yml similarity index 100% rename from {{cookiecutter.python_name}}/.yarnrc.yml rename to template/{{python_name}}/.yarnrc.yml diff --git a/{{cookiecutter.python_name}}/CHANGELOG.md b/template/{{python_name}}/CHANGELOG.md similarity index 100% rename from {{cookiecutter.python_name}}/CHANGELOG.md rename to template/{{python_name}}/CHANGELOG.md diff --git a/{{cookiecutter.python_name}}/LICENSE b/template/{{python_name}}/LICENSE similarity index 95% rename from {{cookiecutter.python_name}}/LICENSE rename to template/{{python_name}}/LICENSE index c71b5cc7..c198a4ec 100644 --- a/{{cookiecutter.python_name}}/LICENSE +++ b/template/{{python_name}}/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) {% now 'utc', '%Y' %}, {{ cookiecutter.author_name }} +Copyright (c) {% now 'utc', '%Y' %}, {{ author_name }} All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/{{cookiecutter.python_name}}/README.md b/template/{{python_name}}/README.md similarity index 68% rename from {{cookiecutter.python_name}}/README.md rename to template/{{python_name}}/README.md index 060db353..75b996fd 100644 --- a/{{cookiecutter.python_name}}/README.md +++ b/template/{{python_name}}/README.md @@ -1,14 +1,14 @@ -# {{ cookiecutter.python_name }} +# {{ python_name }} -[![Github Actions Status]({{ cookiecutter.repository }}/workflows/Build/badge.svg)]({{ cookiecutter.repository }}/actions/workflows/build.yml) -{%- if cookiecutter.has_binder.lower().startswith('y') -%} -[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/{{ cookiecutter.repository|replace("https://github.com/", "") }}/main?urlpath=lab) +[![Github Actions Status]({{ repository }}/workflows/Build/badge.svg)]({{ repository }}/actions/workflows/build.yml) +{%- if has_binder -%} +[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/{{ repository|replace("https://github.com/", "") }}/main?urlpath=lab) {%- endif %} -{{ cookiecutter.project_short_description }} -{% if cookiecutter.kind.lower() == 'server' %} -This extension is composed of a Python package named `{{ cookiecutter.python_name }}` -for the server extension and a NPM package named `{{ cookiecutter.labextension_name }}` +{{ project_short_description }} +{% if kind.lower() == 'server' %} +This extension is composed of a Python package named `{{ python_name }}` +for the server extension and a NPM package named `{{ labextension_name }}` for the frontend extension. {% endif %} ## Requirements @@ -20,7 +20,7 @@ for the frontend extension. To install the extension, execute: ```bash -pip install {{ cookiecutter.python_name }} +pip install {{ python_name }} ``` ## Uninstall @@ -28,9 +28,9 @@ pip install {{ cookiecutter.python_name }} To remove the extension, execute: ```bash -pip uninstall {{ cookiecutter.python_name }} +pip uninstall {{ python_name }} ``` -{% if cookiecutter.kind.lower() == 'server' %} +{% if kind.lower() == 'server' %} ## Troubleshoot If you are seeing the frontend extension, but it is not working, check @@ -59,13 +59,13 @@ The `jlpm` command is JupyterLab's pinned version of ```bash # Clone the repo to your local environment -# Change directory to the {{ cookiecutter.python_name }} directory +# Change directory to the {{ python_name }} directory # Install package in development mode -pip install -e ".{% if cookiecutter.test.lower().startswith('y') and cookiecutter.kind.lower() == 'server' %}[test]{% endif %}" +pip install -e ".{% if test and kind.lower() == 'server' %}[test]{% endif %}" # Link your development version of the extension with JupyterLab -jupyter labextension develop . --overwrite{% if cookiecutter.kind.lower() == 'server' %} +jupyter labextension develop . --overwrite{% if kind.lower() == 'server' %} # Server extension must be manually installed in develop mode -jupyter server extension enable {{ cookiecutter.python_name }}{% endif %} +jupyter server extension enable {{ python_name }}{% endif %} # Rebuild extension Typescript source after making changes jlpm build ``` @@ -89,17 +89,17 @@ jupyter lab build --minimize=False ### Development uninstall -```bash{% if cookiecutter.kind.lower() == 'server' %} +```bash{% if kind.lower() == 'server' %} # Server extension must be manually disabled in develop mode -jupyter server extension disable {{ cookiecutter.python_name }}{% endif %} -pip uninstall {{ cookiecutter.python_name }} +jupyter server extension disable {{ python_name }}{% endif %} +pip uninstall {{ python_name }} ``` In development mode, you will also need to remove the symlink created by `jupyter labextension develop` command. To find its location, you can run `jupyter labextension list` to figure out where the `labextensions` -folder is located. Then you can remove the symlink named `{{ cookiecutter.labextension_name }}` within that folder. -{% if cookiecutter.test.lower().startswith('y') %} -### Testing the extension{% if cookiecutter.kind.lower() == 'server' %} +folder is located. Then you can remove the symlink named `{{ labextension_name }}` within that folder. +{% if test %} +### Testing the extension{% if kind.lower() == 'server' %} #### Server tests @@ -116,7 +116,7 @@ jupyter labextension develop . --overwrite To execute them, run: ```sh -pytest -vv -r ap --cov {{ cookiecutter.python_name }} +pytest -vv -r ap --cov {{ python_name }} ```{% endif %} #### Frontend tests diff --git a/{{cookiecutter.python_name}}/RELEASE.md b/template/{{python_name}}/RELEASE.md similarity index 97% rename from {{cookiecutter.python_name}}/RELEASE.md rename to template/{{python_name}}/RELEASE.md index 868956c7..01a5aec5 100644 --- a/{{cookiecutter.python_name}}/RELEASE.md +++ b/template/{{python_name}}/RELEASE.md @@ -1,4 +1,4 @@ -# Making a new release of {{ cookiecutter.python_name }} +# Making a new release of {{ python_name }} The extension can be published to `PyPI` and `npm` manually or using the [Jupyter Releaser](https://github.com/jupyter-server/jupyter_releaser). diff --git a/template/{{python_name}}/install.json b/template/{{python_name}}/install.json new file mode 100644 index 00000000..7c0c6923 --- /dev/null +++ b/template/{{python_name}}/install.json @@ -0,0 +1,5 @@ +{ + "packageManager": "python", + "packageName": "{{ python_name }}", + "uninstallInstructions": "Use your Python package manager (pip, conda, etc.) to uninstall the package {{ python_name }}" +} diff --git a/{{cookiecutter.python_name}}/package.json b/template/{{python_name}}/package.json similarity index 74% rename from {{cookiecutter.python_name}}/package.json rename to template/{{python_name}}/package.json index 77f866e1..9c6d8a48 100644 --- a/{{cookiecutter.python_name}}/package.json +++ b/template/{{python_name}}/package.json @@ -1,33 +1,33 @@ { - "name": "{{ cookiecutter.labextension_name }}", + "name": "{{ labextension_name }}", "version": "0.1.0", - "description": "{{ cookiecutter.project_short_description }}", + "description": "{{ project_short_description }}", "keywords": [ "jupyter", "jupyterlab", "jupyterlab-extension" ], - "homepage": "{{ cookiecutter.repository }}", + "homepage": "{{ repository }}", "bugs": { - "url": "{{ cookiecutter.repository }}/issues" + "url": "{{ repository }}/issues" }, "license": "BSD-3-Clause", "author": { - "name": "{{ cookiecutter.author_name }}", - "email": "{{ cookiecutter.author_email }}" + "name": "{{ author_name }}", + "email": "{{ author_email }}" }, "files": [ "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}", - "style/**/*.{css,js,eot,gif,html,jpg,json,png,svg,woff2,ttf}"{% if cookiecutter.has_settings.lower().startswith('y') %}, + "style/**/*.{css,js,eot,gif,html,jpg,json,png,svg,woff2,ttf}"{% if has_settings %}, "schema/*.json"{% endif %} ], "main": "lib/index.js", - "types": "lib/index.d.ts",{% if cookiecutter.kind != 'theme' %} + "types": "lib/index.d.ts",{% if kind != 'theme' %} "style": "style/index.css",{% endif %} "repository": { "type": "git", - "url": "{{ cookiecutter.repository }}.git" - },{% if cookiecutter.test.lower().startswith('y') %} + "url": "{{ repository }}.git" + },{% if test.lower().startswith('y') %} "workspaces": [ "ui-tests" ],{% endif %} @@ -41,7 +41,7 @@ "clean": "jlpm clean:lib", "clean:lib": "rimraf lib tsconfig.tsbuildinfo", "clean:lintcache": "rimraf .eslintcache .stylelintcache", - "clean:labextension": "rimraf {{ cookiecutter.python_name }}/labextension {{ cookiecutter.python_name }}/_version.py", + "clean:labextension": "rimraf {{ python_name }}/labextension {{ python_name }}/_version.py", "clean:all": "jlpm clean:lib && jlpm clean:labextension && jlpm clean:lintcache", "eslint": "jlpm eslint:check --fix", "eslint:check": "eslint . --cache --ext .ts,.tsx", @@ -52,21 +52,21 @@ "prettier:base": "prettier \"**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}\"", "prettier:check": "jlpm prettier:base --check", "stylelint": "jlpm stylelint:check --fix", - "stylelint:check": "stylelint --cache \"style/**/*.css\"",{% if cookiecutter.test.lower().startswith('y') %} + "stylelint:check": "stylelint --cache \"style/**/*.css\"",{% if test %} "test": "jest --coverage",{% endif %} "watch": "run-p watch:src watch:labextension", "watch:src": "tsc -w", "watch:labextension": "jupyter labextension watch ." }, "dependencies": { - "@jupyterlab/application": "^4.0.0-beta.0"{% if cookiecutter.kind.lower() == 'theme' %}, - "@jupyterlab/apputils": "^4.0.0-beta.0"{% endif %}{% if cookiecutter.has_settings.lower().startswith('y') %}, - "@jupyterlab/settingregistry": "^4.0.0-beta.0"{% endif %}{% if cookiecutter.kind.lower() == 'server' %}, + "@jupyterlab/application": "^4.0.0-beta.0"{% if kind.lower() == 'theme' %}, + "@jupyterlab/apputils": "^4.0.0-beta.0"{% endif %}{% if has_settings.lower().startswith('y') %}, + "@jupyterlab/settingregistry": "^4.0.0-beta.0"{% endif %}{% if kind.lower() == 'server' %}, "@jupyterlab/coreutils": "^6.0.0-beta.0", "@jupyterlab/services": "^7.0.0-beta.0"{% endif %} }, "devDependencies": { - "@jupyterlab/builder": "^4.0.0-beta.0",{% if cookiecutter.test.lower().startswith('y') %} + "@jupyterlab/builder": "^4.0.0-beta.0",{% if test.lower().startswith('y') %} "@jupyterlab/testutils": "^4.0.0-beta.0", "@types/jest": "^29.2.0",{% endif %} "@types/json-schema": "^7.0.11", @@ -76,8 +76,8 @@ "css-loader": "^6.7.1", "eslint": "^8.36.0", "eslint-config-prettier": "^8.7.0", - "eslint-plugin-prettier": "^4.2.1",{% if cookiecutter.test.lower().startswith('y') %} - "jest": "^29.2.0",{% endif %}{% if cookiecutter.kind.lower() == 'server' %} + "eslint-plugin-prettier": "^4.2.1",{% if test.lower().startswith('y') %} + "jest": "^29.2.0",{% endif %}{% if kind.lower() == 'server' %} "mkdirp": "^1.0.3",{% endif %} "npm-run-all": "^4.1.5", "prettier": "^2.8.7", @@ -93,7 +93,7 @@ "yjs": "^13.5.0" }, "sideEffects": [ - "style/*.css"{% if cookiecutter.kind.lower() != 'theme' %}, + "style/*.css"{% if kind.lower() != 'theme' %}, "style/index.js" ], "styleModule": "style/index.js",{% else %} @@ -101,27 +101,27 @@ "publishConfig": { "access": "public" }, - "jupyterlab": { {%- if cookiecutter.kind.lower() == 'server' %} + "jupyterlab": { {%- if kind.lower() == 'server' %} "discovery": { "server": { "managers": [ "pip" ], "base": { - "name": "{{ cookiecutter.python_name }}" + "name": "{{ python_name }}" } } },{% endif %} "extension": true, - "outputDir": "{{cookiecutter.python_name}}/labextension"{% if cookiecutter.has_settings.lower().startswith('y') %}, - "schemaDir": "schema"{% endif %}{% if cookiecutter.kind.lower() == 'theme' %}, + "outputDir": "{{python_name}}/labextension"{% if has_settings %}, + "schemaDir": "schema"{% endif %}{% if kind.lower() == 'theme' %}, "themePath": "style/index.css"{% endif %} }, "eslintIgnore": [ "node_modules", "dist", "coverage", - "**/*.d.ts"{% if cookiecutter.test.lower().startswith('y') %}, + "**/*.d.ts"{% if test.lower().startswith('y') %}, "tests", "**/__tests__", "ui-tests"{% endif %} @@ -195,7 +195,7 @@ "rules": { "property-no-vendor-prefix": null, "selector-no-vendor-prefix": null, - "value-no-vendor-prefix": null{% if cookiecutter.kind.lower() == "theme" %}, + "value-no-vendor-prefix": null{% if kind.lower() == "theme" %}, "alpha-value-notation": null, "color-function-notation": null{% endif %} } diff --git a/{{cookiecutter.python_name}}/pyproject.toml b/template/{{python_name}}/pyproject.toml similarity index 70% rename from {{cookiecutter.python_name}}/pyproject.toml rename to template/{{python_name}}/pyproject.toml index c61dba15..e5c31e16 100644 --- a/{{cookiecutter.python_name}}/pyproject.toml +++ b/template/{{python_name}}/pyproject.toml @@ -3,7 +3,7 @@ requires = ["hatchling>=1.5.0", "jupyterlab>=4.0.0b0,<5", "hatch-nodejs-version" build-backend = "hatchling.build" [project] -name = "{{ cookiecutter.python_name }}" +name = "{{ python_name }}" readme = "README.md" license = { file = "LICENSE" } requires-python = ">=3.8" @@ -21,11 +21,11 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", ] -dependencies = [{% if cookiecutter.kind.lower() == "server" %} +dependencies = [{% if kind.lower() == "server" %} "jupyter_server>=2.0.1,<3"{% endif %} ] dynamic = ["version", "description", "authors", "urls", "keywords"] -{% if cookiecutter.test.lower().startswith('y') and cookiecutter.kind.lower() == 'server' %} +{% if test and kind.lower() == 'server' %} [project.optional-dependencies] test = [ "coverage", @@ -42,26 +42,26 @@ source = "nodejs" fields = ["description", "authors", "urls"] [tool.hatch.build.targets.sdist] -artifacts = ["{{ cookiecutter.python_name }}/labextension"] +artifacts = ["{{ python_name }}/labextension"] exclude = [".github", "binder"] [tool.hatch.build.targets.wheel.shared-data] -"{{ cookiecutter.python_name }}/labextension" = "share/jupyter/labextensions/{{ cookiecutter.labextension_name }}" -"install.json" = "share/jupyter/labextensions/{{ cookiecutter.labextension_name }}/install.json"{% if cookiecutter.kind.lower() == "server" %} +"{{ python_name }}/labextension" = "share/jupyter/labextensions/{{ labextension_name }}" +"install.json" = "share/jupyter/labextensions/{{ labextension_name }}/install.json"{% if kind.lower() == "server" %} "jupyter-config/server-config" = "etc/jupyter/jupyter_server_config.d" "jupyter-config/nb-config" = "etc/jupyter/jupyter_notebook_config.d"{% endif %} [tool.hatch.build.hooks.version] -path = "{{ cookiecutter.python_name }}/_version.py" +path = "{{ python_name }}/_version.py" [tool.hatch.build.hooks.jupyter-builder] dependencies = ["hatch-jupyter-builder>=0.5"] build-function = "hatch_jupyter_builder.npm_builder" -ensured-targets = [{% if cookiecutter.kind.lower() != "theme" %} - "{{ cookiecutter.python_name }}/labextension/static/style.js",{% endif %} - "{{ cookiecutter.python_name }}/labextension/package.json", +ensured-targets = [{% if kind.lower() != "theme" %} + "{{ python_name }}/labextension/static/style.js",{% endif %} + "{{ python_name }}/labextension/package.json", ] -skip-if-exists = ["{{ cookiecutter.python_name }}/labextension/static/style.js"] +skip-if-exists = ["{{ python_name }}/labextension/static/style.js"] [tool.hatch.build.hooks.jupyter-builder.build-kwargs] build_cmd = "build:prod" @@ -71,7 +71,7 @@ npm = ["jlpm"] build_cmd = "install:extension" npm = ["jlpm"] source_dir = "src" -build_dir = "{{cookiecutter.python_name}}/labextension" +build_dir = "{{python_name}}/labextension" [tool.jupyter-releaser.options] version_cmd = "hatch version" diff --git a/{{cookiecutter.python_name}}/setup.py b/template/{{python_name}}/setup.py similarity index 100% rename from {{cookiecutter.python_name}}/setup.py rename to template/{{python_name}}/setup.py diff --git a/template/{{python_name}}/src/index.ts b/template/{{python_name}}/src/index.ts new file mode 100644 index 00000000..baa98b8c --- /dev/null +++ b/template/{{python_name}}/src/index.ts @@ -0,0 +1,54 @@ +import { + JupyterFrontEnd, + JupyterFrontEndPlugin +} from '@jupyterlab/application';{% if kind.lower() == 'theme' %} + +import { IThemeManager } from '@jupyterlab/apputils';{% endif %}{% if has_settings %} + +import { ISettingRegistry } from '@jupyterlab/settingregistry';{% endif %}{% if kind.lower() == 'server' %} + +import { requestAPI } from './handler';{% endif %} + +/** + * Initialization data for the {{ labextension_name }} extension. + */ +const plugin: JupyterFrontEndPlugin = { + id: '{{ labextension_name }}:plugin', + autoStart: true,{% if kind.lower() == 'theme' %} + requires: [IThemeManager],{% endif %}{% if has_settings %} + optional: [ISettingRegistry],{% endif %} + activate: (app: JupyterFrontEnd{% if kind.lower() == 'theme' %}, manager: IThemeManager{% endif %}{% if has_settings %}, settingRegistry: ISettingRegistry | null{% endif %}) => { + console.log('JupyterLab extension {{ labextension_name }} is activated!');{% if kind.lower() == 'theme' %} + const style = '{{ labextension_name }}/index.css'; + + manager.register({ + name: '{{ labextension_name }}', + isLight: true, + load: () => manager.loadCSS(style), + unload: () => Promise.resolve(undefined) + });{% endif %}{% if has_settings %} + + if (settingRegistry) { + settingRegistry + .load(plugin.id) + .then(settings => { + console.log('{{ labextension_name }} settings loaded:', settings.composite); + }) + .catch(reason => { + console.error('Failed to load settings for {{ labextension_name }}.', reason); + }); + }{% endif %}{% if kind.lower() == 'server' %} + + requestAPI('get_example') + .then(data => { + console.log(data); + }) + .catch(reason => { + console.error( + `The {{ python_name }} server extension appears to be missing.\n${reason}` + ); + });{% endif %} + } +}; + +export default plugin; diff --git a/{{cookiecutter.python_name}}/src/handler.ts b/template/{{python_name}}/src/{% if kind == 'server' %}handler.ts{% endif %} similarity index 93% rename from {{cookiecutter.python_name}}/src/handler.ts rename to template/{{python_name}}/src/{% if kind == 'server' %}handler.ts{% endif %} index 5983bcec..a7fcadb2 100644 --- a/{{cookiecutter.python_name}}/src/handler.ts +++ b/template/{{python_name}}/src/{% if kind == 'server' %}handler.ts{% endif %} @@ -17,7 +17,7 @@ export async function requestAPI( const settings = ServerConnection.makeSettings(); const requestUrl = URLExt.join( settings.baseUrl, - '{{ cookiecutter.python_name | replace("_", "-") }}', // API Namespace + '{{ python_name | replace("_", "-") }}', // API Namespace endPoint ); diff --git a/{{cookiecutter.python_name}}/src/__tests__/{{cookiecutter.python_name}}.spec.ts b/template/{{python_name}}/src/{% if test %}__tests__{% endif %}/{{python_name}}.spec.ts similarity index 72% rename from {{cookiecutter.python_name}}/src/__tests__/{{cookiecutter.python_name}}.spec.ts rename to template/{{python_name}}/src/{% if test %}__tests__{% endif %}/{{python_name}}.spec.ts index 244d0548..e46bde14 100644 --- a/{{cookiecutter.python_name}}/src/__tests__/{{cookiecutter.python_name}}.spec.ts +++ b/template/{{python_name}}/src/{% if test %}__tests__{% endif %}/{{python_name}}.spec.ts @@ -2,7 +2,7 @@ * Example of [Jest](https://jestjs.io/docs/getting-started) unit tests */ -describe('{{ cookiecutter.labextension_name }}', () => { +describe('{{ labextension_name }}', () => { it('should be tested', () => { expect(1 + 1).toEqual(2); }); diff --git a/{{cookiecutter.python_name}}/style/base.css b/template/{{python_name}}/style/base.css similarity index 100% rename from {{cookiecutter.python_name}}/style/base.css rename to template/{{python_name}}/style/base.css diff --git a/{{cookiecutter.python_name}}/style/index.css b/template/{{python_name}}/style/index.css similarity index 77% rename from {{cookiecutter.python_name}}/style/index.css rename to template/{{python_name}}/style/index.css index 0f7a8504..ab398fd7 100644 --- a/{{cookiecutter.python_name}}/style/index.css +++ b/template/{{python_name}}/style/index.css @@ -1,4 +1,4 @@ -{% if cookiecutter.kind.lower() == 'theme' %}@import './variables.css'; +{% if kind.lower() == 'theme' %}@import './variables.css'; /* Set the default typography for monospace elements */ tt, diff --git a/{{cookiecutter.python_name}}/style/index.js b/template/{{python_name}}/style/index.js similarity index 100% rename from {{cookiecutter.python_name}}/style/index.js rename to template/{{python_name}}/style/index.js diff --git a/{{cookiecutter.python_name}}/style/variables.css b/template/{{python_name}}/style/{% if kind = 'theme' %}variables.css{% endif %} similarity index 100% rename from {{cookiecutter.python_name}}/style/variables.css rename to template/{{python_name}}/style/{% if kind = 'theme' %}variables.css{% endif %} diff --git a/{{cookiecutter.python_name}}/tsconfig.json b/template/{{python_name}}/tsconfig.json similarity index 86% rename from {{cookiecutter.python_name}}/tsconfig.json rename to template/{{python_name}}/tsconfig.json index e1a6d682..ab2361ab 100644 --- a/{{cookiecutter.python_name}}/tsconfig.json +++ b/template/{{python_name}}/tsconfig.json @@ -18,7 +18,7 @@ "strict": true, "strictNullChecks": true, "target": "ES2018", - "types": [{% if cookiecutter.test.lower().startswith('y') %}"jest"{% endif %}] + "types": [{% if test %}"jest"{% endif %}] }, "include": ["src/*"] } diff --git a/{{cookiecutter.python_name}}/binder/environment.yml b/template/{{python_name}}/{% if has_binder %}binder{% endif %}/environment.yml similarity index 63% rename from {{cookiecutter.python_name}}/binder/environment.yml rename to template/{{python_name}}/{% if has_binder %}binder{% endif %}/environment.yml index 04fc5478..b64f4e6c 100644 --- a/{{cookiecutter.python_name}}/binder/environment.yml +++ b/template/{{python_name}}/{% if has_binder %}binder{% endif %}/environment.yml @@ -1,10 +1,10 @@ -# a mybinder.org-ready environment for demoing {{ cookiecutter.python_name }} +# a mybinder.org-ready environment for demoing {{ python_name }} # this environment may also be used locally on Linux/MacOS/Windows, e.g. # # conda env update --file binder/environment.yml -# conda activate {{ cookiecutter.python_name | replace('_', '-') }}-demo +# conda activate {{ python_name | replace('_', '-') }}-demo # -name: {{ cookiecutter.python_name | replace('_', '-') }}-demo +name: {{ python_name | replace('_', '-') }}-demo channels: - conda-forge diff --git a/{{cookiecutter.python_name}}/binder/postBuild b/template/{{python_name}}/{% if has_binder %}binder{% endif %}/postBuild similarity index 83% rename from {{cookiecutter.python_name}}/binder/postBuild rename to template/{{python_name}}/{% if has_binder %}binder{% endif %}/postBuild index 9dcd2aed..574f61c9 100755 --- a/{{cookiecutter.python_name}}/binder/postBuild +++ b/template/{{python_name}}/{% if has_binder %}binder{% endif %}/postBuild @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -""" perform a development install of {{ cookiecutter.python_name }} +""" perform a development install of {{ python_name }} On Binder, this will run _after_ the environment has been fully created from the environment.yml in this directory. @@ -31,7 +31,7 @@ _(sys.executable, "-m", "pip", "check") # install the labextension _(sys.executable, "-m", "pip", "install", "-e", ".") -_(sys.executable, "-m", "jupyter", "labextension", "develop", "--overwrite", "."){% if cookiecutter.kind.lower() == 'server' %} +_(sys.executable, "-m", "jupyter", "labextension", "develop", "--overwrite", "."){% if kind.lower() == 'server' %} _( sys.executable, "-m", @@ -39,7 +39,7 @@ _( "server", "extension", "enable", - "{{ cookiecutter.python_name }}", + "{{ python_name }}", ){% endif %} # verify the environment the extension didn't break anything @@ -52,5 +52,5 @@ _("jupyter", "server", "extension", "list") _("jupyter", "labextension", "list") -print("JupyterLab with {{ cookiecutter.python_name }} is ready to run with:\n") +print("JupyterLab with {{ python_name }} is ready to run with:\n") print("\tjupyter lab\n") diff --git a/template/{{python_name}}/{% if has_settings %}schema{% endif %}/plugin.json b/template/{{python_name}}/{% if has_settings %}schema{% endif %}/plugin.json new file mode 100644 index 00000000..db471da1 --- /dev/null +++ b/template/{{python_name}}/{% if has_settings %}schema{% endif %}/plugin.json @@ -0,0 +1,8 @@ +{ + "jupyter.lab.shortcuts": [], + "title": "{{ labextension_name }}", + "description": "{{ labextension_name }} settings.", + "type": "object", + "properties": {}, + "additionalProperties": false +} diff --git a/{{cookiecutter.python_name}}/jupyter-config/nb-config/{{cookiecutter.python_name}}.json b/template/{{python_name}}/{% if kind == 'server' %}jupyter-config{% endif %}/nb-config/{{python_name}}.json similarity index 57% rename from {{cookiecutter.python_name}}/jupyter-config/nb-config/{{cookiecutter.python_name}}.json rename to template/{{python_name}}/{% if kind == 'server' %}jupyter-config{% endif %}/nb-config/{{python_name}}.json index 6608b4f3..b333662f 100644 --- a/{{cookiecutter.python_name}}/jupyter-config/nb-config/{{cookiecutter.python_name}}.json +++ b/template/{{python_name}}/{% if kind == 'server' %}jupyter-config{% endif %}/nb-config/{{python_name}}.json @@ -1,7 +1,7 @@ { "NotebookApp": { "nbserver_extensions": { - "{{ cookiecutter.python_name }}": true + "{{ python_name }}": true } } } diff --git a/{{cookiecutter.python_name}}/jupyter-config/server-config/{{cookiecutter.python_name}}.json b/template/{{python_name}}/{% if kind == 'server' %}jupyter-config{% endif %}/server-config/{{python_name}}.json similarity index 57% rename from {{cookiecutter.python_name}}/jupyter-config/server-config/{{cookiecutter.python_name}}.json rename to template/{{python_name}}/{% if kind == 'server' %}jupyter-config{% endif %}/server-config/{{python_name}}.json index c9cacde2..e5b8b13f 100644 --- a/{{cookiecutter.python_name}}/jupyter-config/server-config/{{cookiecutter.python_name}}.json +++ b/template/{{python_name}}/{% if kind == 'server' %}jupyter-config{% endif %}/server-config/{{python_name}}.json @@ -1,7 +1,7 @@ { "ServerApp": { "jpserver_extensions": { - "{{ cookiecutter.python_name }}": true + "{{ python_name }}": true } } } diff --git a/{{cookiecutter.python_name}}/babel.config.js b/template/{{python_name}}/{% if test %}babel.config.js{% endif %} similarity index 100% rename from {{cookiecutter.python_name}}/babel.config.js rename to template/{{python_name}}/{% if test %}babel.config.js{% endif %} diff --git a/{{cookiecutter.python_name}}/conftest.py b/template/{{python_name}}/{% if test %}conftest.py{% endif %} similarity index 57% rename from {{cookiecutter.python_name}}/conftest.py rename to template/{{python_name}}/{% if test %}conftest.py{% endif %} index 912c2a6a..c991429b 100644 --- a/{{cookiecutter.python_name}}/conftest.py +++ b/template/{{python_name}}/{% if test %}conftest.py{% endif %} @@ -5,4 +5,4 @@ @pytest.fixture def jp_server_config(jp_server_config): - return {"ServerApp": {"jpserver_extensions": {"{{ cookiecutter.python_name }}": True}}} + return {"ServerApp": {"jpserver_extensions": {"{{ python_name }}": True}}} diff --git a/{{cookiecutter.python_name}}/jest.config.js b/template/{{python_name}}/{% if test %}jest.config.js{% endif %} similarity index 100% rename from {{cookiecutter.python_name}}/jest.config.js rename to template/{{python_name}}/{% if test %}jest.config.js{% endif %} diff --git a/{{cookiecutter.python_name}}/tsconfig.test.json b/template/{{python_name}}/{% if test %}tsconfig.test.json{% endif %} similarity index 100% rename from {{cookiecutter.python_name}}/tsconfig.test.json rename to template/{{python_name}}/{% if test %}tsconfig.test.json{% endif %} diff --git a/{{cookiecutter.python_name}}/ui-tests/README.md b/template/{{python_name}}/{% if test %}ui-tests{% endif %}/README.md similarity index 100% rename from {{cookiecutter.python_name}}/ui-tests/README.md rename to template/{{python_name}}/{% if test %}ui-tests{% endif %}/README.md diff --git a/{{cookiecutter.python_name}}/ui-tests/jupyter_server_test_config.py b/template/{{python_name}}/{% if test %}ui-tests{% endif %}/jupyter_server_test_config.py similarity index 100% rename from {{cookiecutter.python_name}}/ui-tests/jupyter_server_test_config.py rename to template/{{python_name}}/{% if test %}ui-tests{% endif %}/jupyter_server_test_config.py diff --git a/{{cookiecutter.python_name}}/ui-tests/package.json b/template/{{python_name}}/{% if test %}ui-tests{% endif %}/package.json similarity index 69% rename from {{cookiecutter.python_name}}/ui-tests/package.json rename to template/{{python_name}}/{% if test %}ui-tests{% endif %}/package.json index 24c461dc..670652e1 100644 --- a/{{cookiecutter.python_name}}/ui-tests/package.json +++ b/template/{{python_name}}/{% if test %}ui-tests{% endif %}/package.json @@ -1,7 +1,7 @@ { - "name": "{{ cookiecutter.labextension_name }}-ui-tests", + "name": "{{ labextension_name }}-ui-tests", "version": "1.0.0", - "description": "JupyterLab {{ cookiecutter.labextension_name }} Integration Tests", + "description": "JupyterLab {{ labextension_name }} Integration Tests", "private": true, "scripts": { "start": "jupyter lab --config jupyter_server_test_config.py", diff --git a/{{cookiecutter.python_name}}/ui-tests/playwright.config.js b/template/{{python_name}}/{% if test %}ui-tests{% endif %}/playwright.config.js similarity index 100% rename from {{cookiecutter.python_name}}/ui-tests/playwright.config.js rename to template/{{python_name}}/{% if test %}ui-tests{% endif %}/playwright.config.js diff --git a/{{cookiecutter.python_name}}/ui-tests/tests/{{cookiecutter.python_name}}.spec.ts b/template/{{python_name}}/{% if test %}ui-tests{% endif %}/tests/{{python_name}}.spec.ts similarity index 81% rename from {{cookiecutter.python_name}}/ui-tests/tests/{{cookiecutter.python_name}}.spec.ts rename to template/{{python_name}}/{% if test %}ui-tests{% endif %}/tests/{{python_name}}.spec.ts index a0c95499..f57d2f2b 100644 --- a/{{cookiecutter.python_name}}/ui-tests/tests/{{cookiecutter.python_name}}.spec.ts +++ b/template/{{python_name}}/{% if test %}ui-tests{% endif %}/tests/{{python_name}}.spec.ts @@ -16,6 +16,6 @@ test('should emit an activation console message', async ({ page }) => { await page.goto(); expect( - logs.filter(s => s === 'JupyterLab extension {{ cookiecutter.labextension_name }} is activated!') + logs.filter(s => s === 'JupyterLab extension {{ labextension_name }} is activated!') ).toHaveLength(1); }); diff --git a/{{cookiecutter.python_name}}/ui-tests/yarn.lock b/template/{{python_name}}/{% if test %}ui-tests{% endif %}/yarn.lock similarity index 100% rename from {{cookiecutter.python_name}}/ui-tests/yarn.lock rename to template/{{python_name}}/{% if test %}ui-tests{% endif %}/yarn.lock diff --git a/{{cookiecutter.python_name}}/{{cookiecutter.python_name}}/__init__.py b/template/{{python_name}}/{{python_name}}/__init__.py similarity index 72% rename from {{cookiecutter.python_name}}/{{cookiecutter.python_name}}/__init__.py rename to template/{{python_name}}/{{python_name}}/__init__.py index 0261bc9d..4e6c8ec2 100644 --- a/{{cookiecutter.python_name}}/{{cookiecutter.python_name}}/__init__.py +++ b/template/{{python_name}}/{{python_name}}/__init__.py @@ -1,4 +1,4 @@ -from ._version import __version__{% if cookiecutter.kind.lower() == 'server' %} +from ._version import __version__{% if kind.lower() == 'server' %} from .handlers import setup_handlers {% endif %} @@ -6,14 +6,14 @@ def _jupyter_labextension_paths(): return [{ "src": "labextension", - "dest": "{{ cookiecutter.labextension_name }}" + "dest": "{{ labextension_name }}" }] -{% if cookiecutter.kind.lower() == 'server' %} +{% if kind.lower() == 'server' %} def _jupyter_server_extension_points(): return [{ - "module": "{{ cookiecutter.python_name }}" + "module": "{{ python_name }}" }] @@ -26,7 +26,7 @@ def _load_jupyter_server_extension(server_app): JupyterLab application instance """ setup_handlers(server_app.web_app) - name = "{{ cookiecutter.python_name }}" + name = "{{ python_name }}" server_app.log.info(f"Registered {name} server extension") diff --git a/{{cookiecutter.python_name}}/{{cookiecutter.python_name}}/handlers.py b/template/{{python_name}}/{{python_name}}/{% if kind == 'server' %}handlers.py{% endif %} similarity index 74% rename from {{cookiecutter.python_name}}/{{cookiecutter.python_name}}/handlers.py rename to template/{{python_name}}/{{python_name}}/{% if kind == 'server' %}handlers.py{% endif %} index e296e70d..c3db9fc3 100644 --- a/{{cookiecutter.python_name}}/{{cookiecutter.python_name}}/handlers.py +++ b/template/{{python_name}}/{{python_name}}/{% if kind == 'server' %}handlers.py{% endif %} @@ -11,7 +11,7 @@ class RouteHandler(APIHandler): @tornado.web.authenticated def get(self): self.finish(json.dumps({ - "data": "This is /{{ cookiecutter.python_name | replace('_', '-') }}/get_example endpoint!" + "data": "This is /{{ python_name | replace('_', '-') }}/get_example endpoint!" })) @@ -19,6 +19,6 @@ def setup_handlers(web_app): host_pattern = ".*$" base_url = web_app.settings["base_url"] - route_pattern = url_path_join(base_url, "{{ cookiecutter.python_name | replace('_', '-') }}", "get_example") + route_pattern = url_path_join(base_url, "{{ python_name | replace('_', '-') }}", "get_example") handlers = [(route_pattern, RouteHandler)] web_app.add_handlers(host_pattern, handlers) diff --git a/template/{{python_name}}/{{python_name}}/{% if test %}tests{% endif %}/__init__.py b/template/{{python_name}}/{{python_name}}/{% if test %}tests{% endif %}/__init__.py new file mode 100644 index 00000000..8bad5b27 --- /dev/null +++ b/template/{{python_name}}/{{python_name}}/{% if test %}tests{% endif %}/__init__.py @@ -0,0 +1 @@ +"""Python unit tests for {{ python_name }}.""" diff --git a/template/{{python_name}}/{{python_name}}/{% if test %}tests{% endif %}/test_handlers.py b/template/{{python_name}}/{{python_name}}/{% if test %}tests{% endif %}/test_handlers.py new file mode 100644 index 00000000..c9b7f4db --- /dev/null +++ b/template/{{python_name}}/{{python_name}}/{% if test %}tests{% endif %}/test_handlers.py @@ -0,0 +1,13 @@ +import json + + +async def test_get_example(jp_fetch): + # When + response = await jp_fetch("{{ python_name | replace('_', '-') }}", "get_example") + + # Then + assert response.code == 200 + payload = json.loads(response.body) + assert payload == { + "data": "This is /{{ python_name | replace('_', '-') }}/get_example endpoint!" + } \ No newline at end of file diff --git a/{{cookiecutter.python_name}}/install.json b/{{cookiecutter.python_name}}/install.json deleted file mode 100644 index df7b7f49..00000000 --- a/{{cookiecutter.python_name}}/install.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "packageManager": "python", - "packageName": "{{ cookiecutter.python_name }}", - "uninstallInstructions": "Use your Python package manager (pip, conda, etc.) to uninstall the package {{ cookiecutter.python_name }}" -} diff --git a/{{cookiecutter.python_name}}/schema/plugin.json b/{{cookiecutter.python_name}}/schema/plugin.json deleted file mode 100644 index 8ad57396..00000000 --- a/{{cookiecutter.python_name}}/schema/plugin.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "jupyter.lab.shortcuts": [], - "title": "{{ cookiecutter.labextension_name }}", - "description": "{{ cookiecutter.labextension_name }} settings.", - "type": "object", - "properties": {}, - "additionalProperties": false -} diff --git a/{{cookiecutter.python_name}}/src/index.ts b/{{cookiecutter.python_name}}/src/index.ts deleted file mode 100644 index 3248fcfd..00000000 --- a/{{cookiecutter.python_name}}/src/index.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { - JupyterFrontEnd, - JupyterFrontEndPlugin -} from '@jupyterlab/application';{% if cookiecutter.kind.lower() == 'theme' %} - -import { IThemeManager } from '@jupyterlab/apputils';{% endif %}{% if cookiecutter.has_settings.lower().startswith('y') %} - -import { ISettingRegistry } from '@jupyterlab/settingregistry';{% endif %}{% if cookiecutter.kind.lower() == 'server' %} - -import { requestAPI } from './handler';{% endif %} - -/** - * Initialization data for the {{ cookiecutter.labextension_name }} extension. - */ -const plugin: JupyterFrontEndPlugin = { - id: '{{ cookiecutter.labextension_name }}:plugin', - autoStart: true,{% if cookiecutter.kind.lower() == 'theme' %} - requires: [IThemeManager],{% endif %}{% if cookiecutter.has_settings.lower().startswith('y') %} - optional: [ISettingRegistry],{% endif %} - activate: (app: JupyterFrontEnd{% if cookiecutter.kind.lower() == 'theme' %}, manager: IThemeManager{% endif %}{% if cookiecutter.has_settings.lower().startswith('y') %}, settingRegistry: ISettingRegistry | null{% endif %}) => { - console.log('JupyterLab extension {{ cookiecutter.labextension_name }} is activated!');{% if cookiecutter.kind.lower() == 'theme' %} - const style = '{{ cookiecutter.labextension_name }}/index.css'; - - manager.register({ - name: '{{ cookiecutter.labextension_name }}', - isLight: true, - load: () => manager.loadCSS(style), - unload: () => Promise.resolve(undefined) - });{% endif %}{% if cookiecutter.has_settings.lower().startswith('y') %} - - if (settingRegistry) { - settingRegistry - .load(plugin.id) - .then(settings => { - console.log('{{ cookiecutter.labextension_name }} settings loaded:', settings.composite); - }) - .catch(reason => { - console.error('Failed to load settings for {{ cookiecutter.labextension_name }}.', reason); - }); - }{% endif %}{% if cookiecutter.kind.lower() == 'server' %} - - requestAPI('get_example') - .then(data => { - console.log(data); - }) - .catch(reason => { - console.error( - `The {{ cookiecutter.python_name }} server extension appears to be missing.\n${reason}` - ); - });{% endif %} - } -}; - -export default plugin; diff --git a/{{cookiecutter.python_name}}/{{cookiecutter.python_name}}/tests/__init__.py b/{{cookiecutter.python_name}}/{{cookiecutter.python_name}}/tests/__init__.py deleted file mode 100644 index edc5557d..00000000 --- a/{{cookiecutter.python_name}}/{{cookiecutter.python_name}}/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Python unit tests for {{ cookiecutter.python_name }}.""" diff --git a/{{cookiecutter.python_name}}/{{cookiecutter.python_name}}/tests/test_handlers.py b/{{cookiecutter.python_name}}/{{cookiecutter.python_name}}/tests/test_handlers.py deleted file mode 100644 index f8df064b..00000000 --- a/{{cookiecutter.python_name}}/{{cookiecutter.python_name}}/tests/test_handlers.py +++ /dev/null @@ -1,13 +0,0 @@ -import json - - -async def test_get_example(jp_fetch): - # When - response = await jp_fetch("{{ cookiecutter.python_name | replace('_', '-') }}", "get_example") - - # Then - assert response.code == 200 - payload = json.loads(response.body) - assert payload == { - "data": "This is /{{ cookiecutter.python_name | replace('_', '-') }}/get_example endpoint!" - } \ No newline at end of file From d1e07d5cdf34d4f392ddacb5363b33081a8d49ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Collonval?= Date: Wed, 12 Apr 2023 16:50:26 +0200 Subject: [PATCH 2/6] Fix bugs --- .github/workflows/main.yml | 2 +- copier.yml | 8 +- .../.github/workflows/build.yml | 0 .../.github/workflows/check-release.yml | 0 .../.github/workflows/enforce-label.yml | 0 .../.github/workflows/prep-release.yml | 0 .../.github/workflows/publish-release.yml | 0 ...f has_binder %}binder-on-pr.yml{% endif %} | 0 ... %}update-integration-tests.yml{% endif %} | 0 template/.gitignore | 125 ++++++++++++++++++ .../{{{python_name}} => }/.prettierignore | 0 template/{{{python_name}} => }/CHANGELOG.md | 0 template/{{{python_name}} => }/LICENSE | 0 template/{{{python_name}} => }/README.md | 0 template/{{{python_name}} => }/RELEASE.md | 0 template/{{{python_name}} => }/install.json | 0 template/{{{python_name}} => }/package.json | 0 template/{{{python_name}} => }/pyproject.toml | 0 template/{{{python_name}} => }/setup.py | 0 template/{{{python_name}} => }/src/index.ts | 0 ...f kind == 'server' %}handler.ts{% endif %} | 0 .../{{python_name}}.spec.ts | 0 template/{{{python_name}} => }/style/base.css | 0 .../{{{python_name}} => }/style/index.css | 0 template/{{{python_name}} => }/style/index.js | 0 ...ind == 'theme' %}variables.css{% endif %}} | 0 template/{{{python_name}} => }/tsconfig.json | 0 .../environment.yml | 0 .../postBuild | 0 .../plugin.json | 0 .../nb-config/{{python_name}}.json | 0 .../server-config/{{python_name}}.json | 0 .../{% if test %}babel.config.js{% endif %} | 0 .../{% if test %}conftest.py{% endif %} | 0 .../{% if test %}jest.config.js{% endif %} | 0 ...{% if test %}tsconfig.test.json{% endif %} | 0 .../README.md | 0 .../jupyter_server_test_config.py | 0 .../package.json | 0 .../playwright.config.js | 0 .../tests/{{python_name}}.spec.ts | 0 .../yarn.lock | 0 template/{{_copier_conf.answers_file}}.jinja | 2 + .../{{{python_name}} => }/__init__.py | 0 ... kind == 'server' %}handlers.py{% endif %} | 0 .../{% if test %}tests{% endif %}/__init__.py | 0 .../test_handlers.py | 0 47 files changed, 129 insertions(+), 8 deletions(-) rename template/{{{python_name}} => }/.github/workflows/build.yml (100%) rename template/{{{python_name}} => }/.github/workflows/check-release.yml (100%) rename template/{{{python_name}} => }/.github/workflows/enforce-label.yml (100%) rename template/{{{python_name}} => }/.github/workflows/prep-release.yml (100%) rename template/{{{python_name}} => }/.github/workflows/publish-release.yml (100%) rename template/{{{python_name}} => }/.github/workflows/{% if has_binder %}binder-on-pr.yml{% endif %} (100%) rename template/{{{python_name}} => }/.github/workflows/{% if test %}update-integration-tests.yml{% endif %} (100%) create mode 100644 template/.gitignore rename template/{{{python_name}} => }/.prettierignore (100%) rename template/{{{python_name}} => }/CHANGELOG.md (100%) rename template/{{{python_name}} => }/LICENSE (100%) rename template/{{{python_name}} => }/README.md (100%) rename template/{{{python_name}} => }/RELEASE.md (100%) rename template/{{{python_name}} => }/install.json (100%) rename template/{{{python_name}} => }/package.json (100%) rename template/{{{python_name}} => }/pyproject.toml (100%) rename template/{{{python_name}} => }/setup.py (100%) rename template/{{{python_name}} => }/src/index.ts (100%) rename template/{{{python_name}} => }/src/{% if kind == 'server' %}handler.ts{% endif %} (100%) rename template/{{{python_name}} => }/src/{% if test %}__tests__{% endif %}/{{python_name}}.spec.ts (100%) rename template/{{{python_name}} => }/style/base.css (100%) rename template/{{{python_name}} => }/style/index.css (100%) rename template/{{{python_name}} => }/style/index.js (100%) rename template/{{{python_name}}/style/{% if kind = 'theme' %}variables.css{% endif %} => style/{% if kind == 'theme' %}variables.css{% endif %}} (100%) rename template/{{{python_name}} => }/tsconfig.json (100%) rename template/{{{python_name}} => }/{% if has_binder %}binder{% endif %}/environment.yml (100%) rename template/{{{python_name}} => }/{% if has_binder %}binder{% endif %}/postBuild (100%) rename template/{{{python_name}} => }/{% if has_settings %}schema{% endif %}/plugin.json (100%) rename template/{{{python_name}} => }/{% if kind == 'server' %}jupyter-config{% endif %}/nb-config/{{python_name}}.json (100%) rename template/{{{python_name}} => }/{% if kind == 'server' %}jupyter-config{% endif %}/server-config/{{python_name}}.json (100%) rename template/{{{python_name}} => }/{% if test %}babel.config.js{% endif %} (100%) rename template/{{{python_name}} => }/{% if test %}conftest.py{% endif %} (100%) rename template/{{{python_name}} => }/{% if test %}jest.config.js{% endif %} (100%) rename template/{{{python_name}} => }/{% if test %}tsconfig.test.json{% endif %} (100%) rename template/{{{python_name}} => }/{% if test %}ui-tests{% endif %}/README.md (100%) rename template/{{{python_name}} => }/{% if test %}ui-tests{% endif %}/jupyter_server_test_config.py (100%) rename template/{{{python_name}} => }/{% if test %}ui-tests{% endif %}/package.json (100%) rename template/{{{python_name}} => }/{% if test %}ui-tests{% endif %}/playwright.config.js (100%) rename template/{{{python_name}} => }/{% if test %}ui-tests{% endif %}/tests/{{python_name}}.spec.ts (100%) rename template/{{{python_name}} => }/{% if test %}ui-tests{% endif %}/yarn.lock (100%) create mode 100644 template/{{_copier_conf.answers_file}}.jinja rename template/{{python_name}}/{{{python_name}} => }/__init__.py (100%) rename template/{{python_name}}/{{{python_name}} => }/{% if kind == 'server' %}handlers.py{% endif %} (100%) rename template/{{python_name}}/{{{python_name}} => }/{% if test %}tests{% endif %}/__init__.py (100%) rename template/{{python_name}}/{{{python_name}} => }/{% if test %}tests{% endif %}/test_handlers.py (100%) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 09904533..84e7282e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -30,7 +30,7 @@ jobs: - name: Install dependencies run: | - python -m pip install cookiecutter + python -m pip install copier>=7.1.0 - name: Create pure frontend extension env: diff --git a/copier.yml b/copier.yml index 8bfb4064..358bc1ca 100644 --- a/copier.yml +++ b/copier.yml @@ -1,11 +1,5 @@ -_min_copier_version: "6.2.0" +_min_copier_version: "7.1.0" _subdirectory: template -_exclude: - - ".github" - - "hooks" - - "cookiecutter.json" - - "LICENSE" - - "README.md" kind: type: str diff --git a/template/{{python_name}}/.github/workflows/build.yml b/template/.github/workflows/build.yml similarity index 100% rename from template/{{python_name}}/.github/workflows/build.yml rename to template/.github/workflows/build.yml diff --git a/template/{{python_name}}/.github/workflows/check-release.yml b/template/.github/workflows/check-release.yml similarity index 100% rename from template/{{python_name}}/.github/workflows/check-release.yml rename to template/.github/workflows/check-release.yml diff --git a/template/{{python_name}}/.github/workflows/enforce-label.yml b/template/.github/workflows/enforce-label.yml similarity index 100% rename from template/{{python_name}}/.github/workflows/enforce-label.yml rename to template/.github/workflows/enforce-label.yml diff --git a/template/{{python_name}}/.github/workflows/prep-release.yml b/template/.github/workflows/prep-release.yml similarity index 100% rename from template/{{python_name}}/.github/workflows/prep-release.yml rename to template/.github/workflows/prep-release.yml diff --git a/template/{{python_name}}/.github/workflows/publish-release.yml b/template/.github/workflows/publish-release.yml similarity index 100% rename from template/{{python_name}}/.github/workflows/publish-release.yml rename to template/.github/workflows/publish-release.yml diff --git a/template/{{python_name}}/.github/workflows/{% if has_binder %}binder-on-pr.yml{% endif %} b/template/.github/workflows/{% if has_binder %}binder-on-pr.yml{% endif %} similarity index 100% rename from template/{{python_name}}/.github/workflows/{% if has_binder %}binder-on-pr.yml{% endif %} rename to template/.github/workflows/{% if has_binder %}binder-on-pr.yml{% endif %} diff --git a/template/{{python_name}}/.github/workflows/{% if test %}update-integration-tests.yml{% endif %} b/template/.github/workflows/{% if test %}update-integration-tests.yml{% endif %} similarity index 100% rename from template/{{python_name}}/.github/workflows/{% if test %}update-integration-tests.yml{% endif %} rename to template/.github/workflows/{% if test %}update-integration-tests.yml{% endif %} diff --git a/template/.gitignore b/template/.gitignore new file mode 100644 index 00000000..be835527 --- /dev/null +++ b/template/.gitignore @@ -0,0 +1,125 @@ +*.bundle.* +lib/ +node_modules/ +*.log +.eslintcache +.stylelintcache +*.egg-info/ +.ipynb_checkpoints +*.tsbuildinfo +{{python_name}}/labextension +# Version file is handled by hatchling +{{cookiecutter.python_name}}/_version.py +{% if cookiecutter.test.lower().startswith('y') %} +# Integration tests +ui-tests/test-results/ +ui-tests/playwright-report/ +{% endif %} +# Created by https://www.gitignore.io/api/python +# Edit at https://www.gitignore.io/?templates=python + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage/ +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# Mr Developer +.mr.developer.cfg +.project +.pydevproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# End of https://www.gitignore.io/api/python + +# OSX files +.DS_Store + +# Yarn cache +.yarn/ diff --git a/template/{{python_name}}/.prettierignore b/template/.prettierignore similarity index 100% rename from template/{{python_name}}/.prettierignore rename to template/.prettierignore diff --git a/template/{{python_name}}/CHANGELOG.md b/template/CHANGELOG.md similarity index 100% rename from template/{{python_name}}/CHANGELOG.md rename to template/CHANGELOG.md diff --git a/template/{{python_name}}/LICENSE b/template/LICENSE similarity index 100% rename from template/{{python_name}}/LICENSE rename to template/LICENSE diff --git a/template/{{python_name}}/README.md b/template/README.md similarity index 100% rename from template/{{python_name}}/README.md rename to template/README.md diff --git a/template/{{python_name}}/RELEASE.md b/template/RELEASE.md similarity index 100% rename from template/{{python_name}}/RELEASE.md rename to template/RELEASE.md diff --git a/template/{{python_name}}/install.json b/template/install.json similarity index 100% rename from template/{{python_name}}/install.json rename to template/install.json diff --git a/template/{{python_name}}/package.json b/template/package.json similarity index 100% rename from template/{{python_name}}/package.json rename to template/package.json diff --git a/template/{{python_name}}/pyproject.toml b/template/pyproject.toml similarity index 100% rename from template/{{python_name}}/pyproject.toml rename to template/pyproject.toml diff --git a/template/{{python_name}}/setup.py b/template/setup.py similarity index 100% rename from template/{{python_name}}/setup.py rename to template/setup.py diff --git a/template/{{python_name}}/src/index.ts b/template/src/index.ts similarity index 100% rename from template/{{python_name}}/src/index.ts rename to template/src/index.ts diff --git a/template/{{python_name}}/src/{% if kind == 'server' %}handler.ts{% endif %} b/template/src/{% if kind == 'server' %}handler.ts{% endif %} similarity index 100% rename from template/{{python_name}}/src/{% if kind == 'server' %}handler.ts{% endif %} rename to template/src/{% if kind == 'server' %}handler.ts{% endif %} diff --git a/template/{{python_name}}/src/{% if test %}__tests__{% endif %}/{{python_name}}.spec.ts b/template/src/{% if test %}__tests__{% endif %}/{{python_name}}.spec.ts similarity index 100% rename from template/{{python_name}}/src/{% if test %}__tests__{% endif %}/{{python_name}}.spec.ts rename to template/src/{% if test %}__tests__{% endif %}/{{python_name}}.spec.ts diff --git a/template/{{python_name}}/style/base.css b/template/style/base.css similarity index 100% rename from template/{{python_name}}/style/base.css rename to template/style/base.css diff --git a/template/{{python_name}}/style/index.css b/template/style/index.css similarity index 100% rename from template/{{python_name}}/style/index.css rename to template/style/index.css diff --git a/template/{{python_name}}/style/index.js b/template/style/index.js similarity index 100% rename from template/{{python_name}}/style/index.js rename to template/style/index.js diff --git a/template/{{python_name}}/style/{% if kind = 'theme' %}variables.css{% endif %} b/template/style/{% if kind == 'theme' %}variables.css{% endif %} similarity index 100% rename from template/{{python_name}}/style/{% if kind = 'theme' %}variables.css{% endif %} rename to template/style/{% if kind == 'theme' %}variables.css{% endif %} diff --git a/template/{{python_name}}/tsconfig.json b/template/tsconfig.json similarity index 100% rename from template/{{python_name}}/tsconfig.json rename to template/tsconfig.json diff --git a/template/{{python_name}}/{% if has_binder %}binder{% endif %}/environment.yml b/template/{% if has_binder %}binder{% endif %}/environment.yml similarity index 100% rename from template/{{python_name}}/{% if has_binder %}binder{% endif %}/environment.yml rename to template/{% if has_binder %}binder{% endif %}/environment.yml diff --git a/template/{{python_name}}/{% if has_binder %}binder{% endif %}/postBuild b/template/{% if has_binder %}binder{% endif %}/postBuild similarity index 100% rename from template/{{python_name}}/{% if has_binder %}binder{% endif %}/postBuild rename to template/{% if has_binder %}binder{% endif %}/postBuild diff --git a/template/{{python_name}}/{% if has_settings %}schema{% endif %}/plugin.json b/template/{% if has_settings %}schema{% endif %}/plugin.json similarity index 100% rename from template/{{python_name}}/{% if has_settings %}schema{% endif %}/plugin.json rename to template/{% if has_settings %}schema{% endif %}/plugin.json diff --git a/template/{{python_name}}/{% if kind == 'server' %}jupyter-config{% endif %}/nb-config/{{python_name}}.json b/template/{% if kind == 'server' %}jupyter-config{% endif %}/nb-config/{{python_name}}.json similarity index 100% rename from template/{{python_name}}/{% if kind == 'server' %}jupyter-config{% endif %}/nb-config/{{python_name}}.json rename to template/{% if kind == 'server' %}jupyter-config{% endif %}/nb-config/{{python_name}}.json diff --git a/template/{{python_name}}/{% if kind == 'server' %}jupyter-config{% endif %}/server-config/{{python_name}}.json b/template/{% if kind == 'server' %}jupyter-config{% endif %}/server-config/{{python_name}}.json similarity index 100% rename from template/{{python_name}}/{% if kind == 'server' %}jupyter-config{% endif %}/server-config/{{python_name}}.json rename to template/{% if kind == 'server' %}jupyter-config{% endif %}/server-config/{{python_name}}.json diff --git a/template/{{python_name}}/{% if test %}babel.config.js{% endif %} b/template/{% if test %}babel.config.js{% endif %} similarity index 100% rename from template/{{python_name}}/{% if test %}babel.config.js{% endif %} rename to template/{% if test %}babel.config.js{% endif %} diff --git a/template/{{python_name}}/{% if test %}conftest.py{% endif %} b/template/{% if test %}conftest.py{% endif %} similarity index 100% rename from template/{{python_name}}/{% if test %}conftest.py{% endif %} rename to template/{% if test %}conftest.py{% endif %} diff --git a/template/{{python_name}}/{% if test %}jest.config.js{% endif %} b/template/{% if test %}jest.config.js{% endif %} similarity index 100% rename from template/{{python_name}}/{% if test %}jest.config.js{% endif %} rename to template/{% if test %}jest.config.js{% endif %} diff --git a/template/{{python_name}}/{% if test %}tsconfig.test.json{% endif %} b/template/{% if test %}tsconfig.test.json{% endif %} similarity index 100% rename from template/{{python_name}}/{% if test %}tsconfig.test.json{% endif %} rename to template/{% if test %}tsconfig.test.json{% endif %} diff --git a/template/{{python_name}}/{% if test %}ui-tests{% endif %}/README.md b/template/{% if test %}ui-tests{% endif %}/README.md similarity index 100% rename from template/{{python_name}}/{% if test %}ui-tests{% endif %}/README.md rename to template/{% if test %}ui-tests{% endif %}/README.md diff --git a/template/{{python_name}}/{% if test %}ui-tests{% endif %}/jupyter_server_test_config.py b/template/{% if test %}ui-tests{% endif %}/jupyter_server_test_config.py similarity index 100% rename from template/{{python_name}}/{% if test %}ui-tests{% endif %}/jupyter_server_test_config.py rename to template/{% if test %}ui-tests{% endif %}/jupyter_server_test_config.py diff --git a/template/{{python_name}}/{% if test %}ui-tests{% endif %}/package.json b/template/{% if test %}ui-tests{% endif %}/package.json similarity index 100% rename from template/{{python_name}}/{% if test %}ui-tests{% endif %}/package.json rename to template/{% if test %}ui-tests{% endif %}/package.json diff --git a/template/{{python_name}}/{% if test %}ui-tests{% endif %}/playwright.config.js b/template/{% if test %}ui-tests{% endif %}/playwright.config.js similarity index 100% rename from template/{{python_name}}/{% if test %}ui-tests{% endif %}/playwright.config.js rename to template/{% if test %}ui-tests{% endif %}/playwright.config.js diff --git a/template/{{python_name}}/{% if test %}ui-tests{% endif %}/tests/{{python_name}}.spec.ts b/template/{% if test %}ui-tests{% endif %}/tests/{{python_name}}.spec.ts similarity index 100% rename from template/{{python_name}}/{% if test %}ui-tests{% endif %}/tests/{{python_name}}.spec.ts rename to template/{% if test %}ui-tests{% endif %}/tests/{{python_name}}.spec.ts diff --git a/template/{{python_name}}/{% if test %}ui-tests{% endif %}/yarn.lock b/template/{% if test %}ui-tests{% endif %}/yarn.lock similarity index 100% rename from template/{{python_name}}/{% if test %}ui-tests{% endif %}/yarn.lock rename to template/{% if test %}ui-tests{% endif %}/yarn.lock diff --git a/template/{{_copier_conf.answers_file}}.jinja b/template/{{_copier_conf.answers_file}}.jinja new file mode 100644 index 00000000..ee70a215 --- /dev/null +++ b/template/{{_copier_conf.answers_file}}.jinja @@ -0,0 +1,2 @@ +# Changes here will be overwritten by Copier +{{_copier_answers|to_nice_yaml}} diff --git a/template/{{python_name}}/{{python_name}}/__init__.py b/template/{{python_name}}/__init__.py similarity index 100% rename from template/{{python_name}}/{{python_name}}/__init__.py rename to template/{{python_name}}/__init__.py diff --git a/template/{{python_name}}/{{python_name}}/{% if kind == 'server' %}handlers.py{% endif %} b/template/{{python_name}}/{% if kind == 'server' %}handlers.py{% endif %} similarity index 100% rename from template/{{python_name}}/{{python_name}}/{% if kind == 'server' %}handlers.py{% endif %} rename to template/{{python_name}}/{% if kind == 'server' %}handlers.py{% endif %} diff --git a/template/{{python_name}}/{{python_name}}/{% if test %}tests{% endif %}/__init__.py b/template/{{python_name}}/{% if test %}tests{% endif %}/__init__.py similarity index 100% rename from template/{{python_name}}/{{python_name}}/{% if test %}tests{% endif %}/__init__.py rename to template/{{python_name}}/{% if test %}tests{% endif %}/__init__.py diff --git a/template/{{python_name}}/{{python_name}}/{% if test %}tests{% endif %}/test_handlers.py b/template/{{python_name}}/{% if test %}tests{% endif %}/test_handlers.py similarity index 100% rename from template/{{python_name}}/{{python_name}}/{% if test %}tests{% endif %}/test_handlers.py rename to template/{{python_name}}/{% if test %}tests{% endif %}/test_handlers.py From 762d287a117b8abe01e3b38ae4523c1266e9aa8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Collonval?= Date: Wed, 12 Apr 2023 17:25:57 +0200 Subject: [PATCH 3/6] Set file as jinja template --- copier.yml | 2 ++ template/.github/workflows/{build.yml => build.yml.jinja} | 0 .../workflows/{check-release.yml => check-release.yml.jinja} | 0 .../workflows/{% if has_binder %}binder-on-pr.yml{% endif %} | 2 -- .../{% if test %}update-integration-tests.yml{% endif %} | 3 --- template/{.gitignore => .gitignore.jinja} | 0 template/{.prettierignore => .prettierignore.jinja} | 0 template/{LICENSE => LICENSE.jinja} | 0 template/{README.md => README.md.jinja} | 0 template/{install.json => install.json.jinja} | 0 template/{package.json => package.json.jinja} | 0 template/{pyproject.toml => pyproject.toml.jinja} | 0 template/src/{index.ts => index.ts.jinja} | 0 ...%} => {% if kind == 'server' %}handler.ts{% endif %}.jinja} | 0 .../{{{python_name}}.spec.ts => {{python_name}}.spec.ts.jinja} | 0 template/style/{index.css => index.css.jinja} | 0 template/{tsconfig.json => tsconfig.json.jinja} | 0 .../{environment.yml => environment.yml.jinja} | 0 .../{postBuild => postBuild.jinja} | 0 .../{plugin.json => plugin.json.jinja} | 0 .../{{{python_name}}.json => {{python_name}}.json.jinja} | 0 .../{{{python_name}}.json => {{python_name}}.json.jinja} | 0 ...py{% endif %} => {% if test %}conftest.py{% endif %}.jinja} | 0 .../{package.json => package.json.jinja} | 0 .../{{{python_name}}.spec.ts => {{python_name}}.spec.ts.jinja} | 0 template/{{python_name}}/{__init__.py => __init__.py.jinja} | 0 ...} => {% if kind == 'server' %}handlers.py{% endif %}.jinja} | 0 .../{__init__.py => __init__.py.jinja} | 0 .../{test_handlers.py => test_handlers.py.jinja} | 0 29 files changed, 2 insertions(+), 5 deletions(-) rename template/.github/workflows/{build.yml => build.yml.jinja} (100%) rename template/.github/workflows/{check-release.yml => check-release.yml.jinja} (100%) rename template/{.gitignore => .gitignore.jinja} (100%) rename template/{.prettierignore => .prettierignore.jinja} (100%) rename template/{LICENSE => LICENSE.jinja} (100%) rename template/{README.md => README.md.jinja} (100%) rename template/{install.json => install.json.jinja} (100%) rename template/{package.json => package.json.jinja} (100%) rename template/{pyproject.toml => pyproject.toml.jinja} (100%) rename template/src/{index.ts => index.ts.jinja} (100%) rename template/src/{{% if kind == 'server' %}handler.ts{% endif %} => {% if kind == 'server' %}handler.ts{% endif %}.jinja} (100%) rename template/src/{% if test %}__tests__{% endif %}/{{{python_name}}.spec.ts => {{python_name}}.spec.ts.jinja} (100%) rename template/style/{index.css => index.css.jinja} (100%) rename template/{tsconfig.json => tsconfig.json.jinja} (100%) rename template/{% if has_binder %}binder{% endif %}/{environment.yml => environment.yml.jinja} (100%) rename template/{% if has_binder %}binder{% endif %}/{postBuild => postBuild.jinja} (100%) rename template/{% if has_settings %}schema{% endif %}/{plugin.json => plugin.json.jinja} (100%) rename template/{% if kind == 'server' %}jupyter-config{% endif %}/nb-config/{{{python_name}}.json => {{python_name}}.json.jinja} (100%) rename template/{% if kind == 'server' %}jupyter-config{% endif %}/server-config/{{{python_name}}.json => {{python_name}}.json.jinja} (100%) rename template/{{% if test %}conftest.py{% endif %} => {% if test %}conftest.py{% endif %}.jinja} (100%) rename template/{% if test %}ui-tests{% endif %}/{package.json => package.json.jinja} (100%) rename template/{% if test %}ui-tests{% endif %}/tests/{{{python_name}}.spec.ts => {{python_name}}.spec.ts.jinja} (100%) rename template/{{python_name}}/{__init__.py => __init__.py.jinja} (100%) rename template/{{python_name}}/{{% if kind == 'server' %}handlers.py{% endif %} => {% if kind == 'server' %}handlers.py{% endif %}.jinja} (100%) rename template/{{python_name}}/{% if test %}tests{% endif %}/{__init__.py => __init__.py.jinja} (100%) rename template/{{python_name}}/{% if test %}tests{% endif %}/{test_handlers.py => test_handlers.py.jinja} (100%) diff --git a/copier.yml b/copier.yml index 358bc1ca..698c0fb2 100644 --- a/copier.yml +++ b/copier.yml @@ -1,5 +1,7 @@ _min_copier_version: "7.1.0" _subdirectory: template +_jinja_extensions: + - jinja2_time.TimeExtension kind: type: str diff --git a/template/.github/workflows/build.yml b/template/.github/workflows/build.yml.jinja similarity index 100% rename from template/.github/workflows/build.yml rename to template/.github/workflows/build.yml.jinja diff --git a/template/.github/workflows/check-release.yml b/template/.github/workflows/check-release.yml.jinja similarity index 100% rename from template/.github/workflows/check-release.yml rename to template/.github/workflows/check-release.yml.jinja diff --git a/template/.github/workflows/{% if has_binder %}binder-on-pr.yml{% endif %} b/template/.github/workflows/{% if has_binder %}binder-on-pr.yml{% endif %} index b2e7d68e..87e9cd29 100644 --- a/template/.github/workflows/{% if has_binder %}binder-on-pr.yml{% endif %} +++ b/template/.github/workflows/{% if has_binder %}binder-on-pr.yml{% endif %} @@ -11,6 +11,4 @@ jobs: steps: - uses: jupyterlab/maintainer-tools/.github/actions/binder-link@v1 with: - {% raw %} github_token: ${{ secrets.github_token }} - {% endraw %} diff --git a/template/.github/workflows/{% if test %}update-integration-tests.yml{% endif %} b/template/.github/workflows/{% if test %}update-integration-tests.yml{% endif %} index 4af7df3f..52c6723c 100644 --- a/template/.github/workflows/{% if test %}update-integration-tests.yml{% endif %} +++ b/template/.github/workflows/{% if test %}update-integration-tests.yml{% endif %} @@ -9,8 +9,6 @@ permissions: pull-requests: write jobs: - {# Escape double curly brace #} - {% raw %} update-snapshots: if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, 'please update playwright snapshots') }} runs-on: ubuntu-latest @@ -47,4 +45,3 @@ jobs: # Playwright knows how to start JupyterLab server start_server_script: 'null' test_folder: ui-tests - {% endraw %} diff --git a/template/.gitignore b/template/.gitignore.jinja similarity index 100% rename from template/.gitignore rename to template/.gitignore.jinja diff --git a/template/.prettierignore b/template/.prettierignore.jinja similarity index 100% rename from template/.prettierignore rename to template/.prettierignore.jinja diff --git a/template/LICENSE b/template/LICENSE.jinja similarity index 100% rename from template/LICENSE rename to template/LICENSE.jinja diff --git a/template/README.md b/template/README.md.jinja similarity index 100% rename from template/README.md rename to template/README.md.jinja diff --git a/template/install.json b/template/install.json.jinja similarity index 100% rename from template/install.json rename to template/install.json.jinja diff --git a/template/package.json b/template/package.json.jinja similarity index 100% rename from template/package.json rename to template/package.json.jinja diff --git a/template/pyproject.toml b/template/pyproject.toml.jinja similarity index 100% rename from template/pyproject.toml rename to template/pyproject.toml.jinja diff --git a/template/src/index.ts b/template/src/index.ts.jinja similarity index 100% rename from template/src/index.ts rename to template/src/index.ts.jinja diff --git a/template/src/{% if kind == 'server' %}handler.ts{% endif %} b/template/src/{% if kind == 'server' %}handler.ts{% endif %}.jinja similarity index 100% rename from template/src/{% if kind == 'server' %}handler.ts{% endif %} rename to template/src/{% if kind == 'server' %}handler.ts{% endif %}.jinja diff --git a/template/src/{% if test %}__tests__{% endif %}/{{python_name}}.spec.ts b/template/src/{% if test %}__tests__{% endif %}/{{python_name}}.spec.ts.jinja similarity index 100% rename from template/src/{% if test %}__tests__{% endif %}/{{python_name}}.spec.ts rename to template/src/{% if test %}__tests__{% endif %}/{{python_name}}.spec.ts.jinja diff --git a/template/style/index.css b/template/style/index.css.jinja similarity index 100% rename from template/style/index.css rename to template/style/index.css.jinja diff --git a/template/tsconfig.json b/template/tsconfig.json.jinja similarity index 100% rename from template/tsconfig.json rename to template/tsconfig.json.jinja diff --git a/template/{% if has_binder %}binder{% endif %}/environment.yml b/template/{% if has_binder %}binder{% endif %}/environment.yml.jinja similarity index 100% rename from template/{% if has_binder %}binder{% endif %}/environment.yml rename to template/{% if has_binder %}binder{% endif %}/environment.yml.jinja diff --git a/template/{% if has_binder %}binder{% endif %}/postBuild b/template/{% if has_binder %}binder{% endif %}/postBuild.jinja similarity index 100% rename from template/{% if has_binder %}binder{% endif %}/postBuild rename to template/{% if has_binder %}binder{% endif %}/postBuild.jinja diff --git a/template/{% if has_settings %}schema{% endif %}/plugin.json b/template/{% if has_settings %}schema{% endif %}/plugin.json.jinja similarity index 100% rename from template/{% if has_settings %}schema{% endif %}/plugin.json rename to template/{% if has_settings %}schema{% endif %}/plugin.json.jinja diff --git a/template/{% if kind == 'server' %}jupyter-config{% endif %}/nb-config/{{python_name}}.json b/template/{% if kind == 'server' %}jupyter-config{% endif %}/nb-config/{{python_name}}.json.jinja similarity index 100% rename from template/{% if kind == 'server' %}jupyter-config{% endif %}/nb-config/{{python_name}}.json rename to template/{% if kind == 'server' %}jupyter-config{% endif %}/nb-config/{{python_name}}.json.jinja diff --git a/template/{% if kind == 'server' %}jupyter-config{% endif %}/server-config/{{python_name}}.json b/template/{% if kind == 'server' %}jupyter-config{% endif %}/server-config/{{python_name}}.json.jinja similarity index 100% rename from template/{% if kind == 'server' %}jupyter-config{% endif %}/server-config/{{python_name}}.json rename to template/{% if kind == 'server' %}jupyter-config{% endif %}/server-config/{{python_name}}.json.jinja diff --git a/template/{% if test %}conftest.py{% endif %} b/template/{% if test %}conftest.py{% endif %}.jinja similarity index 100% rename from template/{% if test %}conftest.py{% endif %} rename to template/{% if test %}conftest.py{% endif %}.jinja diff --git a/template/{% if test %}ui-tests{% endif %}/package.json b/template/{% if test %}ui-tests{% endif %}/package.json.jinja similarity index 100% rename from template/{% if test %}ui-tests{% endif %}/package.json rename to template/{% if test %}ui-tests{% endif %}/package.json.jinja diff --git a/template/{% if test %}ui-tests{% endif %}/tests/{{python_name}}.spec.ts b/template/{% if test %}ui-tests{% endif %}/tests/{{python_name}}.spec.ts.jinja similarity index 100% rename from template/{% if test %}ui-tests{% endif %}/tests/{{python_name}}.spec.ts rename to template/{% if test %}ui-tests{% endif %}/tests/{{python_name}}.spec.ts.jinja diff --git a/template/{{python_name}}/__init__.py b/template/{{python_name}}/__init__.py.jinja similarity index 100% rename from template/{{python_name}}/__init__.py rename to template/{{python_name}}/__init__.py.jinja diff --git a/template/{{python_name}}/{% if kind == 'server' %}handlers.py{% endif %} b/template/{{python_name}}/{% if kind == 'server' %}handlers.py{% endif %}.jinja similarity index 100% rename from template/{{python_name}}/{% if kind == 'server' %}handlers.py{% endif %} rename to template/{{python_name}}/{% if kind == 'server' %}handlers.py{% endif %}.jinja diff --git a/template/{{python_name}}/{% if test %}tests{% endif %}/__init__.py b/template/{{python_name}}/{% if test %}tests{% endif %}/__init__.py.jinja similarity index 100% rename from template/{{python_name}}/{% if test %}tests{% endif %}/__init__.py rename to template/{{python_name}}/{% if test %}tests{% endif %}/__init__.py.jinja diff --git a/template/{{python_name}}/{% if test %}tests{% endif %}/test_handlers.py b/template/{{python_name}}/{% if test %}tests{% endif %}/test_handlers.py.jinja similarity index 100% rename from template/{{python_name}}/{% if test %}tests{% endif %}/test_handlers.py rename to template/{{python_name}}/{% if test %}tests{% endif %}/test_handlers.py.jinja From 58d7093dc870e49e3e73ccb79097351c0ac1bf85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Collonval?= Date: Wed, 12 Apr 2023 17:26:03 +0200 Subject: [PATCH 4/6] Update README --- README.md | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index ca651761..e628cbd2 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,32 @@ -# JupyterLab extension-cookiecutter-ts +# JupyterLab extension template [![Github Actions Status](https://github.com/jupyterlab/extension-cookiecutter-ts/workflows/CI/badge.svg)](https://github.com/jupyterlab/extension-cookiecutter-ts/actions/workflows/main.yml) -A [cookiecutter](https://github.com/audreyr/cookiecutter) template for creating +A [copier](https://copier.readthedocs.io) template for creating a JupyterLab extension. Three kinds of extension are supported: - _frontend_: Pure frontend extension written in TypeScript. - _server_: Extension with frontend (in TypeScript) and backend (in Python) parts. - _theme_: Theme for JupyterLab (using CSS variables). - -> See also [extension-cookiecutter-js](https://github.com/jupyterlab/extension-cookiecutter-js) -for an extension in CommonJS. ## Use the template to create package -Install cookiecutter. +1. Install copier and some plugins. +```sh +pip install "copier>=7.1.0" jinja2-time ``` -pip install cookiecutter + +2. Go into the extension directory + +```sh +mkdir myextension +cd myextension ``` -Use cookiecutter to generate a package, following the prompts to fill in the name and authorship of your new JupyterLab extension. +3. Use copier to generate a package, following the prompts to fill in the name and authorship of your new JupyterLab extension. ``` -cookiecutter https://github.com/jupyterlab/extension-cookiecutter-ts --checkout 4.0 +copier https://github.com/jupyterlab/extension-cookiecutter-ts . ``` The available options are: @@ -41,15 +45,15 @@ The available options are: - `test`: Whether to add test set ups and skeletons for the extension or not - `repository`: Version Control System repository URI +If you'd like to generate a package for a older release, use the `--vcs-ref` option and give a tag or commit from this repository. -If you'd like to generate a package for a specific JupyterLab release, use the `--checkout` option and give a tag or commit from this repository. - -``` -cookiecutter https://github.com/jupyterlab/extension-cookiecutter-ts --checkout v1.0 -cookiecutter https://github.com/jupyterlab/extension-cookiecutter-ts --checkout v2.0 -cookiecutter https://github.com/jupyterlab/extension-cookiecutter-ts --checkout 3.0 +```sh +copier --vcs-ref v4.0.0 https://github.com/jupyterlab/extension-cookiecutter-ts ``` +> If you are looking for a template compatible with JupyterLab version prior to 4.0.0, look at +> the [cookiecutter template](https://github.com/jupyterlab/extension-cookiecutter-ts). + ## A simple example Your new extension includes a very simple example of a working extension. Use this example as a guide to build your own extension. Have a look at the [extension examples](https://github.com/jupyterlab/extension-examples) repository for more information on various JupyterLab features. From 6da658077c1225d6a834f780b4ba8382e0ead89e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Collonval?= Date: Wed, 12 Apr 2023 17:26:12 +0200 Subject: [PATCH 5/6] Update tests --- .github/workflows/main.yml | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 84e7282e..9edc876e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -30,7 +30,7 @@ jobs: - name: Install dependencies run: | - python -m pip install copier>=7.1.0 + python -m pip install copier>=7.1.0 jinja2-time - name: Create pure frontend extension env: @@ -39,8 +39,9 @@ jobs: run: | set -eux # Trick to use custom parameters - python -c "from cookiecutter.main import cookiecutter; import json, os; f=open('cookiecutter.json'); d=json.load(f); f.close(); d['kind']=d['kind'][0]; d['labextension_name']=os.getenv('NAME'); cookiecutter('.', extra_context=d, no_input=True)" - pushd ${PYNAME} + mkdir ${NAME} + python -c "from copier import run_auto; import json, os; f=open('cookiecutter.json'); d=json.load(f); f.close(); d['kind']=d['kind'][0]; d['labextension_name']=os.getenv('NAME'); run_all('.', os.getenv('NAME'), data=d, vcs_ref='HEAD')" + pushd ${NAME} python -m pip install "jupyterlab>=4.0.0b0,<5" jlpm jlpm stylelint-config-prettier-check @@ -73,13 +74,14 @@ jobs: - name: Install dependencies run: | - python -m pip install cookiecutter + python -m pip install copier>=7.1.0 jinja2-time - name: Create pure frontend extension run: | set -eux # Trick to use custom parameters - python -c "from cookiecutter.main import cookiecutter; import json; f=open('cookiecutter.json'); d=json.load(f); f.close(); d['kind']=d['kind'][0]; d['test']='n'; cookiecutter('.', extra_context=d, no_input=True)" + mkdir myextension + python -c "from copier import run_auto; import json; f=open('cookiecutter.json'); d=json.load(f); f.close(); d['kind']=d['kind'][0]; d['test']='n'; run_all('.', 'myextension', data=d, vcs_ref='HEAD')" pushd myextension pip install "jupyterlab>=4.0.0b0,<5" jlpm @@ -112,13 +114,14 @@ jobs: - name: Install dependencies run: | - python -m pip install cookiecutter + python -m pip install copier>=7.1.0 jinja2-time - name: Create pure frontend extension run: | set -eux + mkdir myextension # Trick to use custom parameters - python -c "from cookiecutter.main import cookiecutter; import json; f=open('cookiecutter.json'); d=json.load(f); f.close(); d['kind']=d['kind'][0]; d['has_settings']='y'; cookiecutter('.', extra_context=d, no_input=True)" + python -c "from copier import run_auto; import json; f=open('cookiecutter.json'); d=json.load(f); f.close(); d['kind']=d['kind'][0]; d['has_settings']='y'; run_all('.', 'myextension', data=d, vcs_ref='HEAD')" pushd myextension pip install "jupyterlab>=4.0.0b0,<5" jlpm @@ -155,12 +158,14 @@ jobs: - name: Install dependencies run: | - python -m pip install cookiecutter build + python -m pip install "copier>=7.1.0" jinja2-time build - name: Create server extension pip install run: | + set -eux + mkdir myextension # Trick to use custom parameters - python -c "from cookiecutter.main import cookiecutter; import json; f=open('cookiecutter.json'); d=json.load(f); f.close(); d['kind']='server'; cookiecutter('.', extra_context=d, no_input=True)" + python -c "from copier import run_auto; import json; f=open('cookiecutter.json'); d=json.load(f); f.close(); d['kind']='server'; run_all('.', 'myextension', data=d, vcs_ref='HEAD')" cd myextension cat pyproject.toml pip install . @@ -185,8 +190,10 @@ jobs: - name: Create server extension pip develop run: | + set -eux + mkdir myextension # Trick to use custom parameters - python -c "from cookiecutter.main import cookiecutter; import json; f=open('cookiecutter.json'); d=json.load(f); f.close(); d['kind']='server'; cookiecutter('.', extra_context=d, no_input=True)" + python -c "from copier import run_auto; import json; f=open('cookiecutter.json'); d=json.load(f); f.close(); d['kind']='server'; run_all('.', 'myextension', data=d, vcs_ref='HEAD')" cd myextension python -m pip install -e .[test] python -m pip install "jupyterlab>=4.0.0b0,<5" @@ -216,12 +223,14 @@ jobs: jupyter labextension uninstall myextension python -m pip uninstall -y myextension jupyterlab - python -c "import shutil; shutil.rmtree('myextension')" + rm -rf myextension - name: Install server extension from a tarball run: | + set -eux + mkdir myextension # Trick to use custom parameters - python -c "from cookiecutter.main import cookiecutter; import json; f=open('cookiecutter.json'); d=json.load(f); f.close(); d['kind']='server'; cookiecutter('.', extra_context=d, no_input=True)" + python -c "from copier import run_auto; import json; f=open('cookiecutter.json'); d=json.load(f); f.close(); d['kind']='server'; run_all('.', 'myextension', data=d, vcs_ref='HEAD')" cd myextension python -m pip install "jupyterlab>=4.0.0b0,<5" jupyter lab clean --all @@ -316,8 +325,9 @@ jobs: - name: Create pure frontend extension run: | set -eux + mkdir mytheme # Trick to use custom parameters - python -c "from cookiecutter.main import cookiecutter; import json; f=open('cookiecutter.json'); d=json.load(f); f.close(); d['kind']='theme'; cookiecutter('.', extra_context=d, no_input=True)" + python -c "from copier import run_auto; import json; f=open('cookiecutter.json'); d=json.load(f); f.close(); d['kind']='theme'; run_all('.', 'mytheme', data=d, vcs_ref='HEAD')" pushd mytheme python -m pip install "jupyterlab>=4.0.0b0,<5" jlpm From 22665726156fc13db0e382deea956c49c98dd5ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Collonval?= Date: Wed, 12 Apr 2023 17:41:51 +0200 Subject: [PATCH 6/6] Fix template --- template/.github/workflows/build.yml.jinja | 2 +- template/.github/workflows/prep-release.yml | 2 - .../.github/workflows/publish-release.yml | 2 - template/.gitignore.jinja | 4 +- template/package.json.jinja | 10 +- template/{{python_name}}/.gitignore.jinja2 | 125 ------------------ 6 files changed, 8 insertions(+), 137 deletions(-) delete mode 100644 template/{{python_name}}/.gitignore.jinja2 diff --git a/template/.github/workflows/build.yml.jinja b/template/.github/workflows/build.yml.jinja index 08df76c6..5542e1de 100644 --- a/template/.github/workflows/build.yml.jinja +++ b/template/.github/workflows/build.yml.jinja @@ -25,7 +25,7 @@ jobs: set -eux jlpm jlpm run lint:check -{% if test.lower().startswith('y') %} +{% if test %} - name: Test the extension run: | set -eux diff --git a/template/.github/workflows/prep-release.yml b/template/.github/workflows/prep-release.yml index a9592031..7a2a18de 100644 --- a/template/.github/workflows/prep-release.yml +++ b/template/.github/workflows/prep-release.yml @@ -25,7 +25,6 @@ jobs: steps: - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 -{% raw %} - name: Prep Release id: prep-release uses: jupyter-server/jupyter_releaser/.github/actions/prep-release@v2 @@ -41,4 +40,3 @@ jobs: - name: "** Next Step **" run: | echo "Optional): Review Draft Release: ${{ steps.prep-release.outputs.release_url }}" -{% endraw %} diff --git a/template/.github/workflows/publish-release.yml b/template/.github/workflows/publish-release.yml index 2b48d068..dbaaeaad 100644 --- a/template/.github/workflows/publish-release.yml +++ b/template/.github/workflows/publish-release.yml @@ -18,7 +18,6 @@ jobs: steps: - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 -{% raw %} - name: Populate Release id: populate-release uses: jupyter-server/jupyter_releaser/.github/actions/populate-release@v2 @@ -53,4 +52,3 @@ jobs: run: | echo "Failed to Publish the Draft Release Url:" echo ${{ steps.populate-release.outputs.release_url }} -{% endraw %} diff --git a/template/.gitignore.jinja b/template/.gitignore.jinja index be835527..fcbfa936 100644 --- a/template/.gitignore.jinja +++ b/template/.gitignore.jinja @@ -9,8 +9,8 @@ node_modules/ *.tsbuildinfo {{python_name}}/labextension # Version file is handled by hatchling -{{cookiecutter.python_name}}/_version.py -{% if cookiecutter.test.lower().startswith('y') %} +{{python_name}}/_version.py +{% if test %} # Integration tests ui-tests/test-results/ ui-tests/playwright-report/ diff --git a/template/package.json.jinja b/template/package.json.jinja index 9c6d8a48..392375ea 100644 --- a/template/package.json.jinja +++ b/template/package.json.jinja @@ -27,7 +27,7 @@ "repository": { "type": "git", "url": "{{ repository }}.git" - },{% if test.lower().startswith('y') %} + },{% if test %} "workspaces": [ "ui-tests" ],{% endif %} @@ -60,13 +60,13 @@ }, "dependencies": { "@jupyterlab/application": "^4.0.0-beta.0"{% if kind.lower() == 'theme' %}, - "@jupyterlab/apputils": "^4.0.0-beta.0"{% endif %}{% if has_settings.lower().startswith('y') %}, + "@jupyterlab/apputils": "^4.0.0-beta.0"{% endif %}{% if has_settings %}, "@jupyterlab/settingregistry": "^4.0.0-beta.0"{% endif %}{% if kind.lower() == 'server' %}, "@jupyterlab/coreutils": "^6.0.0-beta.0", "@jupyterlab/services": "^7.0.0-beta.0"{% endif %} }, "devDependencies": { - "@jupyterlab/builder": "^4.0.0-beta.0",{% if test.lower().startswith('y') %} + "@jupyterlab/builder": "^4.0.0-beta.0",{% if test %} "@jupyterlab/testutils": "^4.0.0-beta.0", "@types/jest": "^29.2.0",{% endif %} "@types/json-schema": "^7.0.11", @@ -76,7 +76,7 @@ "css-loader": "^6.7.1", "eslint": "^8.36.0", "eslint-config-prettier": "^8.7.0", - "eslint-plugin-prettier": "^4.2.1",{% if test.lower().startswith('y') %} + "eslint-plugin-prettier": "^4.2.1",{% if test %} "jest": "^29.2.0",{% endif %}{% if kind.lower() == 'server' %} "mkdirp": "^1.0.3",{% endif %} "npm-run-all": "^4.1.5", @@ -121,7 +121,7 @@ "node_modules", "dist", "coverage", - "**/*.d.ts"{% if test.lower().startswith('y') %}, + "**/*.d.ts"{% if test %}, "tests", "**/__tests__", "ui-tests"{% endif %} diff --git a/template/{{python_name}}/.gitignore.jinja2 b/template/{{python_name}}/.gitignore.jinja2 deleted file mode 100644 index be835527..00000000 --- a/template/{{python_name}}/.gitignore.jinja2 +++ /dev/null @@ -1,125 +0,0 @@ -*.bundle.* -lib/ -node_modules/ -*.log -.eslintcache -.stylelintcache -*.egg-info/ -.ipynb_checkpoints -*.tsbuildinfo -{{python_name}}/labextension -# Version file is handled by hatchling -{{cookiecutter.python_name}}/_version.py -{% if cookiecutter.test.lower().startswith('y') %} -# Integration tests -ui-tests/test-results/ -ui-tests/playwright-report/ -{% endif %} -# Created by https://www.gitignore.io/api/python -# Edit at https://www.gitignore.io/?templates=python - -### Python ### -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -pip-wheel-metadata/ -share/python-wheels/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage/ -coverage.xml -*.cover -.hypothesis/ -.pytest_cache/ - -# Translations -*.mo -*.pot - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# pyenv -.python-version - -# celery beat schedule file -celerybeat-schedule - -# SageMath parsed files -*.sage.py - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# Mr Developer -.mr.developer.cfg -.project -.pydevproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# End of https://www.gitignore.io/api/python - -# OSX files -.DS_Store - -# Yarn cache -.yarn/