v2.3.0
Important
This release, like the previous one, includes some breaking changes to the public code API of certain classes, hence the bump in version from 2.2.0 to 2.3.0. The breaking changes aim to improve the user experience (UX) when using Controllers and registering routes. In particular, they address issues #511 and #540.The scope of the breaking changes is relatively minor, as they affect built-in features that are likely not commonly modified: removes the prepare_controllers and the get_controller_handler_pattern from the Application class, transferring them to a dedicated ControllersManager class. Additionally, the Router class has been refactored to work consistently for request handlers defined as functions and those defined as Controllers' methods.
The Router now allows registering all request handlers without evaluating them immediately, postponing duplicate checks, and introduces an apply_routes method to make routes effective upon application startup. This change is necessary to support using the same functions for both functions and methods, addressing issue #540, improving UX, and eliminating potential confusion caused by having two sets of decorators (get, post, put, etc.) that behave differently. While the two sets of decorators are still maintained to minimize the impact of breaking changes, the framework now supports using them interchangeably.
While breaking changes may cause inconvenience for some users, I believe the new features in this release represent a significant step forward. Now Controllers support routes inheritance! This is an important feature that was missing so far in the web framework.
- Fix #511. Add support
for inheriting endpoints from parent controller classes, when subclassing
controllers. Example:
from blacksheep import Application
from blacksheep.server.controllers import Controller, abstract, get
app = Application()
@abstract()
class BaseController(Controller):
@get("/hello-world")
def index(self):
# Note: the route /hello-world itself will not be registered in the router,
# because this class is decorated with @abstract()
return self.text(f"Hello, World! {self.__class__.__name__}")
class ControllerOne(BaseController):
route = "/one"
# /one/hello-world
class ControllerTwo(BaseController):
route = "/two"
# /two/hello-world
@get("/specific-route") # /two/specific-route
def specific_route(self):
return self.text("This is a specific route in ControllerTwo")- Add a new
@abstract()decorator that can be applied to controller classes to skip
routes defined in them; so that only their subclasses will have the routes
registered, prefixed by their own prefix). - BREAKING CHANGE. Refactor the
Applicationcode to encapsulate in a
dedicated class functions that prepare controllers' routes. - BREAKING CHANGE. Refactor the
Routerclass to handle consistently
request handlers defined using functions and controllers' class methods
(refer to the note above for more information). - Fix #498: Buffer reuse
and race condition inclient.IncomingContent.stream(), by @ohait. - Fix #365, adding support
for Pydantic's@validate_calland@validate_argumentsand other wrappers
applied to functions before they are configured as request handlers.
Contribution by @aldem, who reported the issue and provided the solution. - To better support
@validate_call, configure automatically a default
exception handler forpydantic.ValidationErrorwhen Pydantic is installed. - Fix #550. Ensure that
all generated$refvalues contain only allowed characters. - Fix #484. Improve the
implementation of Server-Sent Events (SSE) to support sending data in any
shape, and not only as JSON. Add aTextServerSentEventclass to send plain
text to the client (this still escapes new lines!). - Modify the
is_stoppingfunction to emit a warning instead of raising a
RuntimeErrorif the env variableAPP_SIGNAL_HANDLERis not set to a
truthy value. - Improve the error message of the
RouteDuplicateclass. - Fix #38 for notations that
are available since Python 3.9 (e.g.list[str],set[str],tuple[str]). - Fix a regression
introduced in2.2.0that would prevent customHTTPExceptionhandlers from
being used when the user configured a catch-allExceptionhandler
(this practice is not recommended; let the framework handle unhandled exceptions
usingInternalServerErrorexception handler). - Add a
ConflictHTTPExceptiontoblacksheep.exceptionsfor409
response code. - Improve the test code to make it less verbose.