diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..170d7ddb --- /dev/null +++ b/.editorconfig @@ -0,0 +1,36 @@ +# http://editorconfig.org + +root = true + +[*] +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true +charset = utf-8 +end_of_line = lf + +[*.py] +indent_size = 4 +max_line_length = 120 + +[*.yml] +indent_size = 4 + +[*.md] +indent_size = 4 + +[*.html] +indent_size = 4 +max_line_length = off + +[*.js] +max_line_length = off + +[*.css] +indent_size = 4 +max_line_length = off + +# Tests can violate line width restrictions in the interest of clarity. +[**/test_*.py] +max_line_length = off diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index e01b3e62..12f72a6a 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,6 +1,6 @@ # These are supported funding model platforms -github: [rmorshea] +github: [archmonger] patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index f237e91d..a5553200 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,13 +1,14 @@ -*By submitting this pull request you agree that all contributions to this project are made under the MIT license.* - ## Description -A summary of the changes. + -## Checklist: +## Checklist Please update this checklist as you complete each item: -- [ ] Tests have been included for all bug fixes or added functionality. -- [ ] The changelog has been updated with any significant changes, if necessary. -- [ ] GitHub Issues which may be closed by this PR have been linked. +- [ ] Tests have been developed for bug fixes or new functionality. +- [ ] The changelog has been updated, if necessary. +- [ ] Documentation has been updated, if necessary. +- [ ] GitHub Issues closed by this PR have been linked. + +By submitting this pull request I agree that all contributions comply with this project's open source license(s). diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 0f26793e..63a412e0 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -12,67 +12,66 @@ name: "CodeQL" on: - push: - branches: [ "main" ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ "main" ] - schedule: - # Runs at 22:21 on Monday. - - cron: '21 22 * * 1' + push: + branches: ["main"] + pull_request: + # The branches below must be a subset of the branches above + branches: ["main"] + schedule: + # Runs at 22:21 on Monday. + - cron: "21 22 * * 1" jobs: - analyze: - name: Analyze - runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} - timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} - permissions: - actions: read - contents: read - security-events: write + analyze: + name: Analyze + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} + permissions: + actions: read + contents: read + security-events: write - strategy: - fail-fast: false - matrix: - language: [ 'javascript', 'python' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby', 'swift' ] - # Use only 'java' to analyze code written in Java, Kotlin or both - # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both - # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + strategy: + fail-fast: false + matrix: + language: ["javascript", "python"] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby', 'swift' ] + # Use only 'java' to analyze code written in Java, Kotlin or both + # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support - steps: - - name: Checkout repository - uses: actions/checkout@v3 + steps: + - name: Checkout repository + uses: actions/checkout@v4 - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. - # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v3 - # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 + # â„šī¸ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - # â„šī¸ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. - # If the Autobuild fails above, remove it and uncomment the following three lines. - # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh - # - run: | - # echo "Run, Build Application using script" - # ./location_of_script_within_repo/buildscript.sh - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 - with: - category: "/language:${{matrix.language}}" + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/publish-develop-docs.yml b/.github/workflows/publish-develop-docs.yml new file mode 100644 index 00000000..43d114af --- /dev/null +++ b/.github/workflows/publish-develop-docs.yml @@ -0,0 +1,29 @@ +name: Publish Develop Docs + +on: + push: + branches: + - main +jobs: + publish-develop-docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + - uses: actions/setup-python@v5 + with: + python-version: 3.x + - name: Install dependencies + run: pip install hatch + - name: Configure Git + run: | + git config user.name github-actions + git config user.email github-actions@github.com + - name: Publish Develop Docs + run: hatch run docs:deploy_develop + concurrency: + group: publish-docs diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml deleted file mode 100644 index d6339c6b..00000000 --- a/.github/workflows/publish-docs.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Publish Docs -on: - push: - branches: - - main -jobs: - deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - uses: actions/setup-python@v4 - with: - python-version: 3.x - - run: pip install -r requirements/build-docs.txt - - run: mkdocs gh-deploy --force diff --git a/.github/workflows/publish-latest-docs.yml b/.github/workflows/publish-latest-docs.yml new file mode 100644 index 00000000..a4945b6f --- /dev/null +++ b/.github/workflows/publish-latest-docs.yml @@ -0,0 +1,29 @@ +name: Publish Latest Docs + +on: + release: + types: [published] + +jobs: + publish-latest-docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + - uses: actions/setup-python@v5 + with: + python-version: 3.x + - name: Install dependencies + run: pip install hatch + - name: Configure Git + run: | + git config user.name github-actions + git config user.email github-actions@github.com + - name: Publish ${{ github.event.release.name }} Docs + run: 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 deleted file mode 100644 index 4439cb5e..00000000 --- a/.github/workflows/publish-py.yml +++ /dev/null @@ -1,36 +0,0 @@ -# This workflows will upload a Python Package using Twine when a release is created -# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries - -name: Publish Python - -on: - release: - types: [published] - -jobs: - release-package: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: "14.x" - - name: Set up Python - uses: actions/setup-python@v1 - with: - python-version: "3.x" - - name: Install NPM - run: | - npm install -g npm@7.22.0 - npm --version - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements/build-pkg.txt - - name: Build and publish - env: - TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} - TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} - run: | - python -m build --sdist --wheel --outdir dist . - twine upload dist/* diff --git a/.github/workflows/publish-python.yml b/.github/workflows/publish-python.yml new file mode 100644 index 00000000..e20affbb --- /dev/null +++ b/.github/workflows/publish-python.yml @@ -0,0 +1,27 @@ +name: Publish Python + +on: + release: + types: [published] + +jobs: + publish-python: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.x" + - name: Install dependencies + run: pip install hatch + - name: Build Package + run: hatch build --clean + - name: Publish to PyPI + env: + HATCH_INDEX_USER: ${{ secrets.PYPI_USERNAME }} + HATCH_INDEX_AUTH: ${{ secrets.PYPI_PASSWORD }} + run: hatch publish --yes diff --git a/.github/workflows/test-docs.yml b/.github/workflows/test-docs.yml index 4a988d2d..5a2d4fd4 100644 --- a/.github/workflows/test-docs.yml +++ b/.github/workflows/test-docs.yml @@ -7,31 +7,26 @@ on: pull_request: branches: - main - schedule: - - cron: "0 0 * * *" jobs: docs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-python@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 hatch + # 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 - linkcheckMarkdown docs/ -v -r - linkcheckMarkdown README.md -v -r - linkcheckMarkdown CHANGELOG.md -v -r - 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/python/ - black docs/python/ --check - isort docs/python/ --check-only - flake8 docs/python/ + run: hatch fmt docs --check diff --git a/.github/workflows/test-javascript.yml b/.github/workflows/test-javascript.yml new file mode 100644 index 00000000..8e204dcb --- /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 hatch + - name: Run Tests + run: hatch run javascript:check diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml new file mode 100644 index 00000000..ac8d77b6 --- /dev/null +++ b/.github/workflows/test-python.yml @@ -0,0 +1,63 @@ +name: Test + +on: + push: + branches: + - main + pull_request: + branches: + - main + schedule: + - cron: "0 0 * * *" + +jobs: + python-source: + runs-on: ${{ matrix.operating-system }} + strategy: + matrix: + python-version: ["3.9", "3.10", "3.11", "3.12"] + settings-module: ["single_db", "multi_db"] + operating-system: ["ubuntu-latest", "windows-latest"] + steps: + - uses: actions/checkout@v4 + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + - name: Use Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install Python Dependencies + run: pip install hatch + - name: Run Single DB Tests + run: hatch test --python ${{ matrix.python-version }} --ds=test_app.settings_${{matrix.settings-module}} -v + + python-formatting: + 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 hatch + - name: Check Python formatting + run: hatch fmt src tests --check + + python-types: + 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 hatch + - name: Run Python type checker + run: hatch run python:type_check diff --git a/.github/workflows/test-src.yml b/.github/workflows/test-src.yml deleted file mode 100644 index 16c6cd5d..00000000 --- a/.github/workflows/test-src.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Test - -on: - push: - branches: - - main - pull_request: - branches: - - main - schedule: - - cron: "0 0 * * *" - -jobs: - source: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.8", "3.9", "3.10"] - steps: - - uses: actions/checkout@v3 - - uses: nanasess/setup-chromedriver@master - - uses: actions/setup-node@v3 - with: - node-version: "14" - - name: Use Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - name: Install Python Dependencies - run: pip install -r requirements/test-run.txt - - name: Run Tests - run: | - npm install -g npm@latest - npm --version - nox -s test diff --git a/.gitignore b/.gitignore index a59a51e4..e675e09a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ # ReactPy-Django Build Artifacts -src/reactpy_django/static/* +src/reactpy_django/static/reactpy_django/index.js +src/reactpy_django/static/reactpy_django/index.js.map +src/reactpy_django/static/reactpy_django/pyscript +src/reactpy_django/static/reactpy_django/morphdom # Django # logs @@ -89,8 +92,8 @@ celerybeat-schedule.* *.sage.py # Environments -.env -.venv +.env*/ +.venv*/ env/ venv/ ENV/ @@ -99,6 +102,7 @@ venv.bak/ # mkdocs documentation /site +docs/site # mypy .mypy_cache/ diff --git a/.mailmap b/.mailmap new file mode 100644 index 00000000..1e68fb67 --- /dev/null +++ b/.mailmap @@ -0,0 +1,2 @@ +# .mailmap +Mark Bakhit <16909269+archmonger@users.noreply.github.com> diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..32ad81f3 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "proseWrap": "never", + "trailingComma": "all" +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 10bb1d3f..f3a0ff04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,31 +10,288 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), + + + +## [Unreleased] + +### Changed + +- Updated the interface for `reactpy.hooks.use_channel_layer` to be more intuitive. + - Arguments now must be provided as keyworded arguments. + - The `name` argument has been renamed to `channel`. + - The `group_name` argument has been renamed to `group`. + - The `group_add` and `group_discard` arguments have been removed for simplicity. + +### [5.2.1] - 2025-01-10 + +### Changed + +- Use the latest version of `@reactpy/client` which includes a fix for needless client-side component re-creation. + +### [5.2.0] - 2024-12-29 ### Added -- for new features. + +- User login/logout features! + - `reactpy_django.hooks.use_auth` to provide **persistent** `login` and `logout` functionality to your components. + - `settings.py:REACTPY_AUTH_TOKEN_MAX_AGE` to control the maximum seconds before ReactPy's login token expires. + - `settings.py:REACTPY_CLEAN_AUTH_TOKENS` to control whether ReactPy should clean up expired authentication tokens during automatic cleanups. +- Automatically convert Django forms to ReactPy forms via the new `reactpy_django.components.django_form` component! +- The ReactPy component tree can now be forcibly re-rendered via the new `reactpy_django.hooks.use_rerender` hook. ### Changed -- for changes in existing functionality. + +- Refactoring of internal code to improve maintainability. No changes to publicly documented API. + +### Fixed + +- Fixed bug where pre-rendered components could generate a `SynchronousOnlyOperation` exception if they access a freshly logged out Django user object. + +## [5.1.1] - 2024-12-02 + +### Fixed + +- Fixed regression from the previous release 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`. +- ReactPy web modules are now streamed in chunks. +- ReactPy web modules are now streamed using asynchronous file reading to improve performance. +- Performed refactoring to utilize `ruff` as this repository's linter. + +## [5.1.0] - 2024-11-24 + +### Added + +- `settings.py:REACTPY_ASYNC_RENDERING` to enable asynchronous rendering of components. + +### Changed + +- Bumped the minimum ReactPy version to `1.1.0`. + +## [5.0.0] - 2024-10-22 + +### Changed + +- Now using ReactPy-Router v1 for URL routing, which comes with a slightly different API than before. +- Removed dependency on `aiofile`. + +### Removed + +- Removed the following **deprecated** features: + - The `compatibility` argument on `reactpy_django.components.view_to_component` + - `reactpy_django.components.view_to_component` **usage as a decorator** + - `reactpy_django.decorators.auth_required` + - `reactpy_django.REACTPY_WEBSOCKET_PATH` + - `settings.py:REACTPY_WEBSOCKET_URL` + +## [4.0.0] - 2024-06-22 + +### Added + +- Client-side Python components can now be rendered via the new `{% pyscript_component %}` template tag + - You must first call the `{% pyscript_setup %}` template tag to load PyScript dependencies +- Client-side components can be embedded into existing server-side components via `reactpy_django.components.pyscript_component`. +- Tired of writing JavaScript? You can now write PyScript code that runs directly within client browser via the `reactpy_django.html.pyscript` element. + - This is a viable substitution for most JavaScript code. + +### Changed + +- New syntax for `use_query` and `use_mutation` hooks. Here's a quick comparison of the changes: + + ```python + query = use_query(QueryOptions(thread_sensitive=True), get_items, foo="bar") # Old + query = use_query(get_items, {"foo":"bar"}, thread_sensitive=True) # New + + mutation = use_mutation(MutationOptions(thread_sensitive=True), remove_item) # Old + mutation = use_mutation(remove_item, thread_sensitive=True) # New + ``` + +### Removed + +- `QueryOptions` and `MutationOptions` have been removed. The value contained within these objects are now passed directly into the hook. + +### Fixed + +- Resolved a bug where Django-ReactPy would not properly detect `settings.py:DEBUG`. + +## [3.8.1] - 2024-05-07 + +### Added + +- Python 3.12 compatibility + +## [3.8.0] - 2024-02-20 + +### Added + +- Built-in cross-process communication mechanism via the `reactpy_django.hooks.use_channel_layer` hook. +- Access to the root component's `id` via the `reactpy_django.hooks.use_root_id` hook. +- More robust control over ReactPy clean up tasks! + - `settings.py:REACTPY_CLEAN_INTERVAL` to control how often ReactPy automatically performs cleaning tasks. + - `settings.py:REACTPY_CLEAN_SESSIONS` to control whether ReactPy should clean up expired sessions during automatic cleanups. + - `settings.py:REACTPY_CLEAN_USER_DATA` to control whether ReactPy should clean up orphaned user data during automatic cleanups. + - `python manage.py clean_reactpy` command to manually perform ReactPy clean up tasks. + +### Changed + +- Simplified code for cascading deletion of user data. + +## [3.7.0] - 2024-01-30 + +### Added + +- An "offline component" can now be displayed when the client disconnects from the server. +- URL router now supports a `*` wildcard to create default routes. + +## [3.6.0] - 2024-01-10 + +### Added + +- Built-in Single Page Application (SPA) support! + - `reactpy_django.router.django_router` can be used to render your Django application as a SPA. +- SEO compatible rendering! + - `settings.py:REACTPY_PRERENDER` can be set to `True` to make components pre-render by default. + - Or, you can enable it on individual components via the template tag: `{% component "..." prerender="True" %}`. +- New `view_to_iframe` feature! + - `reactpy_django.components.view_to_iframe` uses an `