diff --git a/.github/workflows/publish-develop-docs.yml b/.github/workflows/publish-develop-docs.yml index 53c5aa16..11a7fa23 100644 --- a/.github/workflows/publish-develop-docs.yml +++ b/.github/workflows/publish-develop-docs.yml @@ -5,7 +5,7 @@ on: branches: - main jobs: - deploy: + publish-develop-docs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -17,12 +17,12 @@ jobs: - uses: actions/setup-python@v5 with: python-version: 3.x - - run: pip install -r requirements/build-docs.txt + - name: Install dependencies + run: pip install --upgrade pip hatch uv - name: Publish Develop Docs run: | git config user.name github-actions git config user.email github-actions@github.com - cd docs - mike deploy --push develop + hatch run docs:deploy_develop concurrency: group: publish-docs diff --git a/.github/workflows/publish-latest-docs.yml b/.github/workflows/publish-latest-docs.yml index bc7409f0..697b10da 100644 --- a/.github/workflows/publish-latest-docs.yml +++ b/.github/workflows/publish-latest-docs.yml @@ -5,7 +5,7 @@ on: types: [published] jobs: - deploy: + publish-latest-docs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -17,12 +17,12 @@ jobs: - uses: actions/setup-python@v5 with: python-version: 3.x - - run: pip install -r requirements/build-docs.txt + - name: Install dependencies + run: pip install --upgrade pip hatch uv - name: Publish ${{ github.event.release.name }} Docs run: | git config user.name github-actions git config user.email github-actions@github.com - cd docs - mike deploy --push --update-aliases ${{ github.event.release.name }} latest + hatch run docs:deploy_latest ${{ github.ref_name }} concurrency: group: publish-docs diff --git a/.github/workflows/publish-py.yml b/.github/workflows/publish-py.yml index 6a86db98..f72cc55d 100644 --- a/.github/workflows/publish-py.yml +++ b/.github/workflows/publish-py.yml @@ -8,7 +8,7 @@ on: types: [published] jobs: - release-package: + publish-python: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -20,13 +20,11 @@ jobs: with: python-version: "3.x" - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements/build-pkg.txt + run: pip install --upgrade pip hatch uv - name: Build and publish env: TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} run: | - python -m build --sdist --wheel --outdir dist . + hatch build --clean twine upload dist/* diff --git a/.github/workflows/test-docs.yml b/.github/workflows/test-docs.yml index 66a5c942..08bfadd7 100644 --- a/.github/workflows/test-docs.yml +++ b/.github/workflows/test-docs.yml @@ -7,8 +7,6 @@ on: pull_request: branches: - main - schedule: - - cron: "0 0 * * *" jobs: docs: @@ -23,20 +21,12 @@ jobs: - uses: actions/setup-python@v5 with: python-version: 3.x - # - name: Check docs links - # uses: umbrelladocs/action-linkspector@v1 - # with: - # github_token: ${{ secrets.github_token }} - # reporter: github-pr-review - # fail_on_error: false + - name: Install Python Dependencies + run: pip install --upgrade pip hatch uv + # DISABLED DUE TO DJANGO DOCS CONSTANTLY THROWING 429 ERRORS + # - name: Check documentation links + # run: hatch run docs:linkcheck - name: Check docs build - run: | - pip install -r requirements/build-docs.txt - cd docs - mkdocs build --strict + run: hatch run docs:build - name: Check docs examples - run: | - pip install -r requirements/check-types.txt - pip install -r requirements/check-style.txt - mypy --show-error-codes docs/examples/python/ - ruff check docs/examples/python/ + run: hatch run docs:check_examples diff --git a/.github/workflows/test-javascript.yml b/.github/workflows/test-javascript.yml new file mode 100644 index 00000000..d5b9db1d --- /dev/null +++ b/.github/workflows/test-javascript.yml @@ -0,0 +1,25 @@ +name: Test + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + javascript: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + - uses: actions/setup-python@v5 + with: + python-version: 3.x + - name: Install Python Dependencies + run: pip install --upgrade pip hatch uv + - name: Run Tests + run: hatch run javascript:check diff --git a/.github/workflows/test-src.yml b/.github/workflows/test-python.yml similarity index 66% rename from .github/workflows/test-src.yml rename to .github/workflows/test-python.yml index 5eb2e67a..9fe700b8 100644 --- a/.github/workflows/test-src.yml +++ b/.github/workflows/test-python.yml @@ -11,7 +11,7 @@ on: - cron: "0 0 * * *" jobs: - source: + python: runs-on: ubuntu-latest strategy: matrix: @@ -26,6 +26,8 @@ jobs: with: python-version: ${{ matrix.python-version }} - name: Install Python Dependencies - run: pip install -r requirements/test-run.txt - - name: Run Tests - run: nox -t test + run: pip install --upgrade pip hatch uv + - name: Run Single DB Tests + run: hatch test --python ${{ matrix.python-version }} --ds=test_app.settings_single_db -v + - name: Run Multi-DB Tests + run: hatch test --python ${{ matrix.python-version }} --ds=test_app.settings_multi_db -v diff --git a/.linkspector.yml b/.linkspector.yml deleted file mode 100644 index 6c0747e7..00000000 --- a/.linkspector.yml +++ /dev/null @@ -1,7 +0,0 @@ -dirs: - - ./docs -files: - - README.md - - CHANGELOG.md -useGitIgnore: true -modifiedFilesOnly: false diff --git a/CHANGELOG.md b/CHANGELOG.md index 82209551..ec8d38ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,13 @@ Don't forget to remove deprecated code on each major release! ## [Unreleased] -- Nothing (yet)! +### Fixed + +- Fixed regression in v5.1.0 where components would sometimes not output debug messages when `settings.py:DEBUG` is enabled. + +### Changed + +- Set upper limit on ReactPy version to `<2.0.0`. ## [5.1.0] - 2024-11-24 diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index ddcb7f8d..00000000 --- a/MANIFEST.in +++ /dev/null @@ -1,3 +0,0 @@ -include src/reactpy_django/py.typed -recursive-include src/reactpy_django/static * -recursive-include src/reactpy_django/templates *.html diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index c1b5922f..100b669b 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -16,9 +16,7 @@ nav: - Management Commands: reference/management-commands.md - About: - Changelog: about/changelog.md - - Contributor Guide: - - Code: about/code.md - - Docs: about/docs.md + - Contributor Guide: about/contributing.md - Community: - GitHub Discussions: https://github.com/reactive-python/reactpy-django/discussions - Discord: https://discord.gg/uNb5P4hA9X diff --git a/docs/src/about/code.md b/docs/src/about/code.md deleted file mode 100644 index 81e49c51..00000000 --- a/docs/src/about/code.md +++ /dev/null @@ -1,85 +0,0 @@ -## Overview - -
- - You will need to set up a Python environment to develop ReactPy-Django. - -
- -!!! abstract "Note" - - Looking to contribute features that are not Django specific? - - Everything within the `reactpy-django` repository must be specific to Django integration. Check out the [ReactPy Core documentation](https://reactpy.dev/docs/about/contributor-guide.html) to contribute general features such as components, hooks, and events. - ---- - -## Creating an environment - -If you plan to make code changes to this repository, you will need to install the following dependencies first: - -- [Python 3.9+](https://www.python.org/downloads/) -- [Bun](https://bun.sh/) -- [Git](https://git-scm.com/downloads) - -Once done, you should clone this repository: - -```bash linenums="0" -git clone https://github.com/reactive-python/reactpy-django.git -cd reactpy-django -``` - -Then, by running the command below you can install the dependencies needed to run the ReactPy-Django development environment. - -```bash linenums="0" -pip install -r requirements.txt --upgrade --verbose -``` - -!!! warning "Pitfall" - - Some of our development dependencies require a C++ compiler, which is not installed by default on Windows. If you receive errors related to this during installation, follow the instructions in your console errors. - - Additionally, be aware that ReactPy-Django's JavaScript bundle is built within the following scenarios: - - 1. When `pip install` is run on the `reactpy-django` package. - 2. Every time `python manage.py ...` or `nox ...` is run - -## Running the full test suite - -!!! abstract "Note" - - This repository uses [Nox](https://nox.thea.codes/en/stable/) to run tests. For a full test of available scripts run `nox -l`. - -By running the command below you can run the full test suite: - -```bash linenums="0" -nox -t test -``` - -Or, if you want to run the tests in the background: - -```bash linenums="0" -nox -t test -- --headless -``` - -## Running Django tests - -If you want to only run our Django tests in your current environment, you can use the following command: - -```bash linenums="0" -cd tests -python manage.py test -``` - -## Running Django test web server - -If you want to manually run the Django test application, you can use the following command: - -```bash linenums="0" -cd tests -python manage.py runserver -``` - -## Creating a pull request - -{% include-markdown "../../includes/pr.md" %} diff --git a/docs/src/about/contributing.md b/docs/src/about/contributing.md new file mode 100644 index 00000000..ecb0131b --- /dev/null +++ b/docs/src/about/contributing.md @@ -0,0 +1,93 @@ +## Overview + ++ + You will need to set up a Python environment to develop ReactPy-Django. + +
+ +!!! abstract "Note" + + Looking to contribute features that are not Django specific? + + Everything within the `reactpy-django` repository must be specific to Django integration. Check out the [ReactPy Core documentation](https://reactpy.dev/docs/about/contributor-guide.html) to contribute general features such as components, hooks, and events. + +--- + +## Creating a development environment + +If you plan to make code changes to this repository, you will need to install the following dependencies first: + +- [Git](https://git-scm.com/downloads) +- [Python 3.9+](https://www.python.org/downloads/) +- [Hatch](https://hatch.pypa.io/latest/) +- [Bun](https://bun.sh/) + +Once you finish installing these dependencies, you can clone this repository: + +```bash linenums="0" +git clone https://github.com/reactive-python/reactpy-django.git +cd reactpy-django +``` + +## Executing test environment commands + +By utilizing `hatch`, the following commands are available to manage the development environment. + +### Tests + +| Command | Description | +| --- | --- | +| `hatch test` | Run Python tests using the current environment's Python version | +| `hatch test --all` | Run tests using all compatible Python versions | +| `hatch test --python 3.9` | Run tests using a specific Python version | +| `hatch test --include "django=5.1"` | Run tests using a specific Django version | +| `hatch test -k test_object_in_templatetag` | Run only a specific test | +| `hatch test --ds test_app.settings_multi_db` | Run tests with a specific Django settings file | +| `hatch run django:runserver` | Manually run the Django development server without running tests | + +??? question "What other arguments are available to me?" + + The `hatch test` command is a wrapper for `pytest`. Hatch "intercepts" a handful of arguments, which can be previewed by typing `hatch test --help`. + + Any additional arguments in the `test` command are directly passed on to pytest. See the [pytest documentation](https://docs.pytest.org/en/stable/reference/reference.html#command-line-flags) for what additional arguments are available. + +### Linting and Formatting + +| Command | Description | +| --- | --- | +| `hatch fmt` | Run all linters and formatters | +| `hatch fmt --check` | Run all linters and formatters, but do not save fixes to the disk | +| `hatch fmt --linter` | Run only linters | +| `hatch fmt --formatter` | Run only formatters | +| `hatch run javascript:check` | Run the JavaScript linter/formatter | +| `hatch run javascript:fix` | Run the JavaScript linter/formatter and write fixes to disk | + +??? tip "Configure your IDE for linting" + + This repository uses `hatch fmt` for linting and formatting, which is a [modestly customized](https://hatch.pypa.io/latest/config/internal/static-analysis/#default-settings) version of [`ruff`](https://github.com/astral-sh/ruff). + + You can install `ruff` as a plugin to your preferred code editor to create a similar environment. + +### Documentation + +| Command | Description | +| --- | --- | +| `hatch run docs:serve` | Start the [`mkdocs`](https://www.mkdocs.org/) server to view documentation locally | +| `hatch run docs:build` | Build the documentation | +| `hatch run docs:linkcheck` | Check for broken links in the documentation | +| `hatch run docs:check_examples` | Run linter on code examples in the documentation | + +### Environment Management + +| Command | Description | +| --- | --- | +| `hatch build --clean` | Build the package from source | +| `hatch env prune` | Delete all virtual environments created by `hatch` | +| `hatch python install 3.12` | Install a specific Python version to your system | + +??? tip "Check out Hatch for all available commands!" + + This documentation only covers commonly used commands. + + You can type `hatch --help` to see all available commands. diff --git a/docs/src/about/docs.md b/docs/src/about/docs.md deleted file mode 100644 index 712570ec..00000000 --- a/docs/src/about/docs.md +++ /dev/null @@ -1,45 +0,0 @@ -## Overview - -- -You will need to set up a Python environment to create, test, and preview docs changes. - -
- ---- - -## Modifying Docs - -If you plan to make changes to this documentation, you will need to install the following dependencies first: - -- [Python 3.9+](https://www.python.org/downloads/) -- [Git](https://git-scm.com/downloads) - -Once done, you should clone this repository: - -```bash linenums="0" -git clone https://github.com/reactive-python/reactpy-django.git -cd reactpy-django -``` - -Then, by running the command below you can: - -- Install an editable version of the documentation -- Self-host a test server for the documentation - -```bash linenums="0" -pip install -r requirements.txt --upgrade -``` - -Finally, to verify that everything is working properly, you can manually run the docs preview web server. - -```bash linenums="0" -cd docs -mkdocs serve -``` - -Navigate to [`http://127.0.0.1:8000`](http://127.0.0.1:8000) to view a preview of the documentation. - -## GitHub Pull Request - -{% include-markdown "../../includes/pr.md" %} diff --git a/docs/src/dictionary.txt b/docs/src/dictionary.txt index 14aa7a61..1b4ce080 100644 --- a/docs/src/dictionary.txt +++ b/docs/src/dictionary.txt @@ -43,3 +43,8 @@ unstyled WebSocket WebSockets whitespace +pytest +linter +linters +linting +formatters diff --git a/docs/src/reference/settings.md b/docs/src/reference/settings.md index e65dd203..23760919 100644 --- a/docs/src/reference/settings.md +++ b/docs/src/reference/settings.md @@ -117,7 +117,7 @@ We recommend using [`redis`](https://docs.djangoproject.com/en/stable/topics/cac Configures whether ReactPy components are rendered in a dedicated thread. -This allows the web server to process other traffic during ReactPy rendering. Vastly improves throughput with web servers such as [`hypercorn`](https://pgjones.gitlab.io/hypercorn/) and [`uvicorn`](https://www.uvicorn.org/). +This allows the web server to process other traffic during ReactPy rendering. Vastly improves throughput with web servers such as [`hypercorn`](https://github.com/pgjones/hypercorn) and [`uvicorn`](https://www.uvicorn.org/). This setting is incompatible with [`daphne`](https://github.com/django/daphne). diff --git a/noxfile.py b/noxfile.py deleted file mode 100644 index 8776de45..00000000 --- a/noxfile.py +++ /dev/null @@ -1,73 +0,0 @@ -from __future__ import annotations - -from glob import glob -from pathlib import Path - -from nox import Session, session - -ROOT_DIR = Path(__file__).parent - - -@session(tags=["test"]) -def test_python(session: Session) -> None: - """Run the Python-based test suite""" - install_requirements_file(session, "test-env") - session.install(".[all]") - session.chdir(ROOT_DIR / "tests") - session.env["REACTPY_DEBUG_MODE"] = "1" - - posargs = session.posargs[:] - if "--headless" in posargs: - posargs.remove("--headless") - session.env["PLAYWRIGHT_HEADLESS"] = "1" - - if "--no-debug-mode" not in posargs: - posargs.append("--debug-mode") - - session.run("playwright", "install", "chromium") - - # Run tests for each settings file (tests/test_app/settings_*.py) - settings_glob = "test_app/settings_*.py" - settings_files = glob(settings_glob) - assert settings_files, f"No Django settings files found at '{settings_glob}'!" - for settings_file in settings_files: - settings_module = ( - settings_file.strip(".py").replace("/", ".").replace("\\", ".") - ) - session.run( - "python", - "manage.py", - "test", - *posargs, - "--settings", - settings_module, - ) - - -@session(tags=["test"]) -def test_types(session: Session) -> None: - install_requirements_file(session, "check-types") - install_requirements_file(session, "pkg-deps") - session.run("mypy", "--show-error-codes", "src/reactpy_django", "tests/test_app") - - -@session(tags=["test"]) -def test_style(session: Session) -> None: - """Check that style guidelines are being followed""" - install_requirements_file(session, "check-style") - session.run("ruff", "check", ".") - - -@session(tags=["test"]) -def test_javascript(session: Session) -> None: - install_requirements_file(session, "test-env") - session.chdir(ROOT_DIR / "src" / "js") - session.run("bun", "install", external=True) - session.run("bun", "run", "check", external=True) - - -def install_requirements_file(session: Session, name: str) -> None: - session.install("--upgrade", "pip", "setuptools", "wheel") - file_path = ROOT_DIR / "requirements" / f"{name}.txt" - assert file_path.exists(), f"requirements file {file_path} does not exist" - session.install("-r", str(file_path)) diff --git a/pyproject.toml b/pyproject.toml index 99ff6917..44f920a6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,21 +1,215 @@ [build-system] -requires = ["setuptools>=42", "wheel"] -build-backend = "setuptools.build_meta" +build-backend = "hatchling.build" +requires = ["hatchling", "hatch-build-scripts"] -[tool.mypy] -exclude = ['migrations/.*'] -ignore_missing_imports = true -warn_unused_configs = true -warn_redundant_casts = true -warn_unused_ignores = true -check_untyped_defs = true +############################## +# >>> Hatch Build Config <<< # +############################## -[tool.ruff.lint.isort] -known-first-party = ["src", "tests"] +[project] +name = "reactpy_django" +description = "It's React, but in Python. Now with Django integration." +readme = "README.md" +keywords = [ + "React", + "ReactJS", + "ReactPy", + "components", + "asgi", + "django", + "http", + "server", + "reactive", + "interactive", +] +license = "MIT" +authors = [{ name = "Mark Bakhit", email = "archiethemonger@gmail.com" }] +requires-python = ">=3.9" +classifiers = [ + "Framework :: Django", + "Framework :: Django :: 4.0", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Operating System :: OS Independent", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Topic :: Multimedia :: Graphics", + "Topic :: Software Development :: Widget Sets", + "Topic :: Software Development :: User Interfaces", + "Environment :: Web Environment", + "Typing :: Typed", +] +dependencies = [ + "channels>=4.0.0", + "django>=4.2.0", + "reactpy>=1.1.0, <2.0.0", + "reactpy-router>=1.0.3, <2.0.0", + "dill>=0.3.5", + "orjson>=3.6.0", + "nest_asyncio>=1.5.0", + "typing_extensions", +] +dynamic = ["version"] +urls.Changelog = "https://reactive-python.github.io/reactpy-django/latest/about/changelog/" +urls.Documentation = "https://reactive-python.github.io/reactpy-django/" +urls.Source = "https://github.com/reactive-python/reactpy-django" -[tool.ruff.lint] -ignore = ["E501"] +[tool.hatch.version] +path = "src/reactpy_django/__init__.py" + +[tool.hatch.build.targets.sdist] +include = ["/src"] +artifacts = ["/src/reactpy_django/static/"] + +[tool.hatch.build.targets.wheel] +artifacts = ["/src/reactpy_django/static/"] + +[tool.hatch.metadata] +license-files = { paths = ["LICENSE.md"] } + +[tool.hatch.envs.default] +installer = "uv" + +[[tool.hatch.build.hooks.build-scripts.scripts]] +commands = [ + "bun install --cwd src/js", + "bun build src/js/src/index.tsx --outfile src/reactpy_django/static/reactpy_django/client.js --minify", + 'cd src/build_scripts && python copy_dir.py "src/js/node_modules/@pyscript/core/dist" "src/reactpy_django/static/reactpy_django/pyscript"', + 'cd src/build_scripts && python copy_dir.py "src/js/node_modules/morphdom/dist" "src/reactpy_django/static/reactpy_django/morphdom"', +] +artifacts = [] + +############################# +# >>> Hatch Test Runner <<< # +############################# + +[tool.hatch.envs.hatch-test] +extra-dependencies = [ + "pytest-sugar", + "pytest-django", + "playwright", + "channels[daphne]>=4.0.0", + "twisted", + "tblib", + "servestatic", +] +matrix-name-format = "{variable}-{value}" + +# Django 4.2 +[[tool.hatch.envs.hatch-test.matrix]] +python = ["3.9", "3.10", "3.11", "3.12"] +django = ["4.2"] + +# Django 5.0 +[[tool.hatch.envs.hatch-test.matrix]] +python = ["3.10", "3.11", "3.12"] +django = ["5.0"] + +# Django 5.1 +[[tool.hatch.envs.hatch-test.matrix]] +python = ["3.10", "3.11", "3.12", "3.13"] +django = ["5.1"] + +[tool.hatch.envs.hatch-test.overrides] +matrix.django.dependencies = [ + { if = [ + "4.2", + ], value = "django~=4.2" }, + { if = [ + "5.0", + ], value = "django~=5.0" }, + { if = [ + "5.1", + ], value = "django~=5.1" }, +] + +[tool.pytest.ini_options] +addopts = """\ + --strict-config + --strict-markers + --reuse-db + """ +django_find_project = false +DJANGO_SETTINGS_MODULE = "test_app.settings_single_db" +pythonpath = [".", "tests/"] + +################################ +# >>> Hatch Django Scripts <<< # +################################ + +[tool.hatch.envs.django] +extra-dependencies = ["channels[daphne]>=4.0.0", "twisted", "servestatic"] + +[tool.hatch.envs.django.scripts] +runserver = [ + "cd tests && python manage.py migrate --noinput", + "cd tests && python manage.py runserver", +] + +####################################### +# >>> Hatch Documentation Scripts <<< # +####################################### + +[tool.hatch.envs.docs] +template = "docs" +extra-dependencies = [ + "mkdocs", + "mkdocs-git-revision-date-localized-plugin", + "mkdocs-material==9.4.0", + "mkdocs-include-markdown-plugin", + "mkdocs-spellcheck[all]", + "mkdocs-git-authors-plugin", + "mkdocs-minify-plugin", + "mike", + "ruff", + "django-stubs", + "linkcheckmd", +] + +[tool.hatch.envs.docs.scripts] +serve = ["cd docs && mkdocs serve"] +build = ["cd docs && mkdocs build --strict"] +linkcheck = [ + "linkcheckMarkdown docs/ -v -r --method head", + "linkcheckMarkdown README.md -v -r", + "linkcheckMarkdown CHANGELOG.md -v -r", +] +deploy_latest = ["cd docs && mike deploy --push --update-aliases {args} latest"] +deploy_develop = ["cd docs && mike deploy --push develop"] +check_examples = ["ruff check docs/examples/python"] + +############################ +# >>> Hatch JS Scripts <<< # +############################ + +[tool.hatch.envs.javascript] +detached = true + +[tool.hatch.envs.javascript.scripts] +check = ["cd src/js && bun install", "cd src/js && bun run check"] +fix = ["cd src/js && bun install", "cd src/js && bun run format"] + +######################### +# >>> Generic Tools <<< # +######################### [tool.ruff] extend-exclude = ["*/migrations/*", ".venv/*", ".eggs/*", ".nox/*", "build/*"] line-length = 120 +format.preview = true +lint.extend-ignore = [ + "ARG001", # Unused function argument + "ARG002", # Unused method argument + "ARG004", # Unused static method argument + "FBT001", # Boolean-typed positional argument in function definition + "FBT002", # Boolean default positional argument in function definition + "PLR2004", # Magic value used in comparison + "SIM115", # Use context handler for opening files + "SLF001", # Private member accessed + "E501", # Line too long + "PLC0415", # `import` should be at the top-level of a file +] +lint.preview = true +lint.isort.known-first-party = ["src", "tests"] diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 63e3d68e..00000000 --- a/requirements.txt +++ /dev/null @@ -1,8 +0,0 @@ --r requirements/build-docs.txt --r requirements/build-pkg.txt --r requirements/check-style.txt --r requirements/check-types.txt --r requirements/dev-env.txt --r requirements/pkg-deps.txt --r requirements/test-env.txt --r requirements/test-run.txt diff --git a/requirements/build-docs.txt b/requirements/build-docs.txt deleted file mode 100644 index 846a7ba3..00000000 --- a/requirements/build-docs.txt +++ /dev/null @@ -1,8 +0,0 @@ -mkdocs -mkdocs-git-revision-date-localized-plugin -mkdocs-material==9.4.0 -mkdocs-include-markdown-plugin -mkdocs-spellcheck[all] -mkdocs-git-authors-plugin -mkdocs-minify-plugin -mike diff --git a/requirements/build-pkg.txt b/requirements/build-pkg.txt deleted file mode 100644 index 82f40eaf..00000000 --- a/requirements/build-pkg.txt +++ /dev/null @@ -1,3 +0,0 @@ -twine -wheel -build diff --git a/requirements/check-style.txt b/requirements/check-style.txt deleted file mode 100644 index af3ee576..00000000 --- a/requirements/check-style.txt +++ /dev/null @@ -1 +0,0 @@ -ruff diff --git a/requirements/check-types.txt b/requirements/check-types.txt deleted file mode 100644 index c962b716..00000000 --- a/requirements/check-types.txt +++ /dev/null @@ -1,3 +0,0 @@ -mypy -django-stubs[compatible-mypy] -channels-redis diff --git a/requirements/dev-env.txt b/requirements/dev-env.txt deleted file mode 100644 index 05940702..00000000 --- a/requirements/dev-env.txt +++ /dev/null @@ -1,3 +0,0 @@ -twine -wheel --r ./test-run.txt diff --git a/requirements/pkg-deps.txt b/requirements/pkg-deps.txt deleted file mode 100644 index 61182ef9..00000000 --- a/requirements/pkg-deps.txt +++ /dev/null @@ -1,8 +0,0 @@ -channels >=4.0.0 -django >=4.2.0 -reactpy >=1.1.0, <1.2.0 -reactpy-router >=1.0.0, <2.0.0 -dill >=0.3.5 -orjson >=3.6.0 -nest_asyncio >=1.5.0 -typing_extensions diff --git a/requirements/test-env.txt b/requirements/test-env.txt deleted file mode 100644 index fc1ba2ce..00000000 --- a/requirements/test-env.txt +++ /dev/null @@ -1,5 +0,0 @@ -playwright -twisted -channels[daphne]>=4.0.0 -tblib -whitenoise diff --git a/requirements/test-run.txt b/requirements/test-run.txt deleted file mode 100644 index 816817c6..00000000 --- a/requirements/test-run.txt +++ /dev/null @@ -1 +0,0 @@ -nox diff --git a/setup.py b/setup.py deleted file mode 100644 index f0c2f22d..00000000 --- a/setup.py +++ /dev/null @@ -1,182 +0,0 @@ -from __future__ import annotations, print_function - -import shutil -import subprocess -import sys -import traceback -from logging import getLogger -from pathlib import Path - -from setuptools import find_namespace_packages, setup -from setuptools.command.develop import develop -from setuptools.command.sdist import sdist - -# ----------------------------------------------------------------------------- -# Basic Constants -# ----------------------------------------------------------------------------- -name = "reactpy_django" -root_dir = Path(__file__).parent -src_dir = root_dir / "src" -js_dir = src_dir / "js" -package_dir = src_dir / name -static_dir = package_dir / "static" / name -log = getLogger(__name__) - - -# ----------------------------------------------------------------------------- -# Package Definition -# ----------------------------------------------------------------------------- -package = { - "name": name, - "python_requires": ">=3.9", - "packages": find_namespace_packages(src_dir), - "package_dir": {"": "src"}, - "description": "It's React, but in Python. Now with Django integration.", - "author": "Mark Bakhit", - "author_email": "archiethemonger@gmail.com", - "url": "https://github.com/reactive-python/reactpy-django", - "license": "MIT", - "platforms": "Linux, Mac OS X, Windows", - "keywords": [ - "interactive", - "reactive", - "widgets", - "DOM", - "React", - "ReactJS", - "ReactPy", - ], - "include_package_data": True, - "zip_safe": False, - "classifiers": [ - "Framework :: Django", - "Framework :: Django :: 4.0", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Operating System :: OS Independent", - "Intended Audience :: Developers", - "Intended Audience :: Science/Research", - "Topic :: Multimedia :: Graphics", - "Topic :: Software Development :: Widget Sets", - "Topic :: Software Development :: User Interfaces", - "Environment :: Web Environment", - "Typing :: Typed", - ], -} - - -# ----------------------------------------------------------------------------- -# Library Version -# ----------------------------------------------------------------------------- -for line in (package_dir / "__init__.py").read_text().split("\n"): - if line.startswith("__version__ = "): - package["version"] = eval(line.split("=", 1)[1]) - break -else: - print(f"No version found in {package_dir}/__init__.py") - sys.exit(1) - - -# ----------------------------------------------------------------------------- -# Requirements -# ----------------------------------------------------------------------------- -requirements: list[str] = [] -with (root_dir / "requirements" / "pkg-deps.txt").open() as f: - requirements.extend(line for line in map(str.strip, f) if not line.startswith("#")) -package["install_requires"] = requirements - - -# ----------------------------------------------------------------------------- -# Library Description -# ----------------------------------------------------------------------------- -with (root_dir / "README.md").open() as f: - long_description = f.read() - -package["long_description"] = long_description -package["long_description_content_type"] = "text/markdown" - - -# ---------------------------------------------------------------------------- -# Build Javascript -# ---------------------------------------------------------------------------- -def copy_js_files(source_dir: Path, destination: Path) -> None: - if destination.exists(): - shutil.rmtree(destination) - destination.mkdir() - - for file in source_dir.iterdir(): - if file.is_file(): - shutil.copy(file, destination / file.name) - else: - copy_js_files(file, destination / file.name) - - -def build_javascript_first(build_cls: type): - class Command(build_cls): - def run(self): - - log.info("Installing Javascript...") - result = subprocess.run( - ["bun", "install"], cwd=str(js_dir), check=True - ).returncode - if result != 0: - log.error(traceback.format_exc()) - log.error("Failed to install Javascript") - raise RuntimeError("Failed to install Javascript") - - log.info("Building Javascript...") - result = subprocess.run( - [ - "bun", - "build", - "./src/index.tsx", - "--outfile", - str(static_dir / "client.js"), - "--minify", - ], - cwd=str(js_dir), - check=True, - ).returncode - if result != 0: - log.error(traceback.format_exc()) - log.error("Failed to build Javascript") - raise RuntimeError("Failed to build Javascript") - - log.info("Copying @pyscript/core distribution") - pyscript_dist = js_dir / "node_modules" / "@pyscript" / "core" / "dist" - pyscript_static_dir = static_dir / "pyscript" - copy_js_files(pyscript_dist, pyscript_static_dir) - - log.info("Copying Morphdom distribution") - morphdom_dist = js_dir / "node_modules" / "morphdom" / "dist" - morphdom_static_dir = static_dir / "morphdom" - copy_js_files(morphdom_dist, morphdom_static_dir) - - log.info("Successfully built Javascript") - super().run() - - return Command - - -package["cmdclass"] = { - "sdist": build_javascript_first(sdist), - "develop": build_javascript_first(develop), -} - -if sys.version_info < (3, 10, 6): - from distutils.command.build import build - - package["cmdclass"]["build"] = build_javascript_first(build) -else: - from setuptools.command.build_py import build_py - - package["cmdclass"]["build_py"] = build_javascript_first(build_py) - - -# ----------------------------------------------------------------------------- -# Installation -# ----------------------------------------------------------------------------- -if __name__ == "__main__": - setup(**package) diff --git a/src/build_scripts/copy_dir.py b/src/build_scripts/copy_dir.py new file mode 100644 index 00000000..1f446f83 --- /dev/null +++ b/src/build_scripts/copy_dir.py @@ -0,0 +1,31 @@ +import shutil +import sys +from pathlib import Path + + +def copy_files(source: Path, destination: Path) -> None: + if destination.exists(): + shutil.rmtree(destination) + destination.mkdir() + + for file in source.iterdir(): + if file.is_file(): + shutil.copy(file, destination / file.name) + else: + copy_files(file, destination / file.name) + + +if __name__ == "__main__": + if len(sys.argv) != 3: + print("Usage: python copy_dir.py{% firstof reactpy_error "UnknownError" %}: "{% firstof reactpy_dotted_path "UnknownPath" %}"{% endif %} @@ -10,18 +10,18 @@ {% if reactpy_prerender_html %}