Scenarios of behaviour to check¶
This library is built on the idea of splitting all of our checks into multiple
isolated scenarios where each scenario can focus on enforcing some specific
requirement. These are then strung together using the
test runner.
These scenarios are either a check on the view themself, or a check on the pattern and must subclass one of these two base classes:
- class django_consistency_enforcer.urls.PatternScenario¶
Represents a check that is run on a specific pattern.
- abstract property exit_early : bool¶
Used to indicate that if this scenario fails, no other pattern scenarios should be run.
- abstractmethod run(*, errors: ErrorContainer, auth_user_model: type, pattern: T_Pattern) None¶
This is where the logic for the check needs to go.
- class django_consistency_enforcer.urls.FunctionScenario¶
Represents a check that is run on a specific Django view.
- abstract property exit_early : bool¶
Used to indicate that if this scenario fails, no other pattern scenarios should be run.
- abstractmethod run(*, errors: ErrorContainer, auth_user_model: type, pattern: T_Pattern, function: DispatchFunction) None¶
This is where the logic for the check needs to go.
Built in scenarios¶
-
class django_consistency_enforcer.urls.CheckAcceptsArgsFunctionScenario(exit_early: bool =
attr_dict['exit_early'].default)¶ Checks that all the arguments in the pattern are accepted by the function.
- add_error(*, errors: ErrorContainer, error: ViewDoesNotAcceptCapturedArg) None¶
Add an error to come out of the scenario.
- exit_early : bool¶
- run(*, errors: ErrorContainer, auth_user_model: type, pattern: T_ViewPattern, function: DispatchFunction) None¶
If the function has a **kwargs: object or **kwargs: Any then no errors because the function takes in anything.
Otherwise we gather the keyword arguments on the function and match them to the captured args found on the pattern.
-
class django_consistency_enforcer.urls.CheckHasCorrectAnnotationsFunctionScenario(exit_early: bool =
attr_dict['exit_early'].default)¶ Check that the annotations on the function args match the types provided by the converters used in the captured groups of the pattern.
- add_error(*, errors: ErrorContainer, error: InvalidArgAnnotations) None¶
Add an error to come out of the scenario.
- exit_early : bool¶
- run(*, errors: ErrorContainer, auth_user_model: type, pattern: T_ViewPattern, function: DispatchFunction) None¶
This matches the annotations on the function args to the annotations on the captured args on the pattern.
-
class django_consistency_enforcer.urls.CheckKwargsMustBeAnnotatedFunctionScenario(allows_object: bool =
attr_dict['allows_object'].default, allows_any: bool =attr_dict['allows_any'].default, exit_early: bool =attr_dict['exit_early'].default)¶ Check that a **kwargs on the django view is annotated correctly.
- add_error(*, errors: ErrorContainer, error: KwargsMustBeAnnotated) None¶
Add an error to come out of the scenario.
- allows_any : bool¶
- allows_object : bool¶
- exit_early : bool¶
- run(*, errors: ErrorContainer, auth_user_model: type, pattern: T_Pattern, function: DispatchFunction) None¶
Ensure that the annotation is correct
Annotation of object is correct only if self.allows_object
Annotation of Any is correct only if self.allows_any
Otherwise complain because the only valid annotation otherwise is a TypedDict and those are already unpacked when we create the function objects.
-
class django_consistency_enforcer.urls.CheckPositionalArgsAreCorrectFunctionScenario(disallow_var_args: bool =
attr_dict['disallow_var_args'].default, enforce_keyword_args: bool =attr_dict['enforce_keyword_args'].default, exit_early: bool =attr_dict['exit_early'].default)¶ This is a scenario that checks that the positional arguments on a view are correct.
This view needs to be subclass’d with an implementation for is_mistyped.
- add_error(*, errors: ErrorContainer, error: MismatchedRequiredArgs) None¶
Add an error to come out of the scenario.
- disallow_var_args : bool¶
- enforce_keyword_args : bool¶
- exit_early : bool¶
- abstractmethod is_mistyped(*, function: DispatchFunction, want_annotation: object, got_annotation: object, auth_user_model: type, name: str, position: int) Incorrect | None¶
Used to determine what error is appropriate when the annotation doesn’t match for any of the required positional arguments.
This is abstract cause deciding that is likely project specific.
- run(*, errors: ErrorContainer, auth_user_model: type, pattern: T_Pattern, function: DispatchFunction) None¶
This check looks at all the function_args and:
Skips the self argument
Matches the positional arguments found on the view against the required arguments defined by function
Complains about *args if self.disallow_var_args
Complains about a missing * after required positional args if self.enforce_keyword_args
Calls into is_mistyped to get an error if the annotation on the argument is neither Any or the expected annotation for that argument.
-
class django_consistency_enforcer.urls.CheckRequiredArgsMatchUrlPatternFunctionScenario(exit_early: bool =
attr_dict['exit_early'].default)¶ Checks that the arguments that are required by a function are found in the pattern that routes to the view.
- add_error(*, errors: ErrorContainer, error: RequiredArgOnViewNotAlwaysRequiredByPattern) None¶
Add an error to come out of the scenario.
- exit_early : bool¶
- run(*, errors: ErrorContainer, auth_user_model: type, pattern: T_ViewPattern, function: DispatchFunction) None¶
Discover the arguments that must be passed into the function and complain about any that are missing from the pattern.
-
class django_consistency_enforcer.urls.CheckViewClassRequestAnnotationScenario(acceptable_annotations: Sequence[object], acceptable_request_annotation_containers: Sequence[object], error_class: type[InvalidRequestAnnotation], exit_early: bool =
attr_dict['exit_early'].default)¶ Check that the view class has an annotation for request that is correct.
- acceptable_annotations : Sequence[object]¶
- acceptable_request_annotation_containers : Sequence[object]¶
- add_error(*, errors: ErrorContainer, error: InvalidRequestAnnotation) None¶
Add an error to come out of the scenario.
- annotation_is_valid(*, errors: ErrorContainer, auth_user_model: type, annotation: object, pattern: T_ViewPattern) bool¶
Return whether the annotation found for request is valid.
This can be subclass’d when a project has it’s own specific rules.
- error_class : type[InvalidRequestAnnotation]¶
- exit_early : bool¶
- run(*, errors: ErrorContainer, auth_user_model: type, pattern: T_ViewPattern) None¶
If the pattern is not a view class method or there is no request annotation on the class then there is nothing to check and we exit.
Otherwise we defer to annotation_is_valid to determine if the annotation is correct.