Require stricter object names (#2146)

This commit is contained in:
Adam Hopkins 2021-05-30 15:37:44 +03:00 committed by GitHub
parent 72a745bfd5
commit ba374139f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 80 additions and 15 deletions

View File

@ -135,13 +135,8 @@ class Sanic(BaseSanic):
register: Optional[bool] = None,
dumps: Optional[Callable[..., str]] = None,
) -> None:
super().__init__()
super().__init__(name=name)
if name is None:
raise SanicException(
"Sanic instance cannot be unnamed. "
"Please use Sanic(name='your_application_name') instead.",
)
# logging
if configure_logging:
logging.config.dictConfig(log_config or LOGGING_CONFIG_DEFAULTS)
@ -161,7 +156,6 @@ class Sanic(BaseSanic):
self.is_running = False
self.is_stopping = False
self.listeners: Dict[str, List[ListenerType]] = defaultdict(list)
self.name = name
self.named_request_middleware: Dict[str, Deque[MiddlewareType]] = {}
self.named_response_middleware: Dict[str, Deque[MiddlewareType]] = {}
self.request_class = request_class

View File

@ -1,6 +1,9 @@
import re
from typing import Any, Tuple
from warnings import warn
from sanic.exceptions import SanicException
from sanic.mixins.exceptions import ExceptionMixin
from sanic.mixins.listeners import ListenerMixin
from sanic.mixins.middleware import MiddlewareMixin
@ -8,6 +11,9 @@ from sanic.mixins.routes import RouteMixin
from sanic.mixins.signals import SignalMixin
VALID_NAME = re.compile(r"^[a-zA-Z][a-zA-Z0-9_\-]*$")
class BaseSanic(
RouteMixin,
MiddlewareMixin,
@ -17,7 +23,25 @@ class BaseSanic(
):
__fake_slots__: Tuple[str, ...]
def __init__(self, *args, **kwargs) -> None:
def __init__(self, name: str = None, *args, **kwargs) -> None:
class_name = self.__class__.__name__
if name is None:
raise SanicException(
f"{class_name} instance cannot be unnamed. "
"Please use Sanic(name='your_application_name') instead.",
)
if not VALID_NAME.match(name):
warn(
f"{class_name} instance named '{name}' uses a format that is"
f"deprecated. Starting in version 21.12, {class_name} objects "
"be named only using alphanumeric characters, _, or -.",
DeprecationWarning,
)
self.name = name
for base in BaseSanic.__bases__:
base.__init__(self, *args, **kwargs) # type: ignore
@ -36,6 +60,7 @@ class BaseSanic(
f"Setting variables on {self.__class__.__name__} instances is "
"deprecated and will be removed in version 21.9. You should "
f"change your {self.__class__.__name__} instance to use "
f"instance.ctx.{name} instead."
f"instance.ctx.{name} instead.",
DeprecationWarning,
)
super().__setattr__(name, value)

View File

@ -62,19 +62,20 @@ class Blueprint(BaseSanic):
"strict_slashes",
"url_prefix",
"version",
"version_prefix",
"websocket_routes",
)
def __init__(
self,
name: str,
name: str = None,
url_prefix: Optional[str] = None,
host: Optional[str] = None,
version: Optional[Union[int, str, float]] = None,
strict_slashes: Optional[bool] = None,
version_prefix: str = "/v",
):
super().__init__()
super().__init__(name=name)
self._apps: Set[Sanic] = set()
self.ctx = SimpleNamespace()
@ -82,7 +83,6 @@ class Blueprint(BaseSanic):
self.host = host
self.listeners: Dict[str, List[ListenerType]] = {}
self.middlewares: List[MiddlewareType] = []
self.name = name
self.routes: List[Route] = []
self.statics: List[RouteHandler] = []
self.strict_slashes = strict_slashes

View File

@ -26,10 +26,11 @@ from sanic.views import CompositionView
class RouteMixin:
name: str
def __init__(self, *args, **kwargs) -> None:
self._future_routes: Set[FutureRoute] = set()
self._future_statics: Set[FutureStatic] = set()
self.name = ""
self.strict_slashes: Optional[bool] = False
def _apply_route(self, route: FutureRoute) -> List[Route]:

View File

@ -389,7 +389,7 @@ def test_app_no_registry_env():
def test_app_set_attribute_warning(app):
with pytest.warns(UserWarning) as record:
with pytest.warns(DeprecationWarning) as record:
app.foo = 1
assert len(record) == 1

View File

@ -41,3 +41,48 @@ def test_bp_repr_with_values(bp):
'Blueprint(name="my_bp", url_prefix="/foo", host="example.com", '
"version=3, strict_slashes=True)"
)
@pytest.mark.parametrize(
"name",
(
"something",
"some-thing",
"some_thing",
"Something",
"SomeThing",
"Some-Thing",
"Some_Thing",
"SomeThing123",
"something123",
"some-thing123",
"some_thing123",
"some-Thing123",
"some_Thing123",
),
)
def test_names_okay(name):
app = Sanic(name)
bp = Blueprint(name)
assert app.name == name
assert bp.name == name
@pytest.mark.parametrize(
"name",
(
"123something",
"some thing",
"something!",
),
)
def test_names_not_okay(name):
with pytest.warns(DeprecationWarning):
app = Sanic(name)
with pytest.warns(DeprecationWarning):
bp = Blueprint(name)
assert app.name == name
assert bp.name == name

View File

@ -1028,7 +1028,7 @@ def test_blueprint_registered_multiple_apps():
def test_bp_set_attribute_warning():
bp = Blueprint("bp")
with pytest.warns(UserWarning) as record:
with pytest.warns(DeprecationWarning) as record:
bp.foo = 1
assert len(record) == 1