Representing views and patterns¶
A big part of this library is extracting information about the Django project for the checks that are performed to make sure that details about how to get this information does not affect what checks are made.
Every time a request comes into a Django server, that request is routed to
a view via the urlpatterns defined by the project, such that the view
gets given that request object and any information that is extracted from the
request by that urlpattern.
So we need objects that represent: * What patterns exist * What view they call out to * What information gets extracted from the url pattern * What information the view accepts and requires
These objects can be split into two groups, objects representing the views, and objects representing the patterns.
Django views¶
-
class django_consistency_enforcer.urls.FunctionArg(name: str, required: bool, keyword_only: bool, annotation: object, is_self: bool =
attr_dict['is_self'].default, is_variable_keywords: bool =attr_dict['is_variable_keywords'].default, is_variable_positional: bool =attr_dict['is_variable_positional'].default)¶ Holds onto the information for a single argument on a django view function/method.
- annotation : object¶
The annotation associated with this argument
- is_self : bool¶
Whether this argument represents the instance passed into a method (idiomatically, the self argument)
- is_variable_keywords : bool¶
Whether this argument is a **kwargs
- is_variable_positional : bool¶
Whether this argument is a *args
- keyword_only : bool¶
Whether this argument can only be passed in as a keyword
- matches(annotation: object) bool¶
Returns whether the annotation on the argument matches some specific annotation.
Takes into account:
Matches if this argument is typed as Any
Matches if this argument is **kwargs: object
Union types on both this arg and the provided annotation
- name : str¶
The name of the argument
- required : bool¶
Whether python will fail if this argument is not passed into the function
-
class django_consistency_enforcer.urls.Function(name: str, module: str, function_args: Sequence[FunctionArg], allows_arbitrary: bool, view_class: type | None =
attr_dict['view_class'].default, defined_on: type | None =attr_dict['defined_on'].default)¶ Holds onto the information to a specific django function/method.
- allows_arbitrary : bool¶
Whether there is a **kwargs: object or **kwargs: Any
- defined_on : type | None¶
The specific class this function comes from
(may be different to view_class if defined on a parent)
-
display(*, indent: str =
' ') str¶ Return a string representation of the information held by this object.
Will be a multi line string of one line per specific information, with the specified indent. Does not include function args.
-
classmethod from_callback(callback: Callable[[...], object], view_class: type | None =
None) Self¶ Return an instance of this class provided some function and the view class it was found on if it’s a method.
Will attempt to resolve any stringified annotations and do things like work out which class in the MRO the function is defined on if it’s a method.
Will also find any **kwargs: Unpack[…] and treat those as if they were defined as individual keyword arguments.
- function_args : Sequence[FunctionArg]¶
The arguments to this function
- module : str¶
The import path to the module the function is defined in
- name : str¶
The name of the function
- view_class : type | None¶
The class this function is defined on if it’s a method
- class django_consistency_enforcer.urls.DispatchFunction(function: Function, positional: Sequence[tuple[str, object]])¶
This represents a
Functionthat is used as by django for dispatching a request. Essentially it proxies aFunctionand also includes an understanding of any required positional arguments.- property allows_arbitrary : bool¶
Proxy allows_arbitrary from the function
- property defined_on : type | None¶
Proxy defined_on from the function
-
classmethod from_callback(callback: Callable[[...], object], view_class: type | None =
None, *, positional: Sequence[tuple[str, object]]) Self¶ Create an instance given some callback, the view it is found on if it’s a method, and the positional arguments that are considered required.
- property function_args : Sequence[FunctionArg]¶
Proxy function_args from the function
- property module : str¶
Proxy module from the function
- property name : str¶
Proxy name from the function
- positional : Sequence[tuple[str, object]]¶
Any required arguments as a tuple of (name, annotation) that is expected of this function
- property view_class : type | None¶
Proxy view_class from the function
- class django_consistency_enforcer.urls.Where(name: str, regex: str, module: str, namespace: str)¶
Used to say where an error with a url pattern can be found
-
display(*, indent: str =
' ', display_regex: bool =True) str¶ Return a string representing this location.
Essentially a string with each property on it’s own line indented the amount as specified.
- classmethod empty() Self¶
Used to construct an instance where all the values are empty.
Useful in tests especially to create an instance of this class where we don’t need to worry about the details it’s actually representing.
-
classmethod from_resolver(resolver: URLResolver, *, regex: str, name: str | None =
None, namespace: str | None =None) Self¶ Used to construct an instance taking into account the type of the urlconf_module on a url resolver.
- module : str¶
- name : str¶
- namespace : str¶
- regex : str¶
-
display(*, indent: str =
Django patterns¶
-
class django_consistency_enforcer.urls.CapturedArg(annotation: object, converter: type | None =
attr_dict['converter'].default)¶ This represents a named captured group in a url pattern and the converter that django will use on this part of the url.
The from_converter classmethod on this class will instantiate this class with the annotations that are match the shape of the object the converter will return.
- annotation : object¶
The annotation associated with the captured arg
- converter : type | None¶
The converter used to transform the string received from the url
- classmethod from_converter(converter: type | None) Self¶
Return an instance given some converter type.
This knows about the built in converter types. And how to get the return annotation from the to_python method for other converters.
Where it’s used it’s possible to instead pass in a subclass that knows about more converters.
- protocol django_consistency_enforcer.urls.CapturedArgMaker¶
Represents a constructor that returns a
CapturedArgobject.Classes that implement this protocol must have the following methods / attributes:
- __call__(converter: type | None, /) CapturedArg¶
Call self as a function.
-
class django_consistency_enforcer.urls.RawPatternPart(groups: int, captured: dict[str, CapturedArg], where: Where, default_arg_names: set[str] =
NOTHING)¶ Represents a single part of a Django url pattern.
- captured : dict[str, CapturedArg]¶
A dictionary of captured args from this pattern
- default_arg_names : set[str]¶
Holds onto the names of any arguments that are provided to the view regardless of the url
- classmethod from_pattern(pattern: _PatternType, default_args: dict[str, object], where: Where, *, captured_arg_maker: CapturedArgMaker) Self¶
Return an instance given some Django RoutePattern/RegexPattern.
- groups : int¶
The number of captured groups represented by this part of the pattern
- class django_consistency_enforcer.urls.RawPattern(parts: Sequence[RawPatternPart], callback: Callable[[...], object], view_class: type | None, where: Where)¶
Represents the parts that make up a single pattern that routes a request to a specific view.
The naming “Raw” is because this object makes no judgement over the specific type of the view class when this is a class based view.
- callback : Callable[[...], object]¶
The function that is called by Django if this route is matched
- classmethod from_parts(parts: Sequence[RawPatternPart], *, callback: Callable[[...], object], where: Where) Self¶
Create an instance given the parts that make up the pattern and the callback it calls into when the route is matched.
- parts : Sequence[RawPatternPart]¶
The different parts that leads to the whole pattern
- view_class : type | None¶
The view class associated with the callback when it’s marked as having a view class
- class django_consistency_enforcer.urls.Pattern¶
All our scenarios are in terms of this interface.
- abstract property callback : Callable[[...], object]¶
The function Django calls when this pattern is matched.
- abstractmethod exclude(*, auth_user_model: type) bool¶
Used by the test runner to skip analysis of this pattern.
- abstractmethod exclude_function(*, auth_user_model: type, function: DispatchFunction) bool¶
Used by the test runner to skip analysis of this function.
- abstract property parts : Sequence[RawPatternPart]¶
The parts that make up the whole pattern.
- abstractmethod relevant_functions() Iterator[DispatchFunction]¶
Return an iterator of the functions to run function scenarios over.
- class django_consistency_enforcer.urls.ViewPattern(raw_pattern: RawPattern, parts: Sequence[RawPatternPart], callback: Callable[[...], object], view_class: type[T_ViewClass] | None, where: Where)¶
A concrete implementation of the
Patterninterface that is specific to subclasses of django.views.generic.View- callback : Callable[[...], object]¶
The function Django calls if this pattern is matched
- dispatch_function_request_type() object¶
Return the annotation that should be given to request positional arguments to dispatch functions.
-
display_view_class(*, indent: str =
' ') str¶ Return an empty string if we aren’t a method, otherwise return a string representing information about the view class.
- exclude(*, auth_user_model: type) bool¶
By default no pattern is excluded.
- exclude_function(*, auth_user_model: type, function: DispatchFunction) bool¶
By default only functions defined by Django itself is excluded from analysis.
- make_dispatch_function(callback: Callable[[...], object], *, positional: Sequence[tuple[str, object]]) DispatchFunction¶
Used to return a subclass of
django_consistency_enforce.urls.DispatchFunction.Useful if subclasses want to add different implementation details to these objects.
- parts : Sequence[RawPatternPart]¶
The parts that make up the full pattern
- raw_pattern : RawPattern¶
The full raw pattern this represents
- relevant_dispatch_functions(*, view_class: type[T_ViewClass], request_type: object) Iterator[DispatchFunction]¶
Yield the extra functions that represent specific http method types.
So get, post, delete, etc, as defined by http_method_names on the view class.
As well as http_method_not_allowed method.
- relevant_functions() Iterator[DispatchFunction]¶
Yield the dispatch functions that should be passed into function scenarios.
By default, if the callback is not a method, that’s returned and nothing else.
Otherwise we yield methods found on the view class: - setup - dispatch - make_dispatch_function if we are a subclass of generic.RedirectView - Those yield by relevant_dispatch_functions
- view_class : type[T_ViewClass] | None¶
The subclass of django.views.generic.View if this is a method
-
django_consistency_enforcer.urls.all_django_patterns(resolver: URLResolver, *, captured_arg_maker: CapturedArgMaker =
CapturedArg.from_converter, _chain: list[tuple[_PatternType, dict[str, object], Where]] | None =None) Iterator[RawPattern]¶ This is used to get us every url pattern matched to the callback associated with that url
We can use this to then check that the url patterns and the signatures of the functions on the view match up
- django_consistency_enforcer.urls.ensure_raw_pattern_is_generic_view(*, raw_pattern: RawPattern) type[View] | None¶
A lot of the code here relies on the behaviour of django.views.generic.View and so this helper exists to look at the raw pattern and complain if the view class is not a generic.View subclass when a view_class is associated with the pattern.
This function returns that view class typed such that mypy knows it’s a generic.View subclass
The implemented checks also rely on the behaviour of django.views.generic.View::as_view to guarantee that if there are any named capture groups in the url pattern, then there will be no positional arguments passed into setup/dispatch/get/post/etc
And so it will also complain if there are no named capture groups if the pattern has any captured groups
Errors¶
This library also provides a container class for holding onto many errors.
- class django_consistency_enforcer.errors.InvalidPattern¶
- class django_consistency_enforcer.errors.FoundInvalidPatterns(errors: ErrorContainer)¶
Used to indicate that invalid patterns were found.
- errors : ErrorContainer¶
- class django_consistency_enforcer.errors.ErrorContainer¶
This holds onto zero or more
InvalidPatternerrors with a read only interface for accessing them.- add(error: InvalidPattern) None¶
Add an error to the container.
- property by_most_repeated : Iterator[str]¶
Return an iterator of the stringified representation of the errors held by the container ordered such that the most repeated errors comes before less repeated errors.
- property errors : Iterator[InvalidPattern]¶
This returns the error container as an iterator and is effectively an alias to it’s __iter__ method.