Skip to content

Deploy v25.12 docs#3125

Closed
ahopkins wants to merge 46 commits intoguidefrom
main
Closed

Deploy v25.12 docs#3125
ahopkins wants to merge 46 commits intoguidefrom
main

Conversation

@ahopkins
Copy link
Member

No description provided.

chuiniudawang and others added 30 commits January 2, 2025 12:26
* added minor type hinting

* apply linter
* Cleanup some typing

* Add custom CLI commands

* Add unit tests

* Align checks and versions

* Add SIGKILL type

* squash
* Add REPL context

* fix(type): add missing return type

* chore: rename method and add docstring

* fix: handle null docstring

* chore: add test case

* Add direct attr setting

---------

Co-authored-by: goodki-d <[email protected]>
* Cleanup some typing

* Add custom CLI commands

* Add unit tests

* Fix body check in websockets handshake
* Cleanup some typing

* Add custom CLI commands

* Add unit tests

* Add missing test to workflow
* Cleanup some typing

* Add custom CLI commands

* Add unit tests

* Add default to response cookies
Replaced random payload generation with secrets module for better security. [B311:blacklist] was failing in security tests.
* Add some typing and fix some tests

* Pulled in security fixes
Fixes #3055

During worker restart, a race condition occurs between WorkerProcess.restart()
and WorkerManager._sync_states() that causes the restart to fail with:
"Cannot spawn a worker process until it is idle."

The race condition happens when:
1. WorkerProcess.restart() sets state to RESTARTING and terminates the process
2. WorkerManager._sync_states() runs concurrently, sees process is not alive
3. _sync_states() changes state from RESTARTING to COMPLETED
4. WorkerProcess.restart() tries to spawn(), but state is now COMPLETED
5. spawn() raises exception because state is not IDLE or RESTARTING

The fix prevents _sync_states() from changing the state of processes that
are in the RESTARTING state, allowing the restart flow to complete without
interference.

Changes:
- Added check in _sync_states() to skip processes with state RESTARTING
- This prevents the race condition by ensuring restart flow is not interrupted
- Safe change: RESTARTING is temporary, managed entirely by restart() method
- No performance impact: just one additional state check per process

Co-authored-by: Adam Hopkins <[email protected]>
…3085)

Fixes #3081

During server shutdown, the _cleanup() function in runners.py calls
close_if_idle() on all connection objects. However, if a connection
was created but connection_task() hasn't called _setup_connection()
yet, the _http attribute doesn't exist, causing an AttributeError.

The HttpProtocolMixin already provides an 'http' property (lines 73-77)
that safely handles this case using hasattr(). This commit updates
close_if_idle() to use the property instead of direct attribute access.

Changes:
- Changed self._http to self.http in close_if_idle() method
- This leverages the existing property that returns None when _http
  doesn't exist yet
- Maintains exact same behavior for initialized connections
- Prevents AttributeError for uninitialized connections during shutdown

Co-authored-by: Adam Hopkins <[email protected]>
* Add typing for parameters of constructor of `WorkerManager`

Signed-off-by: Zhiwei Liang <[email protected]>

* Change to Dict

* Add future annotations

* Cleanup

---------

Signed-off-by: Zhiwei Liang <[email protected]>
Co-authored-by: Adam Hopkins <[email protected]>
…3080)

* Update str_to_bool function to include 'nope' as a valid false value

* Run make pretty

---------

Co-authored-by: Adam Hopkins <[email protected]>
* Windows has no os.killpg

* Actually kill processes on Windows

---------

Co-authored-by: Adam Hopkins <[email protected]>
Change `dicussed` to `discussed`

Co-authored-by: Adam Hopkins <[email protected]>
* Change the log type to debug

* Fixed incorrect links throughout the documentation

* Update compat.py

---------

Co-authored-by: Adam Hopkins <[email protected]>
* Update required Python to >=3.9

* Remove more Python 3.8 reference
Tronic and others added 16 commits December 4, 2025 07:51
* feat: Add automatic charset=UTF-8 to text content types

Refactor content type handling to automatically append charset=UTF-8
to text/* MIME types when serving static files and file responses.

- Add new guess_content_type() utility function that wraps mimetypes.guess_type()
- Automatically append '; charset=UTF-8' to text content types
- Replace direct mimetypes.guess_type() usage with new utility
- Update static file serving and file() response functions to use new utility

* Tests...

* Change UTF-8 to utf-8 as is the convention. Fix the new tests.

* Moved from overly long test_request to test_static, even for the file() interface as it is related. Removed duplicate tests, clarified naming.

* Fix some broken tests

---------

Co-authored-by: Adam Hopkins <[email protected]>
* Upgrade tracerite to latest

* Update sanic/__main__.py

Co-authored-by: Copilot <[email protected]>

* Update tests to match new tracerite patterns

---------

Co-authored-by: Copilot <[email protected]>
* Upgrade tracerite to latest

* Update sanic/__main__.py

Co-authored-by: Copilot <[email protected]>

* Add better error catching for common startup issues

* Use errno.EADDRINUSE constant instead of hardcoded platform-specific value (#3106)

* Initial plan

* Replace hardcoded errno 98 with errno.EADDRINUSE constant

Co-authored-by: ahopkins <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: ahopkins <[email protected]>

* Make pretty

* Add CODECOV token

---------

Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: ahopkins <[email protected]>
* Add support for running tests with xdist

* Get coverage and tests running successfully with xdist

* Get coverage and tests running successfully with xdist

* Run base tests (not coverages) with xdist

* Cleanup test file ordering
* Move to 2-stage coverage check

* Update .github/workflows/coverage-upload.yml

Co-authored-by: Copilot <[email protected]>

* Update .github/workflows/coverage-upload.yml

Co-authored-by: Copilot <[email protected]>

* Update .github/workflows/coverage.yml

Co-authored-by: Copilot <[email protected]>

---------

Co-authored-by: Copilot <[email protected]>
* fixing bad term cleanup at exit

* Move logic to method

* Change to 2-stage coverage check

* Update upload workflow

---------

Co-authored-by: Adam Hopkins <[email protected]>
…ws (#3109)

* Bump dawidd6/action-download-artifact from 3 to 6 in /.github/workflows

Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 3 to 6.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](dawidd6/action-download-artifact@v3...v6)

---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
  dependency-version: '6'
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>

* Clear caplog before assertions and filter for sanic-specific errors to avoid capturing stray asyncio warnings from other tests.

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Adam Hopkins <[email protected]>
* Add daemon mode to Sanic CLI

* Simplify help docs in CLI

* Make pretty

* Update sanic/worker/daemon.py

Co-authored-by: Copilot <[email protected]>

* Update sanic/worker/daemon.py

Co-authored-by: Copilot <[email protected]>

* Fix daemon lockfile race condition during daemonization (#3111)

* Initial plan

* Fix race condition by acquiring lockfile before forking

Co-authored-by: ahopkins <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: ahopkins <[email protected]>

* Add explanatory comments to exception handlers in daemon lockfile cleanup (#3113)

* Initial plan

* Add explanatory comments to except OSError blocks in _release_lockfile

Co-authored-by: ahopkins <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: ahopkins <[email protected]>

* Improve test coverage

* Polish help displays

---------

Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: ahopkins <[email protected]>
* Remove v3.9 and add v3.14

* Update test with new version of tracerite header checks

* squash

* Use explicit loop on server shutdown

* Correct py3.14 issues
* Explicit symlink params for static files/dirs

* Fix symlink type detection for external symlink access control (#3118)

* Initial plan

* Fix symlink type detection to correctly distinguish file vs directory symlinks

Co-authored-by: ahopkins <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: ahopkins <[email protected]>

* Cleanup linting

---------

Co-authored-by: Copilot <[email protected]>
Co-authored-by: ahopkins <[email protected]>
* Respect LOG_EXTRA in all cases

* disable xdist on python 3.10 that seems to have a deadlock with uvloop
* Prepare docs for v25.12 release

* Update tests for new worker ready log line
Copilot AI review requested due to automatic review settings December 31, 2025 19:07
@ahopkins ahopkins requested review from a team as code owners December 31, 2025 19:07
@ahopkins ahopkins closed this Dec 31, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR deploys the v25.12 documentation release for Sanic, featuring a major version update from 24.12.0 to 25.12.0. The changes include dropping Python 3.8/3.9 support, adding Python 3.14 support, introducing daemon mode functionality, modernizing type annotations to use PEP 604 syntax (Union[X, Y] → X | Y), improving security for static file serving with symlink handling, and numerous bug fixes and improvements across the codebase.

Key changes:

  • Drop Python 3.8/3.9 support, add Python 3.14 support
  • Introduce daemon mode with full CLI support
  • Modernize type annotations throughout codebase
  • Add comprehensive symlink security for static file serving
  • Improve startup error handling and logging
  • Add new test coverage for tasks, daemon, and startup errors

Reviewed changes

Copilot reviewed 159 out of 160 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
sanic/version.py Version bump to 25.12.0
setup.py Updated Python version requirements (3.10+), added pytest-xdist/pytest-cov, updated tracerite dependency
tox.ini Removed py39 support, added py314, updated test configuration with parallel execution
sanic/worker/daemon.py New daemon mode implementation with PID/lock file management
sanic/startup/errors.py New startup error handling module
sanic/mixins/static.py Added symlink security controls for static file serving
sanic/handlers/directory.py Enhanced directory handler with symlink filtering
sanic/response/convenience.py Added guess_content_type function with charset handling
tests/test_daemon.py Comprehensive daemon mode test suite
tests/test_static_directory.py Extensive symlink security tests
Multiple files Type annotation modernization (Union →
Multiple test files Added xdist_group markers for parallel test execution

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


@classmethod
def generate_id(*_) -> Union[uuid.UUID, str, int]:
def generate_id(*_) -> uuid.UUID | str | int:
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Class methods or methods of a type deriving from type should have 'cls' as their first parameter.

Copilot uses AI. Check for mistakes.
"""


class Config(dict, metaclass=DescriptorMeta):
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The class 'Config' does not override 'eq', but adds the new attribute defaults.
The class 'Config' does not override 'eq', but adds the new attribute _converters.
The class 'Config' does not override 'eq', but adds the new attribute KEEP_ALIVE.
The class 'Config' does not override 'eq', but adds the new attribute _init.
The class 'Config' does not override 'eq', but adds the new attribute LOCAL_CERT_CREATOR.

Copilot uses AI. Check for mistakes.
return
except asyncio.CancelledError:
...
except BaseException:
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except block directly handles BaseException.

Copilot uses AI. Check for mistakes.
if lockfile.exists():
try:
lockfile.unlink()
except OSError:
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'except' clause does nothing but pass and there is no explanatory comment.

Copilot uses AI. Check for mistakes.
except OSError as e:
try:
os.close(fd)
except OSError:
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'except' clause does nothing but pass and there is no explanatory comment.

Copilot uses AI. Check for mistakes.
self.set_state(ProcessState.TERMINATED, force=True)
try:
self.set_state(ProcessState.TERMINATED, force=True)
except (BrokenPipeError, ConnectionResetError, EOFError):
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'except' clause does nothing but pass and there is no explanatory comment.

Copilot uses AI. Check for mistakes.
for _signal in [SIGINT, SIGTERM]:
try:
loop.remove_signal_handler(_signal)
except (NotImplementedError, OSError):
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'except' clause does nothing but pass and there is no explanatory comment.

Copilot uses AI. Check for mistakes.
app.set_serving(False)
try:
app.set_serving(False)
except (BrokenPipeError, ConnectionResetError, EOFError):
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'except' clause does nothing but pass and there is no explanatory comment.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.