diff --git a/guide/config/en/general.yaml b/guide/config/en/general.yaml index 19afeacea6..0b074eff74 100644 --- a/guide/config/en/general.yaml +++ b/guide/config/en/general.yaml @@ -1 +1 @@ -current_version: "23.6" +current_version: "24.6" diff --git a/guide/config/en/sidebar.yaml b/guide/config/en/sidebar.yaml index f10b3f1a28..000c4beafc 100644 --- a/guide/config/en/sidebar.yaml +++ b/guide/config/en/sidebar.yaml @@ -143,6 +143,10 @@ root: path: plugins/sanic-testing/clients.html - label: Release Notes items: + - label: "2024" + items: + - label: Sanic 24.6 + path: release-notes/2024/v24.6.html - label: "2023" items: - label: Sanic 23.12 diff --git a/guide/content/en/guide/basics/listeners.md b/guide/content/en/guide/basics/listeners.md index 3e600ad255..84fc20c9e1 100644 --- a/guide/content/en/guide/basics/listeners.md +++ b/guide/content/en/guide/basics/listeners.md @@ -238,9 +238,7 @@ Given the following setup, we should expect to see this in the console if we run ### Priority -.. new:: v23.12 - - In v23.12, the `priority` keyword argument was added to listeners. This allows for fine-tuning the order of execution of listeners. The default priority is `0`. Listeners with a higher priority will be executed first. Listeners with the same priority will be executed in the order they were registered. Furthermore, listeners attached to the `app` instance will be executed before listeners attached to a `Blueprint` instance. +In v23.12, the `priority` keyword argument was added to listeners. This allows for fine-tuning the order of execution of listeners. The default priority is `0`. Listeners with a higher priority will be executed first. Listeners with the same priority will be executed in the order they were registered. Furthermore, listeners attached to the `app` instance will be executed before listeners attached to a `Blueprint` instance. Overall the rules for deciding the order of execution are as follows: diff --git a/guide/content/en/guide/running/development.md b/guide/content/en/guide/running/development.md index f0fcda8a46..09d2415392 100644 --- a/guide/content/en/guide/running/development.md +++ b/guide/content/en/guide/running/development.md @@ -70,9 +70,7 @@ sanic server:app --host=0.0.0.0 --port=1234 --debug ## Development REPL -.. new:: v23.12 - - The Sanic CLI comes with a REPL (aka "read-eval-print loop") that can be used to interact with your application. This is useful for debugging and testing. A REPL is the interactive shell that you get when you run `python` without any arguments. +The Sanic CLI comes with a REPL (aka "read-eval-print loop") that can be used to interact with your application. This is useful for debugging and testing. A REPL is the interactive shell that you get when you run `python` without any arguments. .. column:: @@ -202,7 +200,7 @@ Or, by destructuring the tuple: .. column:: - If you would like to be in debug mode **and** have the Automatic Reloader running, you can pass `dev=True`. This is equivalent to **debug + auto reload**. + If you would like to be in debug mode **and** have the Automatic Reloader running, you can pass `dev=True`. This is equivalent to **debug + auto reload + REPL**. *Added in v22.3* @@ -216,11 +214,10 @@ Or, by destructuring the tuple: sanic path.to:app -d ``` -.. new:: v23.12 - - Added to the `--dev` flag in v23.12 is the ability to start a REPL. See the [Development REPL](./development.md#development-repl) section for more information. +Added to the `--dev` flag in v23.12 is the ability to start a REPL. See the [Development REPL](./development.md#development-repl) section for more information. - As of v23.12, the `--dev` flag is roughly equivalent to `--debug --reload --repl`. Using `--dev` will require you to expressly begin the REPL by hitting "ENTER", while passing the `--repl` flag explicitly starts it. +As of v23.12, the `--dev` flag is roughly equivalent to `--debug --reload --repl`. Using `--dev` will require you to expressly begin the REPL by hitting "ENTER", while passing the `--repl` flag explicitly starts it. +Before v23.12, the `--dev` flag is more similar to `--debug --reload`. .. column:: diff --git a/guide/content/en/guide/running/manager.md b/guide/content/en/guide/running/manager.md index c021170ce6..021369f41e 100644 --- a/guide/content/en/guide/running/manager.md +++ b/guide/content/en/guide/running/manager.md @@ -360,15 +360,12 @@ To run a managed custom process on Sanic, you must create a callable. If that pr ### Tracked v. untracked processes -.. new:: v23.12 +Out of the box, Sanic will track the state of all processes. This means that you can access the state of the process from the [multiplexer](./manager#access-to-the-multiplexer) object, or from the [Inspector](./manager#inspector). - Out of the box, Sanic will track the state of all processes. This means that you can access the state of the process from the [multiplexer](./manager#access-to-the-multiplexer) object, or from the [Inspector](./manager#inspector). +See [worker state](./manager#worker-state) for more information. - See [worker state](./manager#worker-state) for more information. +Sometimes it is helpful to run background processes that are not long-running. You run them once until completion and then they exit. Upon completion, they will either be in `FAILED` or `COMPLETED` state. - Sometimes it is helpful to run background processes that are not long-running. You run them once until completion and then they exit. Upon completion, they will either be in `FAILED` or `COMPLETED` state. - - .. column:: When you are running a non-long-running process, you can opt out of tracking it by setting `tracked=False` in the `manage` method. This means that upon completion of the process it will be removed from the list of tracked processes. You will only be able to check the state of the process while it is running. @@ -390,9 +387,7 @@ To run a managed custom process on Sanic, you must create a callable. If that pr ### Restartable custom processes -.. new:: v23.12 - - A custom process that is transient will **always** be restartable. That means the auto-restart will work as expected. However, what if you want to be able to *manually* restart a process, but not have it be restarted by the auto-reloader? +A custom process that is transient will **always** be restartable. That means the auto-restart will work as expected. However, what if you want to be able to *manually* restart a process, but not have it be restarted by the auto-reloader? .. column:: @@ -428,9 +423,7 @@ To run a managed custom process on Sanic, you must create a callable. If that pr ### On the fly process management -.. new:: v23.12 - - Custom processes are usually added in the `main_process_ready` listener. However, there may be times when you want to add a process after the application has started. For example, you may want to add a process from a request handler. The multiplexer provides a method for doing this. +Custom processes are usually added in the `main_process_ready` listener. However, there may be times when you want to add a process after the application has started. For example, you may want to add a process from a request handler. The multiplexer provides a method for doing this. .. column:: diff --git a/guide/content/en/release-notes/changelog.md b/guide/content/en/release-notes/changelog.md index 797e8603fa..bbf3192ece 100644 --- a/guide/content/en/release-notes/changelog.md +++ b/guide/content/en/release-notes/changelog.md @@ -8,10 +8,47 @@ content_class: changelog πŸ”· In support LTS release -## Version 23.12.0 πŸ”ΆπŸ”· +## Version 24.6.0 πŸ”Ά _Current version_ +### Features +- [#2838](https://github.com/sanic-org/sanic/pull/2838) Simplify request cookies `getlist` +- [#2850](https://github.com/sanic-org/sanic/pull/2850) Unix sockets can now use `pathlib.Path` +- [#2931](https://github.com/sanic-org/sanic/pull/2931) [#2958](https://github.com/sanic-org/sanic/pull/2958) Logging improvements +- [#2947](https://github.com/sanic-org/sanic/pull/2947) Make the .message field on exceptions non-empty +- [#2961](https://github.com/sanic-org/sanic/pull/2961) [#2964](https://github.com/sanic-org/sanic/pull/2964) Allow for custom name generation + +### Bugfixes +- [#2919](https://github.com/sanic-org/sanic/pull/2919) Remove deprecation notice in websockets +- [#2937](https://github.com/sanic-org/sanic/pull/2937) Resolve response streaming error when in ASGI mode +- [#2959](https://github.com/sanic-org/sanic/pull/2959) Resolve Python 3.12 deprecation notic +- [#2960](https://github.com/sanic-org/sanic/pull/2960) Ensure proper intent for noisy exceptions +- [#2970](https://github.com/sanic-org/sanic/pull/2970) [#2978](https://github.com/sanic-org/sanic/pull/2978) Fix missing dependencies for 3.12 +- [#2971](https://github.com/sanic-org/sanic/pull/2971) Fix middleware exceptions on Not Found routes with error in middleware +- [#2973](https://github.com/sanic-org/sanic/pull/2973) Resolve cheduling logic for `transport.close` and `transport.abort` +- [#2976](https://github.com/sanic-org/sanic/pull/2976) Fix deleting a cookie that was created with `secure=False` +- [#2979](https://github.com/sanic-org/sanic/pull/2979) Throw error on bad body length +- [#2980](https://github.com/sanic-org/sanic/pull/2980) Throw error on bad body encoding + +### Deprecations and Removals +- [#2899](https://github.com/sanic-org/sanic/pull/2899) Remove erroneous line from REPL impacting environments without HTTPX +- [#2962](https://github.com/sanic-org/sanic/pull/2962) Merge entity header removal + +### Developer infrastructure +- [#2882](https://github.com/sanic-org/sanic/pull/2882) [#2896](https://github.com/sanic-org/sanic/pull/2896) Apply dynamic port fixture for improving tests with port selection +- [#2887](https://github.com/sanic-org/sanic/pull/2887) Updates to docker image builds +- [#2932](https://github.com/sanic-org/sanic/pull/2932) Cleanup code base with Ruff + +### Improved Documentation +- [#2924](https://github.com/sanic-org/sanic/pull/2924) Cleanup markdown on html5tagger page +- [#2930](https://github.com/sanic-org/sanic/pull/2930) Cleanup typo on Sanic Extensions README.md +- [#2934](https://github.com/sanic-org/sanic/pull/2934) Add more context to the health check documents +- [#2936](https://github.com/sanic-org/sanic/pull/2936) Improve worker manager documentation +- [#2955](https://github.com/sanic-org/sanic/pull/2955) Fixed wrong formatting in `request.md` + +## Version 23.12.0 πŸ”· + ### Features - [#2775](https://github.com/sanic-org/sanic/pull/2775) Start and restart arbitrary processes - [#2811](https://github.com/sanic-org/sanic/pull/2811) Cleaner process management in shutdown @@ -33,8 +70,6 @@ _Current version_ ### Bugfixes - [#2803](https://github.com/sanic-org/sanic/pull/2803) Fix MOTD display for extra data -### Deprecations and Removals - ### Developer infrastructure - [#2796](https://github.com/sanic-org/sanic/pull/2796) Refactor unit test cases - [#2801](https://github.com/sanic-org/sanic/pull/2801) Fix `test_fast` when there is only one CPU diff --git a/guide/public/assets/images/logging-dev.png b/guide/public/assets/images/logging-dev.png new file mode 100644 index 0000000000..038eb81790 Binary files /dev/null and b/guide/public/assets/images/logging-dev.png differ diff --git a/guide/public/assets/images/logging-prod.png b/guide/public/assets/images/logging-prod.png new file mode 100644 index 0000000000..76457c49f3 Binary files /dev/null and b/guide/public/assets/images/logging-prod.png differ diff --git a/guide/public/assets/style.css b/guide/public/assets/style.css index 36b3952791..d72fc3facf 100644 --- a/guide/public/assets/style.css +++ b/guide/public/assets/style.css @@ -12598,7 +12598,18 @@ a.has-text-danger-dark:hover, a.has-text-danger-dark:focus { .c1 { color: #4a4a4a; } .introduction-table .table tbody tr:last-child td { - border-bottom-width: 1px; } } + border-bottom-width: 1px; } + ::-webkit-scrollbar { + width: 12px; + height: 12px; } + ::-webkit-scrollbar-track { + background: #242424; } + ::-webkit-scrollbar-thumb { + background: #121212; + border-radius: 6px; + border: 3px solid #242424; } + ::-webkit-scrollbar-thumb:hover { + background: #0a0a0a; } } .burger { display: none; @@ -13107,6 +13118,15 @@ h3 + .code-block { .changelog .ol .li, .changelog .ol .list-item, .changelog .ul .li, .changelog .ul .list-item, .changelog .list .li, .changelog .list .list-item { padding: 0; } +.sponsors { + display: flex; + flex-wrap: wrap; + justify-content: center; + text-align: center; + padding: 0.25rem 0; } + .sponsors .button { + margin-left: 1rem; } + @media screen and (min-width: 769px) { .hero.is-large .hero-body { padding: 18rem 6rem 3rem; } } diff --git a/guide/style/elements.scss b/guide/style/elements.scss index dc2d4e9f70..28368fddad 100644 --- a/guide/style/elements.scss +++ b/guide/style/elements.scss @@ -387,3 +387,12 @@ h3 + .code-block { margin-top: 1rem; } .li, .list-item { padding: 0; } } } + +.sponsors { + display: flex; + flex-wrap: wrap; + justify-content: center; + text-align: center; + padding: 0.25rem 0; + .button { margin-left: 1rem; } +} diff --git a/guide/style/theme.scss b/guide/style/theme.scss index 6ee2503d0a..0e6acc7ff4 100644 --- a/guide/style/theme.scss +++ b/guide/style/theme.scss @@ -62,4 +62,14 @@ $background-image-size: 270px; .nc { color: #{$yellow}; } .c1 { color: #{$grey-dark}; } .introduction-table .table tbody tr:last-child td { border-bottom-width: 1px; } + + $scrollbar-width: 12px; + ::-webkit-scrollbar { width: $scrollbar-width; height: $scrollbar-width; } + ::-webkit-scrollbar-track { background: #{$black-ter}; } + ::-webkit-scrollbar-thumb { + background: #{$black-bis}; + border-radius: 6px; + border: 3px solid #{$black-ter}; + } + ::-webkit-scrollbar-thumb:hover { background: #{$black}; } } diff --git a/guide/webapp/display/layouts/elements/sidebar.py b/guide/webapp/display/layouts/elements/sidebar.py index dbf91ec567..6686eddf83 100644 --- a/guide/webapp/display/layouts/elements/sidebar.py +++ b/guide/webapp/display/layouts/elements/sidebar.py @@ -36,6 +36,20 @@ def _menu_items(request: Request) -> list[Builder]: .a("sanicbook.com", href="https://sanicbook.com", target="_blank") .br.img(src="https://sanicbook.com/images/SanicCoverFinal.png"), E.br.small("Book proceeds fund our journey"), + E.hr(), + E.p("Secure, auto-document, and monetize your Sanic API with:").a( + E.img( + src="/assets/images/zuplo.svg", + alt=( + "Zuplo - Secure, auto-document, " + "and monetize your Sanic API" + ), + style="width: 90%;", + ), + href="https://zuplo.com", + target="_blank", + rel="nofollow noopener noreferrer", + ), ] diff --git a/guide/webapp/display/layouts/home.py b/guide/webapp/display/layouts/home.py index bf937d2b19..1564981b94 100644 --- a/guide/webapp/display/layouts/home.py +++ b/guide/webapp/display/layouts/home.py @@ -16,6 +16,7 @@ class HomeLayout(BaseLayout): def layout( self, request: Request, full: bool = True ) -> Generator[None, None, None]: + self._sponsors() self._hero(request.ctx.language) with self.builder.div(class_="home container"): yield @@ -52,6 +53,19 @@ def _do_buttons(self, language: str) -> Builder: ) return builder + def _sponsors(self) -> None: + with self.builder.section(class_="sponsors"): + self.builder( + "Secure, auto-document, and monetize " + "your Sanic API with Zuplo", + E.a( + "Start free", + href="https://zuplo.com", + target="_blank", + class_="button is-primary is-small", + ), + ) + def _footer(self, request: Request) -> None: do_footer( self.builder, diff --git a/sanic/__version__.py b/sanic/__version__.py index ba95260d83..a7f5098aa0 100644 --- a/sanic/__version__.py +++ b/sanic/__version__.py @@ -1 +1 @@ -__version__ = "24.3.0.dev" +__version__ = "24.6.0" diff --git a/sanic/cookies/request.py b/sanic/cookies/request.py index ca8ae0691a..3b8b3f15e0 100644 --- a/sanic/cookies/request.py +++ b/sanic/cookies/request.py @@ -128,13 +128,13 @@ class CookieRequestParameters(RequestParameters): def __getitem__(self, key: str) -> Optional[str]: deprecation( f"You are accessing cookie key '{key}', which is currently in " - "compat mode returning a single cookie value. Starting in v24.3 " + "compat mode returning a single cookie value. Starting in v24.9 " "accessing a cookie value like this will return a list of values. " "To avoid this behavior and continue accessing a single value, " f"please upgrade from request.cookies['{key}'] to " f"request.cookies.get('{key}'). See more details: " "https://sanic.dev/en/guide/release-notes/v23.3.html#request-cookies", # noqa - 24.3, + 24.9, ) try: value = self._get_prefixed_cookie(key) diff --git a/sanic/cookies/response.py b/sanic/cookies/response.py index e84a24d820..1c710d20e0 100644 --- a/sanic/cookies/response.py +++ b/sanic/cookies/response.py @@ -51,7 +51,7 @@ def _quote(str): # no cov _is_legal_key = re.compile("[%s]+" % re.escape(LEGAL_CHARS)).fullmatch -# In v24.3, we should remove this as being a subclass of dict +# In v24.9, we should remove this as being a subclass of dict class CookieJar(dict): """A container to manipulate cookies. @@ -111,82 +111,82 @@ def __getitem__(self, key: str) -> Cookie: def __iter__(self): # no cov deprecation( "Iterating over the CookieJar has been deprecated and will be " - "removed in v24.3. To learn more, please see: " + "removed in v24.9. To learn more, please see: " "https://sanic.dev/en/guide/release-notes/v23.3.html#response-cookies", # noqa - 24.3, + 24.9, ) return super().__iter__() def keys(self): # no cov - """Deprecated in v24.3""" + """Deprecated in v24.9""" deprecation( "Accessing CookieJar.keys() has been deprecated and will be " - "removed in v24.3. To learn more, please see: " + "removed in v24.9. To learn more, please see: " "https://sanic.dev/en/guide/release-notes/v23.3.html#response-cookies", # noqa - 24.3, + 24.9, ) return super().keys() def values(self): # no cov - """Deprecated in v24.3""" + """Deprecated in v24.9""" deprecation( "Accessing CookieJar.values() has been deprecated and will be " - "removed in v24.3. To learn more, please see: " + "removed in v24.9. To learn more, please see: " "https://sanic.dev/en/guide/release-notes/v23.3.html#response-cookies", # noqa - 24.3, + 24.9, ) return super().values() def items(self): # no cov - """Deprecated in v24.3""" + """Deprecated in v24.9""" deprecation( "Accessing CookieJar.items() has been deprecated and will be " - "removed in v24.3. To learn more, please see: " + "removed in v24.9. To learn more, please see: " "https://sanic.dev/en/guide/release-notes/v23.3.html#response-cookies", # noqa - 24.3, + 24.9, ) return super().items() def get(self, *args, **kwargs): # no cov - """Deprecated in v24.3""" + """Deprecated in v24.9""" deprecation( "Accessing cookies from the CookieJar using get is deprecated " - "and will be removed in v24.3. You should instead use the " + "and will be removed in v24.9. You should instead use the " "cookies.get_cookie method. To learn more, please see: " "https://sanic.dev/en/guide/release-notes/v23.3.html#response-cookies", # noqa - 24.3, + 24.9, ) return super().get(*args, **kwargs) def pop(self, key, *args, **kwargs): # no cov - """Deprecated in v24.3""" + """Deprecated in v24.9""" deprecation( "Using CookieJar.pop() has been deprecated and will be " - "removed in v24.3. To learn more, please see: " + "removed in v24.9. To learn more, please see: " "https://sanic.dev/en/guide/release-notes/v23.3.html#response-cookies", # noqa - 24.3, + 24.9, ) self.delete(key) return super().pop(key, *args, **kwargs) @property def header_key(self): # no cov - """Deprecated in v24.3""" + """Deprecated in v24.9""" deprecation( "The CookieJar.header_key property has been deprecated and will " - "be removed in version 24.3. Use CookieJar.HEADER_KEY. ", - 24.3, + "be removed in version 24.9. Use CookieJar.HEADER_KEY. ", + 24.9, ) return CookieJar.HEADER_KEY @property def cookie_headers(self) -> Dict[str, str]: # no cov - """Deprecated in v24.3""" + """Deprecated in v24.9""" deprecation( "The CookieJar.coookie_headers property has been deprecated " - "and will be removed in version 24.3. If you need to check if a " + "and will be removed in version 24.9. If you need to check if a " "particular cookie key has been set, use CookieJar.has_cookie.", - 24.3, + 24.9, ) return {key: self.header_key for key in self} @@ -352,7 +352,7 @@ def add_cookie( ) self.headers.add(self.HEADER_KEY, cookie) - # This should be removed in v24.3 + # This should be removed in v24.9 super().__setitem__(key, cookie) return cookie @@ -413,7 +413,7 @@ def delete_cookie( self.headers.add(self.HEADER_KEY, cookie) elif existing_cookie is None: existing_cookie = cookie - # This should be removed in v24.3 + # This should be removed in v24.9 try: super().__delitem__(key) except KeyError: @@ -449,7 +449,7 @@ def delete_cookie( ) -# In v24.3, we should remove this as being a subclass of dict +# In v24.9, we should remove this as being a subclass of dict # Instead, it should be an object with __slots__ # All of the current property accessors should be removed in favor # of actual slotted properties. @@ -583,14 +583,14 @@ def __init__( def __setitem__(self, key, value): deprecation( "Setting values on a Cookie object as a dict has been deprecated. " - "This feature will be removed in v24.3. You should instead set " + "This feature will be removed in v24.9. You should instead set " f"values on cookies as object properties: cookie.{key}=... ", - 24.3, + 24.9, ) self._set_value(key, value) # This is a temporary method for backwards compat and should be removed - # in v24.3 when this is no longer a dict + # in v24.9 when this is no longer a dict def _set_value(self, key: str, value: Any) -> None: if key not in self._keys: raise KeyError("Unknown cookie property: %s=%s" % (key, value)) @@ -619,7 +619,7 @@ def encode(self, encoding: str) -> bytes: the cookies. .. warning:: - Direct encoding of a Cookie object has been deprecated and will be removed in v24.3. + Direct encoding of a Cookie object has been deprecated and will be removed in v24.9. Args: encoding (str): The encoding type to be used. @@ -629,8 +629,8 @@ def encode(self, encoding: str) -> bytes: """ # noqa: E501 deprecation( "Direct encoding of a Cookie object has been deprecated and will " - "be removed in v24.3.", - 24.3, + "be removed in v24.9.", + 24.9, ) return str(self).encode(encoding) diff --git a/sanic/request/types.py b/sanic/request/types.py index 0d3cb31958..808f92f099 100644 --- a/sanic/request/types.py +++ b/sanic/request/types.py @@ -81,9 +81,12 @@ sanic_type = TypeVar( "sanic_type", bound=Sanic, default=Sanic[Config, SimpleNamespace] ) + ctx_type = TypeVar( + "ctx_type", bound=SimpleNamespace, default=SimpleNamespace + ) else: sanic_type = TypeVar("sanic_type") -ctx_type = TypeVar("ctx_type", default=SimpleNamespace) + ctx_type = TypeVar("ctx_type") class Request(Generic[sanic_type, ctx_type]):