clear-skies 1.22.10__py3-none-any.whl → 2.0.23__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- clear_skies-2.0.23.dist-info/METADATA +76 -0
- clear_skies-2.0.23.dist-info/RECORD +265 -0
- {clear_skies-1.22.10.dist-info → clear_skies-2.0.23.dist-info}/WHEEL +1 -1
- clearskies/__init__.py +37 -21
- clearskies/action.py +7 -0
- clearskies/authentication/__init__.py +8 -39
- clearskies/authentication/authentication.py +44 -0
- clearskies/authentication/authorization.py +14 -8
- clearskies/authentication/authorization_pass_through.py +14 -10
- clearskies/authentication/jwks.py +135 -58
- clearskies/authentication/public.py +3 -26
- clearskies/authentication/secret_bearer.py +515 -44
- clearskies/autodoc/formats/oai3_json/__init__.py +2 -2
- clearskies/autodoc/formats/oai3_json/oai3_json.py +11 -9
- clearskies/autodoc/formats/oai3_json/parameter.py +6 -3
- clearskies/autodoc/formats/oai3_json/request.py +7 -5
- clearskies/autodoc/formats/oai3_json/response.py +7 -4
- clearskies/autodoc/formats/oai3_json/schema/object.py +10 -1
- clearskies/autodoc/request/__init__.py +2 -0
- clearskies/autodoc/request/header.py +4 -6
- clearskies/autodoc/request/json_body.py +4 -6
- clearskies/autodoc/request/parameter.py +8 -0
- clearskies/autodoc/request/request.py +16 -4
- clearskies/autodoc/request/url_parameter.py +4 -6
- clearskies/autodoc/request/url_path.py +4 -6
- clearskies/autodoc/schema/__init__.py +4 -2
- clearskies/autodoc/schema/array.py +5 -6
- clearskies/autodoc/schema/boolean.py +4 -10
- clearskies/autodoc/schema/date.py +0 -3
- clearskies/autodoc/schema/datetime.py +1 -4
- clearskies/autodoc/schema/double.py +0 -3
- clearskies/autodoc/schema/enum.py +4 -2
- clearskies/autodoc/schema/integer.py +4 -9
- clearskies/autodoc/schema/long.py +0 -3
- clearskies/autodoc/schema/number.py +4 -9
- clearskies/autodoc/schema/object.py +5 -7
- clearskies/autodoc/schema/password.py +0 -3
- clearskies/autodoc/schema/schema.py +11 -0
- clearskies/autodoc/schema/string.py +4 -10
- clearskies/backends/__init__.py +55 -20
- clearskies/backends/api_backend.py +1118 -280
- clearskies/backends/backend.py +54 -85
- clearskies/backends/cursor_backend.py +246 -191
- clearskies/backends/memory_backend.py +514 -208
- clearskies/backends/secrets_backend.py +68 -31
- clearskies/column.py +1221 -0
- clearskies/columns/__init__.py +71 -0
- clearskies/columns/audit.py +306 -0
- clearskies/columns/belongs_to_id.py +478 -0
- clearskies/columns/belongs_to_model.py +129 -0
- clearskies/columns/belongs_to_self.py +109 -0
- clearskies/columns/boolean.py +110 -0
- clearskies/columns/category_tree.py +273 -0
- clearskies/columns/category_tree_ancestors.py +51 -0
- clearskies/columns/category_tree_children.py +126 -0
- clearskies/columns/category_tree_descendants.py +48 -0
- clearskies/columns/created.py +92 -0
- clearskies/columns/created_by_authorization_data.py +114 -0
- clearskies/columns/created_by_header.py +103 -0
- clearskies/columns/created_by_ip.py +90 -0
- clearskies/columns/created_by_routing_data.py +102 -0
- clearskies/columns/created_by_user_agent.py +89 -0
- clearskies/columns/date.py +232 -0
- clearskies/columns/datetime.py +284 -0
- clearskies/columns/email.py +78 -0
- clearskies/columns/float.py +149 -0
- clearskies/columns/has_many.py +529 -0
- clearskies/columns/has_many_self.py +62 -0
- clearskies/columns/has_one.py +21 -0
- clearskies/columns/integer.py +158 -0
- clearskies/columns/json.py +126 -0
- clearskies/columns/many_to_many_ids.py +335 -0
- clearskies/columns/many_to_many_ids_with_data.py +274 -0
- clearskies/columns/many_to_many_models.py +156 -0
- clearskies/columns/many_to_many_pivots.py +132 -0
- clearskies/columns/phone.py +162 -0
- clearskies/columns/select.py +95 -0
- clearskies/columns/string.py +102 -0
- clearskies/columns/timestamp.py +164 -0
- clearskies/columns/updated.py +107 -0
- clearskies/columns/uuid.py +83 -0
- clearskies/configs/README.md +105 -0
- clearskies/configs/__init__.py +170 -0
- clearskies/configs/actions.py +43 -0
- clearskies/configs/any.py +15 -0
- clearskies/configs/any_dict.py +24 -0
- clearskies/configs/any_dict_or_callable.py +25 -0
- clearskies/configs/authentication.py +23 -0
- clearskies/configs/authorization.py +23 -0
- clearskies/configs/boolean.py +18 -0
- clearskies/configs/boolean_or_callable.py +20 -0
- clearskies/configs/callable_config.py +20 -0
- clearskies/configs/columns.py +34 -0
- clearskies/configs/conditions.py +30 -0
- clearskies/configs/config.py +26 -0
- clearskies/configs/datetime.py +20 -0
- clearskies/configs/datetime_or_callable.py +21 -0
- clearskies/configs/email.py +10 -0
- clearskies/configs/email_list.py +17 -0
- clearskies/configs/email_list_or_callable.py +17 -0
- clearskies/configs/email_or_email_list_or_callable.py +59 -0
- clearskies/configs/endpoint.py +23 -0
- clearskies/configs/endpoint_list.py +29 -0
- clearskies/configs/float.py +18 -0
- clearskies/configs/float_or_callable.py +20 -0
- clearskies/configs/headers.py +28 -0
- clearskies/configs/integer.py +18 -0
- clearskies/configs/integer_or_callable.py +20 -0
- clearskies/configs/joins.py +30 -0
- clearskies/configs/list_any_dict.py +32 -0
- clearskies/configs/list_any_dict_or_callable.py +33 -0
- clearskies/configs/model_class.py +35 -0
- clearskies/configs/model_column.py +67 -0
- clearskies/configs/model_columns.py +58 -0
- clearskies/configs/model_destination_name.py +26 -0
- clearskies/configs/model_to_id_column.py +45 -0
- clearskies/configs/readable_model_column.py +11 -0
- clearskies/configs/readable_model_columns.py +11 -0
- clearskies/configs/schema.py +23 -0
- clearskies/configs/searchable_model_columns.py +11 -0
- clearskies/configs/security_headers.py +39 -0
- clearskies/configs/select.py +28 -0
- clearskies/configs/select_list.py +49 -0
- clearskies/configs/string.py +31 -0
- clearskies/configs/string_dict.py +34 -0
- clearskies/configs/string_list.py +47 -0
- clearskies/configs/string_list_or_callable.py +48 -0
- clearskies/configs/string_or_callable.py +18 -0
- clearskies/configs/timedelta.py +20 -0
- clearskies/configs/timezone.py +20 -0
- clearskies/configs/url.py +25 -0
- clearskies/configs/validators.py +45 -0
- clearskies/configs/writeable_model_column.py +11 -0
- clearskies/configs/writeable_model_columns.py +11 -0
- clearskies/configurable.py +78 -0
- clearskies/contexts/__init__.py +8 -8
- clearskies/contexts/cli.py +129 -43
- clearskies/contexts/context.py +93 -56
- clearskies/contexts/wsgi.py +79 -33
- clearskies/contexts/wsgi_ref.py +87 -0
- clearskies/cursors/__init__.py +7 -0
- clearskies/cursors/cursor.py +166 -0
- clearskies/cursors/from_environment/__init__.py +5 -0
- clearskies/cursors/from_environment/mysql.py +51 -0
- clearskies/cursors/from_environment/postgresql.py +49 -0
- clearskies/cursors/from_environment/sqlite.py +35 -0
- clearskies/cursors/mysql.py +61 -0
- clearskies/cursors/postgresql.py +61 -0
- clearskies/cursors/sqlite.py +62 -0
- clearskies/decorators.py +33 -0
- clearskies/decorators.pyi +10 -0
- clearskies/di/__init__.py +11 -7
- clearskies/di/additional_config.py +115 -4
- clearskies/di/additional_config_auto_import.py +12 -0
- clearskies/di/di.py +714 -125
- clearskies/di/inject/__init__.py +23 -0
- clearskies/di/inject/akeyless_sdk.py +16 -0
- clearskies/di/inject/by_class.py +24 -0
- clearskies/di/inject/by_name.py +22 -0
- clearskies/di/inject/di.py +16 -0
- clearskies/di/inject/environment.py +15 -0
- clearskies/di/inject/input_output.py +19 -0
- clearskies/di/inject/now.py +16 -0
- clearskies/di/inject/requests.py +16 -0
- clearskies/di/inject/secrets.py +15 -0
- clearskies/di/inject/utcnow.py +16 -0
- clearskies/di/inject/uuid.py +16 -0
- clearskies/di/injectable.py +32 -0
- clearskies/di/injectable_properties.py +131 -0
- clearskies/end.py +219 -0
- clearskies/endpoint.py +1303 -0
- clearskies/endpoint_group.py +333 -0
- clearskies/endpoints/__init__.py +25 -0
- clearskies/endpoints/advanced_search.py +519 -0
- clearskies/endpoints/callable.py +382 -0
- clearskies/endpoints/create.py +201 -0
- clearskies/endpoints/delete.py +133 -0
- clearskies/endpoints/get.py +267 -0
- clearskies/endpoints/health_check.py +181 -0
- clearskies/endpoints/list.py +567 -0
- clearskies/endpoints/restful_api.py +417 -0
- clearskies/endpoints/schema.py +185 -0
- clearskies/endpoints/simple_search.py +279 -0
- clearskies/endpoints/update.py +188 -0
- clearskies/environment.py +7 -3
- clearskies/exceptions/__init__.py +19 -0
- clearskies/{handlers/exceptions/input_error.py → exceptions/input_errors.py} +1 -1
- clearskies/exceptions/missing_dependency.py +2 -0
- clearskies/exceptions/moved_permanently.py +3 -0
- clearskies/exceptions/moved_temporarily.py +3 -0
- clearskies/functional/__init__.py +2 -2
- clearskies/functional/json.py +47 -0
- clearskies/functional/routing.py +92 -0
- clearskies/functional/string.py +19 -11
- clearskies/functional/validations.py +61 -9
- clearskies/input_outputs/__init__.py +9 -7
- clearskies/input_outputs/cli.py +135 -160
- clearskies/input_outputs/exceptions/__init__.py +6 -1
- clearskies/input_outputs/headers.py +54 -0
- clearskies/input_outputs/input_output.py +77 -123
- clearskies/input_outputs/programmatic.py +62 -0
- clearskies/input_outputs/wsgi.py +36 -48
- clearskies/model.py +1874 -193
- clearskies/query/__init__.py +12 -0
- clearskies/query/condition.py +228 -0
- clearskies/query/join.py +136 -0
- clearskies/query/query.py +193 -0
- clearskies/query/sort.py +27 -0
- clearskies/schema.py +82 -0
- clearskies/secrets/__init__.py +4 -31
- clearskies/secrets/additional_configs/mysql_connection_dynamic_producer.py +15 -4
- clearskies/secrets/additional_configs/mysql_connection_dynamic_producer_via_ssh_cert_bastion.py +11 -5
- clearskies/secrets/akeyless.py +421 -155
- clearskies/secrets/exceptions/__init__.py +7 -1
- clearskies/secrets/exceptions/not_found_error.py +2 -0
- clearskies/secrets/exceptions/permissions_error.py +2 -0
- clearskies/secrets/secrets.py +12 -11
- clearskies/security_header.py +17 -0
- clearskies/security_headers/__init__.py +8 -8
- clearskies/security_headers/cache_control.py +47 -109
- clearskies/security_headers/cors.py +38 -92
- clearskies/security_headers/csp.py +76 -150
- clearskies/security_headers/hsts.py +14 -15
- clearskies/typing.py +11 -0
- clearskies/validator.py +36 -0
- clearskies/validators/__init__.py +33 -0
- clearskies/validators/after_column.py +61 -0
- clearskies/validators/before_column.py +15 -0
- clearskies/validators/in_the_future.py +29 -0
- clearskies/validators/in_the_future_at_least.py +13 -0
- clearskies/validators/in_the_future_at_most.py +12 -0
- clearskies/validators/in_the_past.py +29 -0
- clearskies/validators/in_the_past_at_least.py +12 -0
- clearskies/validators/in_the_past_at_most.py +12 -0
- clearskies/validators/maximum_length.py +25 -0
- clearskies/validators/maximum_value.py +28 -0
- clearskies/validators/minimum_length.py +25 -0
- clearskies/validators/minimum_value.py +28 -0
- clearskies/{input_requirements → validators}/required.py +18 -9
- clearskies/validators/timedelta.py +58 -0
- clearskies/validators/unique.py +28 -0
- clear_skies-1.22.10.dist-info/METADATA +0 -47
- clear_skies-1.22.10.dist-info/RECORD +0 -213
- clearskies/application.py +0 -29
- clearskies/authentication/auth0_jwks.py +0 -118
- clearskies/authentication/auth_exception.py +0 -2
- clearskies/authentication/jwks_jwcrypto.py +0 -51
- clearskies/backends/api_get_only_backend.py +0 -48
- clearskies/backends/example_backend.py +0 -43
- clearskies/backends/file_backend.py +0 -48
- clearskies/backends/json_backend.py +0 -7
- clearskies/backends/restful_api_advanced_search_backend.py +0 -103
- clearskies/binding_config.py +0 -16
- clearskies/column_types/__init__.py +0 -203
- clearskies/column_types/audit.py +0 -249
- clearskies/column_types/belongs_to.py +0 -271
- clearskies/column_types/boolean.py +0 -60
- clearskies/column_types/category_tree.py +0 -304
- clearskies/column_types/column.py +0 -373
- clearskies/column_types/created.py +0 -26
- clearskies/column_types/created_by_authorization_data.py +0 -26
- clearskies/column_types/created_by_header.py +0 -24
- clearskies/column_types/created_by_ip.py +0 -17
- clearskies/column_types/created_by_routing_data.py +0 -25
- clearskies/column_types/created_by_user_agent.py +0 -17
- clearskies/column_types/created_micro.py +0 -26
- clearskies/column_types/datetime.py +0 -109
- clearskies/column_types/datetime_micro.py +0 -13
- clearskies/column_types/email.py +0 -18
- clearskies/column_types/float.py +0 -43
- clearskies/column_types/has_many.py +0 -179
- clearskies/column_types/has_one.py +0 -58
- clearskies/column_types/integer.py +0 -41
- clearskies/column_types/json.py +0 -25
- clearskies/column_types/many_to_many.py +0 -278
- clearskies/column_types/many_to_many_with_data.py +0 -162
- clearskies/column_types/phone.py +0 -48
- clearskies/column_types/select.py +0 -11
- clearskies/column_types/string.py +0 -24
- clearskies/column_types/timestamp.py +0 -73
- clearskies/column_types/updated.py +0 -26
- clearskies/column_types/updated_micro.py +0 -26
- clearskies/column_types/uuid.py +0 -25
- clearskies/columns.py +0 -123
- clearskies/condition_parser.py +0 -172
- clearskies/contexts/build_context.py +0 -54
- clearskies/contexts/convert_to_application.py +0 -190
- clearskies/contexts/extract_handler.py +0 -37
- clearskies/contexts/test.py +0 -94
- clearskies/decorators/__init__.py +0 -39
- clearskies/decorators/auth0_jwks.py +0 -22
- clearskies/decorators/authorization.py +0 -10
- clearskies/decorators/binding_classes.py +0 -9
- clearskies/decorators/binding_modules.py +0 -9
- clearskies/decorators/bindings.py +0 -9
- clearskies/decorators/create.py +0 -10
- clearskies/decorators/delete.py +0 -10
- clearskies/decorators/docs.py +0 -14
- clearskies/decorators/get.py +0 -10
- clearskies/decorators/jwks.py +0 -26
- clearskies/decorators/merge.py +0 -124
- clearskies/decorators/patch.py +0 -10
- clearskies/decorators/post.py +0 -10
- clearskies/decorators/public.py +0 -11
- clearskies/decorators/response_headers.py +0 -10
- clearskies/decorators/return_raw_response.py +0 -9
- clearskies/decorators/schema.py +0 -10
- clearskies/decorators/secret_bearer.py +0 -24
- clearskies/decorators/security_headers.py +0 -10
- clearskies/di/standard_dependencies.py +0 -151
- clearskies/di/test_module/__init__.py +0 -6
- clearskies/di/test_module/another_module/__init__.py +0 -2
- clearskies/di/test_module/module_class.py +0 -5
- clearskies/handlers/__init__.py +0 -41
- clearskies/handlers/advanced_search.py +0 -271
- clearskies/handlers/base.py +0 -479
- clearskies/handlers/callable.py +0 -191
- clearskies/handlers/create.py +0 -35
- clearskies/handlers/crud_by_method.py +0 -18
- clearskies/handlers/database_connector.py +0 -32
- clearskies/handlers/delete.py +0 -61
- clearskies/handlers/exceptions/__init__.py +0 -5
- clearskies/handlers/exceptions/not_found.py +0 -3
- clearskies/handlers/get.py +0 -156
- clearskies/handlers/health_check.py +0 -59
- clearskies/handlers/input_processing.py +0 -79
- clearskies/handlers/list.py +0 -530
- clearskies/handlers/mygrations.py +0 -82
- clearskies/handlers/request_method_routing.py +0 -47
- clearskies/handlers/restful_api.py +0 -218
- clearskies/handlers/routing.py +0 -62
- clearskies/handlers/schema_helper.py +0 -128
- clearskies/handlers/simple_routing.py +0 -206
- clearskies/handlers/simple_routing_route.py +0 -192
- clearskies/handlers/simple_search.py +0 -136
- clearskies/handlers/update.py +0 -96
- clearskies/handlers/write.py +0 -193
- clearskies/input_requirements/__init__.py +0 -78
- clearskies/input_requirements/after.py +0 -36
- clearskies/input_requirements/before.py +0 -36
- clearskies/input_requirements/in_the_future_at_least.py +0 -19
- clearskies/input_requirements/in_the_future_at_most.py +0 -19
- clearskies/input_requirements/in_the_past_at_least.py +0 -19
- clearskies/input_requirements/in_the_past_at_most.py +0 -19
- clearskies/input_requirements/maximum_length.py +0 -19
- clearskies/input_requirements/maximum_value.py +0 -19
- clearskies/input_requirements/minimum_length.py +0 -22
- clearskies/input_requirements/minimum_value.py +0 -19
- clearskies/input_requirements/requirement.py +0 -25
- clearskies/input_requirements/time_delta.py +0 -38
- clearskies/input_requirements/unique.py +0 -18
- clearskies/mocks/__init__.py +0 -7
- clearskies/mocks/input_output.py +0 -124
- clearskies/mocks/models.py +0 -142
- clearskies/models.py +0 -350
- clearskies/security_headers/base.py +0 -12
- clearskies/tests/simple_api/models/__init__.py +0 -2
- clearskies/tests/simple_api/models/status.py +0 -23
- clearskies/tests/simple_api/models/user.py +0 -21
- clearskies/tests/simple_api/users_api.py +0 -64
- {clear_skies-1.22.10.dist-info → clear_skies-2.0.23.dist-info/licenses}/LICENSE +0 -0
- /clearskies/{contexts/bash.py → autodoc/py.typed} +0 -0
- /clearskies/{handlers/exceptions → exceptions}/authentication.py +0 -0
- /clearskies/{handlers/exceptions → exceptions}/authorization.py +0 -0
- /clearskies/{handlers/exceptions → exceptions}/client_error.py +0 -0
- /clearskies/{secrets/exceptions → exceptions}/not_found.py +0 -0
- /clearskies/{tests/__init__.py → input_outputs/py.typed} +0 -0
- /clearskies/{tests/simple_api/__init__.py → py.typed} +0 -0
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import datetime
|
|
2
|
-
|
|
3
|
-
from .after import After
|
|
4
|
-
from .before import Before
|
|
5
|
-
from ..binding_config import BindingConfig
|
|
6
|
-
from .minimum_length import MinimumLength
|
|
7
|
-
from .minimum_value import MinimumValue
|
|
8
|
-
from .maximum_length import MaximumLength
|
|
9
|
-
from .maximum_value import MaximumValue
|
|
10
|
-
from .required import Required
|
|
11
|
-
from .requirement import Requirement
|
|
12
|
-
from .unique import Unique
|
|
13
|
-
from .in_the_future_at_least import InTheFutureAtLeast
|
|
14
|
-
from .in_the_future_at_most import InTheFutureAtMost
|
|
15
|
-
from .in_the_past_at_least import InThePastAtLeast
|
|
16
|
-
from .in_the_past_at_most import InThePastAtMost
|
|
17
|
-
from .time_delta import TimeDelta
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def after(other_column_name: str, allow_equal: bool = False):
|
|
21
|
-
return BindingConfig(After, other_column_name=other_column_name, allow_equal=allow_equal)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def before(other_column_name: str, allow_equal: bool = False):
|
|
25
|
-
return BindingConfig(Before, other_column_name=other_column_name, allow_equal=allow_equal)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def minimum_length(minimum_length: int):
|
|
29
|
-
return BindingConfig(MinimumLength, minimum_length)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def minimum_value(minimum_value: int):
|
|
33
|
-
return BindingConfig(MinimumValue, minimum_value)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def maximum_length(maximum_length: int):
|
|
37
|
-
return BindingConfig(MaximumLength, maximum_length)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def maximum_value(maximum_value: int):
|
|
41
|
-
return BindingConfig(MaximumValue, maximum_value)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def required():
|
|
45
|
-
return BindingConfig(Required)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def unique():
|
|
49
|
-
return BindingConfig(Unique)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def in_the_future_at_least(time_delta: datetime.timedelta):
|
|
53
|
-
return BindingConfig(InTheFutureAtLeast, time_delta)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def in_the_future_at_most(time_delta: datetime.timedelta):
|
|
57
|
-
return BindingConfig(InTheFutureAtMost, time_delta)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def in_the_past_at_least(time_delta: datetime.timedelta):
|
|
61
|
-
return BindingConfig(InThePastAtLeast, time_delta)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def in_the_past_at_most(time_delta: datetime.timedelta):
|
|
65
|
-
return BindingConfig(InThePastAtMost, time_delta)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
__all__ = [
|
|
69
|
-
"in_the_future_at_least",
|
|
70
|
-
"in_the_future_at_most",
|
|
71
|
-
"in_the_past_at_least",
|
|
72
|
-
"in_the_past_at_most",
|
|
73
|
-
"minimum_length",
|
|
74
|
-
"maximum_length",
|
|
75
|
-
"required",
|
|
76
|
-
"TimeDelta",
|
|
77
|
-
"unique",
|
|
78
|
-
]
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
from .requirement import Requirement
|
|
2
|
-
import datetime
|
|
3
|
-
import dateparser
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class After(Requirement):
|
|
7
|
-
def configure(self, other_column_name: str, allow_equal: bool = False):
|
|
8
|
-
self.other_column_name = other_column_name
|
|
9
|
-
self.allow_equal = allow_equal
|
|
10
|
-
|
|
11
|
-
def check(self, model, data):
|
|
12
|
-
# we won't check anything for missing values (columns should be required if that is an issue)
|
|
13
|
-
if not data.get(self.column_name):
|
|
14
|
-
return ""
|
|
15
|
-
my_value = data[self.column_name]
|
|
16
|
-
other_value = data.get(self.other_column_name, model.__getitem__(self.other_column_name))
|
|
17
|
-
# again, no checks for non-values
|
|
18
|
-
if not other_value:
|
|
19
|
-
return ""
|
|
20
|
-
|
|
21
|
-
my_value_as_date = dateparser.parse(data[self.column_name])
|
|
22
|
-
if not my_value_as_date:
|
|
23
|
-
return f"'{self.column_name}' was not a valid date."
|
|
24
|
-
|
|
25
|
-
if type(other_value) != str and type(other_value) != datetime.datetime:
|
|
26
|
-
return f"'{other_column_name}' was not a valid date."
|
|
27
|
-
other_value_as_date = dateparser.parse(other_value) if type(other_value) == str else other_value
|
|
28
|
-
if not other_value_as_date:
|
|
29
|
-
return f"'{self.other_column_name}' was not a valid date."
|
|
30
|
-
|
|
31
|
-
if my_value_as_date == other_value_as_date:
|
|
32
|
-
return "" if self.allow_equal else f"'{self.column_name}' must be after '{self.other_column_name}'"
|
|
33
|
-
|
|
34
|
-
if my_value_as_date < other_value_as_date:
|
|
35
|
-
return f"'{self.column_name}' must be after '{self.other_column_name}'"
|
|
36
|
-
return ""
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
from .requirement import Requirement
|
|
2
|
-
import datetime
|
|
3
|
-
import dateparser
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Before(Requirement):
|
|
7
|
-
def configure(self, other_column_name: str, allow_equal: bool = False):
|
|
8
|
-
self.other_column_name = other_column_name
|
|
9
|
-
self.allow_equal = allow_equal
|
|
10
|
-
|
|
11
|
-
def check(self, model, data):
|
|
12
|
-
# we won't check anything for missing values (columns should be required if that is an issue)
|
|
13
|
-
if not data.get(self.column_name):
|
|
14
|
-
return ""
|
|
15
|
-
my_value = data[self.column_name]
|
|
16
|
-
other_value = data.get(self.other_column_name, model.__getitem__(self.other_column_name))
|
|
17
|
-
# again, no checks for non-values
|
|
18
|
-
if not other_value:
|
|
19
|
-
return ""
|
|
20
|
-
|
|
21
|
-
my_value_as_date = dateparser.parse(data[self.column_name])
|
|
22
|
-
if not my_value_as_date:
|
|
23
|
-
return f"'{self.column_name}' was not a valid date."
|
|
24
|
-
|
|
25
|
-
if type(other_value) != str and type(other_value) != datetime.datetime:
|
|
26
|
-
return f"'{other_column_name}' was not a valid date."
|
|
27
|
-
other_value_as_date = dateparser.parse(other_value) if type(other_value) == str else other_value
|
|
28
|
-
if not other_value_as_date:
|
|
29
|
-
return f"'{self.other_column_name}' was not a valid date."
|
|
30
|
-
|
|
31
|
-
if my_value_as_date == other_value_as_date:
|
|
32
|
-
return "" if self.allow_equal else f"'{self.column_name}' must be before '{self.other_column_name}'"
|
|
33
|
-
|
|
34
|
-
if my_value_as_date > other_value_as_date:
|
|
35
|
-
return f"'{self.column_name}' must be before '{self.other_column_name}'"
|
|
36
|
-
return ""
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
from .time_delta import TimeDelta
|
|
2
|
-
import datetime
|
|
3
|
-
import dateparser
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class InTheFutureAtLeast(TimeDelta):
|
|
7
|
-
def check(self, model, data):
|
|
8
|
-
if self.column_name not in data or not data[self.column_name]:
|
|
9
|
-
return ""
|
|
10
|
-
as_date = dateparser.parse(data[self.column_name])
|
|
11
|
-
if not as_date:
|
|
12
|
-
return f"'{self.column_name}' was not a valid date"
|
|
13
|
-
now = (
|
|
14
|
-
self.datetime.datetime.now() if not as_date.tzinfo else self.datetime.datetime.now(tz=datetime.timezone.utc)
|
|
15
|
-
)
|
|
16
|
-
if as_date < now + self.time_delta:
|
|
17
|
-
human_friendly = self.delta_human_friendly()
|
|
18
|
-
return f"'{self.column_name}' must be at least {human_friendly} in the future."
|
|
19
|
-
return ""
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
from .time_delta import TimeDelta
|
|
2
|
-
import datetime
|
|
3
|
-
import dateparser
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class InTheFutureAtMost(TimeDelta):
|
|
7
|
-
def check(self, model, data):
|
|
8
|
-
if self.column_name not in data or not data[self.column_name]:
|
|
9
|
-
return ""
|
|
10
|
-
as_date = dateparser.parse(data[self.column_name])
|
|
11
|
-
if not as_date:
|
|
12
|
-
return f"'{self.column_name}' was not a valid date"
|
|
13
|
-
now = (
|
|
14
|
-
self.datetime.datetime.now() if not as_date.tzinfo else self.datetime.datetime.now(tz=datetime.timezone.utc)
|
|
15
|
-
)
|
|
16
|
-
if as_date > now + self.time_delta:
|
|
17
|
-
human_friendly = self.delta_human_friendly()
|
|
18
|
-
return f"'{self.column_name}' must be at most {human_friendly} in the future."
|
|
19
|
-
return ""
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
from .time_delta import TimeDelta
|
|
2
|
-
import datetime
|
|
3
|
-
import dateparser
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class InThePastAtLeast(TimeDelta):
|
|
7
|
-
def check(self, model, data):
|
|
8
|
-
if self.column_name not in data or not data[self.column_name]:
|
|
9
|
-
return ""
|
|
10
|
-
as_date = dateparser.parse(data[self.column_name])
|
|
11
|
-
if not as_date:
|
|
12
|
-
return f"'{self.column_name}' was not a valid date"
|
|
13
|
-
now = (
|
|
14
|
-
self.datetime.datetime.now() if not as_date.tzinfo else self.datetime.datetime.now(tz=datetime.timezone.utc)
|
|
15
|
-
)
|
|
16
|
-
if as_date > now - self.time_delta:
|
|
17
|
-
human_friendly = self.delta_human_friendly()
|
|
18
|
-
return f"'{self.column_name}' must be at least {human_friendly} in the past."
|
|
19
|
-
return ""
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
from .time_delta import TimeDelta
|
|
2
|
-
import datetime
|
|
3
|
-
import dateparser
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class InThePastAtMost(TimeDelta):
|
|
7
|
-
def check(self, model, data):
|
|
8
|
-
if self.column_name not in data or not data[self.column_name]:
|
|
9
|
-
return ""
|
|
10
|
-
as_date = dateparser.parse(data[self.column_name])
|
|
11
|
-
if not as_date:
|
|
12
|
-
return f"'{self.column_name}' was not a valid date"
|
|
13
|
-
now = (
|
|
14
|
-
self.datetime.datetime.now() if not as_date.tzinfo else self.datetime.datetime.now(tz=datetime.timezone.utc)
|
|
15
|
-
)
|
|
16
|
-
if as_date < now - self.time_delta:
|
|
17
|
-
human_friendly = self.delta_human_friendly()
|
|
18
|
-
return f"'{self.column_name}' must be at most {human_friendly} in the past."
|
|
19
|
-
return ""
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
from .requirement import Requirement
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class MaximumLength(Requirement):
|
|
5
|
-
maximum_length = None
|
|
6
|
-
|
|
7
|
-
def configure(self, maximum_length):
|
|
8
|
-
if type(maximum_length) != int:
|
|
9
|
-
raise ValueError(
|
|
10
|
-
f"Maximum length must be an int to use the MaximumLength class for column '{self.column_name}'"
|
|
11
|
-
)
|
|
12
|
-
self.maximum_length = maximum_length
|
|
13
|
-
|
|
14
|
-
def check(self, model, data):
|
|
15
|
-
if self.column_name not in data or not data[self.column_name]:
|
|
16
|
-
return ""
|
|
17
|
-
if len(data[self.column_name]) <= self.maximum_length:
|
|
18
|
-
return ""
|
|
19
|
-
return f"'{self.column_name}' must be at most {self.maximum_length} characters long."
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
from .requirement import Requirement
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class MaximumValue(Requirement):
|
|
5
|
-
maximum_value = None
|
|
6
|
-
|
|
7
|
-
def configure(self, maximum_value):
|
|
8
|
-
if type(maximum_value) != int:
|
|
9
|
-
raise ValueError(
|
|
10
|
-
f"Maximum value must be an int to use the MaximumValue class for column '{self.column_name}'"
|
|
11
|
-
)
|
|
12
|
-
self.maximum_value = maximum_value
|
|
13
|
-
|
|
14
|
-
def check(self, model, data):
|
|
15
|
-
if self.column_name not in data or not data[self.column_name]:
|
|
16
|
-
return ""
|
|
17
|
-
if int(data[self.column_name]) <= self.maximum_value:
|
|
18
|
-
return ""
|
|
19
|
-
return f"'{self.column_name}' must be at most {self.maximum_value}."
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
from .requirement import Requirement
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class MinimumLength(Requirement):
|
|
5
|
-
minimum_length = None
|
|
6
|
-
|
|
7
|
-
def configure(self, minimum_length):
|
|
8
|
-
if type(minimum_length) != int:
|
|
9
|
-
raise ValueError(
|
|
10
|
-
f"Minimum length must be an int to use the MinimumLength class for column '{self.column_name}'"
|
|
11
|
-
)
|
|
12
|
-
self.minimum_length = minimum_length
|
|
13
|
-
|
|
14
|
-
def check(self, model, data):
|
|
15
|
-
# If the column isn't in the data then skip this check. Otherwise, setting a minimum length would implicitly
|
|
16
|
-
# make a column required, and this will likely cause more problems than it solves. In short, the minimum
|
|
17
|
-
# length should only apply if data is actually being set
|
|
18
|
-
if self.column_name not in data or not data[self.column_name]:
|
|
19
|
-
return ""
|
|
20
|
-
if len(data[self.column_name]) >= self.minimum_length:
|
|
21
|
-
return ""
|
|
22
|
-
return f"'{self.column_name}' must be at least {self.minimum_length} characters long."
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
from .requirement import Requirement
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class MinimumValue(Requirement):
|
|
5
|
-
minimum_value = None
|
|
6
|
-
|
|
7
|
-
def configure(self, minimum_value):
|
|
8
|
-
if type(minimum_value) != int:
|
|
9
|
-
raise ValueError(
|
|
10
|
-
f"Minimum value must be an int to use the MinimumValue class for column '{self.column_name}'"
|
|
11
|
-
)
|
|
12
|
-
self.minimum_value = minimum_value
|
|
13
|
-
|
|
14
|
-
def check(self, model, data):
|
|
15
|
-
if self.column_name not in data or not data[self.column_name]:
|
|
16
|
-
return ""
|
|
17
|
-
if int(data[self.column_name]) >= self.minimum_value:
|
|
18
|
-
return ""
|
|
19
|
-
return f"'{self.column_name}' must be at least {self.minimum_value}."
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
from abc import ABC, abstractmethod
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class Requirement(ABC):
|
|
5
|
-
_column_name = None
|
|
6
|
-
|
|
7
|
-
@property
|
|
8
|
-
def column_name(self):
|
|
9
|
-
if self._column_name is None:
|
|
10
|
-
raise ValueError("Attempt to get column name on requirement before setting it")
|
|
11
|
-
return self._column_name
|
|
12
|
-
|
|
13
|
-
@column_name.setter
|
|
14
|
-
def column_name(self, column_name):
|
|
15
|
-
self._column_name = column_name
|
|
16
|
-
|
|
17
|
-
def configure(self, *arguments):
|
|
18
|
-
pass
|
|
19
|
-
|
|
20
|
-
@abstractmethod
|
|
21
|
-
def check(self, data):
|
|
22
|
-
pass
|
|
23
|
-
|
|
24
|
-
def additional_write_columns(self, is_create=False):
|
|
25
|
-
return {}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
from .requirement import Requirement
|
|
2
|
-
import datetime
|
|
3
|
-
from collections import OrderedDict
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class TimeDelta(Requirement):
|
|
7
|
-
time_delta = None
|
|
8
|
-
|
|
9
|
-
def __init__(self, datetime):
|
|
10
|
-
self.datetime = datetime
|
|
11
|
-
|
|
12
|
-
def configure(self, time_delta: datetime.timedelta):
|
|
13
|
-
if type(time_delta) != datetime.timedelta:
|
|
14
|
-
raise ValueError(
|
|
15
|
-
"The argument for all time-related input requirement classes is a datetime.timedelta object, but I received something else."
|
|
16
|
-
)
|
|
17
|
-
self.time_delta = time_delta
|
|
18
|
-
self.human_friendly = None
|
|
19
|
-
|
|
20
|
-
def delta_human_friendly(self):
|
|
21
|
-
remainder = int(self.time_delta.total_seconds())
|
|
22
|
-
parts = []
|
|
23
|
-
conversion = OrderedDict(
|
|
24
|
-
[
|
|
25
|
-
("year", 31536000),
|
|
26
|
-
("day", 86400),
|
|
27
|
-
("hour", 3600),
|
|
28
|
-
("minute", 60),
|
|
29
|
-
("second", 1),
|
|
30
|
-
]
|
|
31
|
-
)
|
|
32
|
-
for name, num_seconds in conversion.items():
|
|
33
|
-
if num_seconds > remainder:
|
|
34
|
-
continue
|
|
35
|
-
amount = int(remainder / num_seconds)
|
|
36
|
-
remainder -= amount * num_seconds
|
|
37
|
-
parts.append(f"{amount} {name}" + ("s" if amount != 1 else ""))
|
|
38
|
-
return ", ".join(parts)
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
from .requirement import Requirement
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class Unique(Requirement):
|
|
5
|
-
def check(self, model, data):
|
|
6
|
-
# Unique is mildly tricky. We obviously want to search the backend for the new value,
|
|
7
|
-
# but we need to first skip this if our column is not being set, or if we're editing
|
|
8
|
-
# the model and nothing is changing.
|
|
9
|
-
if self.column_name not in data:
|
|
10
|
-
return ""
|
|
11
|
-
new_value = data[self.column_name]
|
|
12
|
-
if model.exists and model.__getattr__(self.column_name) == new_value:
|
|
13
|
-
return ""
|
|
14
|
-
|
|
15
|
-
matching_model = model.find(f"{self.column_name}={new_value}")
|
|
16
|
-
if matching_model.exists:
|
|
17
|
-
return f"Invalid value for '{self.column_name}': the given value already exists, and must be unique."
|
|
18
|
-
return ""
|
clearskies/mocks/__init__.py
DELETED
clearskies/mocks/input_output.py
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from .. import input_outputs
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class InputOutput(input_outputs.InputOutput):
|
|
6
|
-
_body = None
|
|
7
|
-
_request_method = None
|
|
8
|
-
_script_name = ""
|
|
9
|
-
_path_info = ""
|
|
10
|
-
_query_string = ""
|
|
11
|
-
_content_type = ""
|
|
12
|
-
_protocol = ""
|
|
13
|
-
_query_parameters = None
|
|
14
|
-
_context_specifics = None
|
|
15
|
-
_client_ip = None
|
|
16
|
-
response = None
|
|
17
|
-
|
|
18
|
-
def __init__(
|
|
19
|
-
self,
|
|
20
|
-
request_headers=None,
|
|
21
|
-
body=None,
|
|
22
|
-
request_method="GET",
|
|
23
|
-
request_url="",
|
|
24
|
-
script_name="",
|
|
25
|
-
path_info="",
|
|
26
|
-
query_string="",
|
|
27
|
-
content_type="",
|
|
28
|
-
protocol="",
|
|
29
|
-
query_parameters=None,
|
|
30
|
-
authorization_data=None,
|
|
31
|
-
context_specifics=None,
|
|
32
|
-
client_ip=None,
|
|
33
|
-
):
|
|
34
|
-
self.set_request_method(request_method)
|
|
35
|
-
self.set_body(body)
|
|
36
|
-
self.set_request_headers(request_headers)
|
|
37
|
-
self.set_request_url(request_url, script_name=script_name)
|
|
38
|
-
self._path_info = path_info
|
|
39
|
-
self._query_string = query_string
|
|
40
|
-
self._content_type = content_type
|
|
41
|
-
self._protocol = protocol
|
|
42
|
-
self._query_parameters = query_parameters if query_parameters is not None else {}
|
|
43
|
-
self._authorization_data = authorization_data
|
|
44
|
-
self._context_specifics = context_specifics if context_specifics is not None else {}
|
|
45
|
-
self._client_ip = client_ip if client_ip is not None else "127.0.0.1"
|
|
46
|
-
|
|
47
|
-
def respond(self, body, status_code=200):
|
|
48
|
-
self.response = {"body": body, "status_code": status_code, "headers": self._response_headers}
|
|
49
|
-
return (body, status_code)
|
|
50
|
-
|
|
51
|
-
def get_body(self):
|
|
52
|
-
return self._body
|
|
53
|
-
|
|
54
|
-
def has_body(self):
|
|
55
|
-
return bool(self._body)
|
|
56
|
-
|
|
57
|
-
def set_body(self, body):
|
|
58
|
-
self._body = None
|
|
59
|
-
if body:
|
|
60
|
-
self._body = body if type(body) == str else json.dumps(body)
|
|
61
|
-
|
|
62
|
-
def set_request_url(self, request_url, script_name=""):
|
|
63
|
-
if request_url and script_name:
|
|
64
|
-
raise ValueError("You cannot specify both request_url and script_name")
|
|
65
|
-
self._script_name = request_url if request_url else script_name
|
|
66
|
-
|
|
67
|
-
def get_request_method(self):
|
|
68
|
-
return self._request_method
|
|
69
|
-
|
|
70
|
-
def set_request_method(self, request_method):
|
|
71
|
-
self._request_method = request_method.upper()
|
|
72
|
-
|
|
73
|
-
def set_request_headers(self, request_headers):
|
|
74
|
-
self._request_headers = {}
|
|
75
|
-
if request_headers is None:
|
|
76
|
-
request_headers = {}
|
|
77
|
-
for key, value in request_headers.items():
|
|
78
|
-
self._request_headers[key.lower()] = value
|
|
79
|
-
|
|
80
|
-
def set_query_parameters(self, query_parameters):
|
|
81
|
-
if query_parameters is None:
|
|
82
|
-
self._query_parameters = {}
|
|
83
|
-
else:
|
|
84
|
-
self._query_parameters = query_parameters
|
|
85
|
-
|
|
86
|
-
def get_script_name(self):
|
|
87
|
-
return self._script_name
|
|
88
|
-
|
|
89
|
-
def get_path_info(self):
|
|
90
|
-
return self._path_info
|
|
91
|
-
|
|
92
|
-
def get_query_string(self):
|
|
93
|
-
return self._query_string
|
|
94
|
-
|
|
95
|
-
def get_content_type(self):
|
|
96
|
-
return self._content_type
|
|
97
|
-
|
|
98
|
-
def get_protocol(self):
|
|
99
|
-
return self._protocol
|
|
100
|
-
|
|
101
|
-
def has_request_header(self, header_name):
|
|
102
|
-
return header_name.lower() in self._request_headers
|
|
103
|
-
|
|
104
|
-
def get_request_header(self, header_name, silent=True):
|
|
105
|
-
if not self.has_request_header(header_name):
|
|
106
|
-
if not silent:
|
|
107
|
-
raise ValueError(f"Request header '{header_name}' not found in request")
|
|
108
|
-
return ""
|
|
109
|
-
return self._request_headers[header_name.lower()]
|
|
110
|
-
|
|
111
|
-
def get_query_parameter(self, key):
|
|
112
|
-
return self._query_parameters[key] if key in self._query_parameters else ""
|
|
113
|
-
|
|
114
|
-
def get_query_parameters(self):
|
|
115
|
-
return self._query_parameters
|
|
116
|
-
|
|
117
|
-
def set_context_specifics(self, context_specifics):
|
|
118
|
-
self._context_specifics = context_specifics
|
|
119
|
-
|
|
120
|
-
def context_specifics(self):
|
|
121
|
-
return self._context_specifics
|
|
122
|
-
|
|
123
|
-
def get_client_ip(self):
|
|
124
|
-
return self._client_ip
|
clearskies/mocks/models.py
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
from ..models import Models as ModelsBase
|
|
2
|
-
from ..model import Model as ModelBase
|
|
3
|
-
from ..columns import Columns
|
|
4
|
-
from ..di import StandardDependencies
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class Model(ModelBase):
|
|
8
|
-
_columns_configuration = None
|
|
9
|
-
|
|
10
|
-
def set_columns_configuration(self, columns_configuration):
|
|
11
|
-
self._columns_configuration = columns_configuration
|
|
12
|
-
|
|
13
|
-
def columns_configuration(self):
|
|
14
|
-
return self._columns_configuration
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class Models(ModelsBase):
|
|
18
|
-
_model_configuration = None
|
|
19
|
-
updated = None
|
|
20
|
-
created = None
|
|
21
|
-
deleted = None
|
|
22
|
-
create_responses = None
|
|
23
|
-
update_responses = None
|
|
24
|
-
search_responses = None
|
|
25
|
-
iterating = None
|
|
26
|
-
iterator_index = None
|
|
27
|
-
iterated = None
|
|
28
|
-
counted = None
|
|
29
|
-
|
|
30
|
-
@classmethod
|
|
31
|
-
def reset(cls):
|
|
32
|
-
cls.updated = None
|
|
33
|
-
cls.created = None
|
|
34
|
-
cls.iterated = None
|
|
35
|
-
cls.counted = None
|
|
36
|
-
cls.deleted = None
|
|
37
|
-
|
|
38
|
-
def __init__(self, model_configuration):
|
|
39
|
-
self._model_configuration = model_configuration
|
|
40
|
-
super().__init__(self, Columns(StandardDependencies()))
|
|
41
|
-
|
|
42
|
-
def model(self, data):
|
|
43
|
-
model_class = self.model_class()
|
|
44
|
-
model = model_class(self._backend, self._columns)
|
|
45
|
-
model.set_columns_configuration(self._model_configuration)
|
|
46
|
-
model.data = data
|
|
47
|
-
return model
|
|
48
|
-
|
|
49
|
-
def model_class(self):
|
|
50
|
-
return Model
|
|
51
|
-
|
|
52
|
-
def table_name(self):
|
|
53
|
-
return "mock_model"
|
|
54
|
-
|
|
55
|
-
def blank(self):
|
|
56
|
-
blank = self.__class__(self._model_configuration)
|
|
57
|
-
blank.create_responses = self.create_responses
|
|
58
|
-
blank.update_responses = self.update_responses
|
|
59
|
-
blank.search_responses = self.search_responses
|
|
60
|
-
return blank
|
|
61
|
-
|
|
62
|
-
def add_update_response(self, data):
|
|
63
|
-
if self.update_responses is None:
|
|
64
|
-
self.update_responses = []
|
|
65
|
-
self.update_responses.append(data)
|
|
66
|
-
|
|
67
|
-
def add_create_response(self, data):
|
|
68
|
-
if self.create_responses is None:
|
|
69
|
-
self.create_responses = []
|
|
70
|
-
self.create_responses.append(data)
|
|
71
|
-
|
|
72
|
-
def add_search_response(self, data):
|
|
73
|
-
# We're expecting a list because a search implicitly returns multiple records. Technically, we're also
|
|
74
|
-
# okay with tuples, but this is the most straight-forward way to get what we want and should avoid weird
|
|
75
|
-
# errors without causing serious issues later.
|
|
76
|
-
if type(data) != list:
|
|
77
|
-
raise ValueError("A list should be passed into to 'add_search_response'")
|
|
78
|
-
if self.search_responses is None:
|
|
79
|
-
self.search_responses = []
|
|
80
|
-
self.search_responses.append(data)
|
|
81
|
-
|
|
82
|
-
def clear_search_responses(self):
|
|
83
|
-
self.search_responses = None
|
|
84
|
-
|
|
85
|
-
# our mock models also acts as the backend for the mock model
|
|
86
|
-
def update(self, id, data, model):
|
|
87
|
-
if self.update_responses is None:
|
|
88
|
-
raise ValueError("Must set update data through 'models.add_update_response' before attempting to update")
|
|
89
|
-
if not len(self.update_responses):
|
|
90
|
-
raise ValueError("Ran out of responses while processing an update!")
|
|
91
|
-
if Models.updated is None:
|
|
92
|
-
Models.updated = []
|
|
93
|
-
Models.updated.append({"id": id, "data": data, "model": model})
|
|
94
|
-
return self.update_responses.pop(0)
|
|
95
|
-
|
|
96
|
-
def create(self, data, model):
|
|
97
|
-
if self.create_responses is None:
|
|
98
|
-
raise ValueError("Must set create data through 'models.add_create_response' before attempting to create")
|
|
99
|
-
if not len(self.create_responses):
|
|
100
|
-
raise ValueError("Ran out of responses while processing an create!")
|
|
101
|
-
if Models.created is None:
|
|
102
|
-
Models.created = []
|
|
103
|
-
Models.created.append({"data": data, "model": model})
|
|
104
|
-
return self.create_responses.pop(0)
|
|
105
|
-
|
|
106
|
-
def delete(self, id, model):
|
|
107
|
-
if Models.deleted is None:
|
|
108
|
-
Models.deleted = []
|
|
109
|
-
Models.deleted.append({"id": id, "model": model})
|
|
110
|
-
return True
|
|
111
|
-
|
|
112
|
-
def count(self, configuration, model):
|
|
113
|
-
if self.search_responses is None:
|
|
114
|
-
raise ValueError("Must set search data through 'models.add_search_response' before counting")
|
|
115
|
-
if Models.counted == None:
|
|
116
|
-
Models.counted = []
|
|
117
|
-
del configuration["model_columns"]
|
|
118
|
-
Models.counted.append(configuration)
|
|
119
|
-
counted = self.search_responses.pop(0)
|
|
120
|
-
return len(counted)
|
|
121
|
-
|
|
122
|
-
def records(self, configuration, model, next_page_data=None):
|
|
123
|
-
if self.search_responses is None:
|
|
124
|
-
raise ValueError("Must set search data through 'models.add_search_response' before counting")
|
|
125
|
-
if Models.iterated == None:
|
|
126
|
-
Models.iterated = []
|
|
127
|
-
del configuration["model_columns"]
|
|
128
|
-
Models.iterated.append(configuration)
|
|
129
|
-
records = self.search_responses.pop(0)
|
|
130
|
-
return records
|
|
131
|
-
|
|
132
|
-
def next(self):
|
|
133
|
-
self.iterator_index += 1
|
|
134
|
-
if self.iterator_index >= len(self.iterating):
|
|
135
|
-
raise StopIteration()
|
|
136
|
-
return self.iterating[self.iterator_index]
|
|
137
|
-
|
|
138
|
-
def column_from_backend(self, column, value):
|
|
139
|
-
return column.from_backend(value)
|
|
140
|
-
|
|
141
|
-
def column_to_backend(self, column, backend_data):
|
|
142
|
-
return column.to_backend(backend_data)
|