diff --git a/.ambient-package-update/metadata.py b/.ambient-package-update/metadata.py index 6e1c906..76e3dd6 100644 --- a/.ambient-package-update/metadata.py +++ b/.ambient-package-update/metadata.py @@ -10,19 +10,19 @@ from ambient_package_update.metadata.ruff_ignored_inspection import RuffIgnoredInspection METADATA = PackageMetadata( - package_name='ambient_toolbox', - company='Ambient Innovation: GmbH', + package_name="ambient_toolbox", + company="Ambient Innovation: GmbH", authors=[ PackageAuthor( - name='Ambient Digital', - email='hello@ambient.digital', + name="Ambient Digital", + email="hello@ambient.digital", ), ], - development_status='5 - Production/Stable', + development_status="5 - Production/Stable", license=LICENSE_MIT, license_year=2012, readme_content=ReadmeContent( - tagline='Python toolbox of Ambient Digital containing an abundance of useful tools and gadgets.', + tagline="Python toolbox of Ambient Digital containing an abundance of useful tools and gadgets.", content="""## Features * Useful classes and mixins for Django admin @@ -51,38 +51,38 @@ """, ), dependencies=[ - 'Django>=3.2.20', - 'bleach>=1.4,<6', - 'python-dateutil>=2.5.3', + "Django>=3.2.20", + "bleach>=1.4,<6", + "python-dateutil>=2.5.3", ], supported_django_versions=SUPPORTED_DJANGO_VERSIONS, supported_python_versions=SUPPORTED_PYTHON_VERSIONS, has_migrations=True, optional_dependencies={ - 'dev': [ + "dev": [ *DEV_DEPENDENCIES, - 'gevent~=22.10', + "gevent~=22.10", ], - 'drf': [ - 'djangorestframework>=3.8.2', + "drf": [ + "djangorestframework>=3.8.2", ], - 'graphql': [ - 'graphene-django>=2.2.0', - 'django-graphql-jwt>=0.2.1', + "graphql": [ + "graphene-django>=2.2.0", + "django-graphql-jwt>=0.2.1", ], - 'sentry': [ - 'sentry-sdk>=1.19.1', + "sentry": [ + "sentry-sdk>=1.19.1", ], - 'view-layer': [ - 'django-crispy-forms>=1.4.0', + "view-layer": [ + "django-crispy-forms>=1.4.0", ], }, ruff_ignore_list=[ - RuffIgnoredInspection(key='N999', comment="Project name contains underscore, not fixable"), - RuffIgnoredInspection(key='A003', comment="Django attributes shadow python builtins"), - RuffIgnoredInspection(key='DJ001', comment="Django model text-based fields shouldn't be nullable"), - RuffIgnoredInspection(key='B905', comment="Can be enabled when Python <=3.9 support is dropped"), - RuffIgnoredInspection(key='DTZ001', comment="TODO will affect \"tz_today()\" method"), - RuffIgnoredInspection(key='DTZ005', comment="TODO will affect \"tz_today()\" method"), + RuffIgnoredInspection(key="N999", comment="Project name contains underscore, not fixable"), + RuffIgnoredInspection(key="A003", comment="Django attributes shadow python builtins"), + RuffIgnoredInspection(key="DJ001", comment="Django model text-based fields shouldn't be nullable"), + RuffIgnoredInspection(key="B905", comment="Can be enabled when Python <=3.9 support is dropped"), + RuffIgnoredInspection(key="DTZ001", comment='TODO will affect "tz_today()" method'), + RuffIgnoredInspection(key="DTZ005", comment='TODO will affect "tz_today()" method'), ], ) diff --git a/.coveragerc b/.coveragerc index f50d2ce..6c92442 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,9 +1,9 @@ [run] omit = setup.py, + *_test.py, tests.py, - tests/*, - testapp/*, + *tests*, conftest.py [report] diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1c3cffc..3ec18a7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,18 +2,14 @@ # https://pre-commit.com/ repos: - - repo: https://github.com/psf/black-pre-commit-mirror - rev: 23.10.0 - hooks: - - id: black - args: [ --check, --diff, --config, ./pyproject.toml ] - stages: [ push ] - - - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: 'v0.1.1' + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.3 hooks: + # Run the Ruff linter. - id: ruff - args: [ --fix, --unsafe-fixes, --exit-non-zero-on-fix ] + args: [--fix, --exit-non-zero-on-fix] + # Run the Ruff formatter. + - id: ruff-format - repo: https://github.com/asottile/pyupgrade rev: v3.15.0 diff --git a/CHANGES.md b/CHANGES.md index 9d8c4b7..565ad6f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,7 @@ **9.1.6** (2023-10-31) * Added migration docs to Readme * Added migration check to GitHub actions + * Switched formatter from `black` to `ruff` * Updates from ambient updater * Fixes typos diff --git a/README.md b/README.md index 4580e95..637ba18 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Downloads](https://static.pepy.tech/badge/ambient-toolbox)](https://pepy.tech/project/ambient-toolbox) [![Coverage](https://img.shields.io/badge/Coverage-100%25-success)](https://github.com/ambient-innovation/ambient-toolbox/actions?workflow=CI) [![Linting](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) -[![Coding Style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/python/black) +[![Coding Style](https://img.shields.io/badge/code%20style-Ruff-000000.svg)](https://github.com/astral-sh/ruff) [![Documentation Status](https://readthedocs.org/projects/ambient-toolbox/badge/?version=latest)](https://ambient-toolbox.readthedocs.io/en/latest/?badge=latest) Python toolbox of Ambient Digital containing an abundance of useful tools and gadgets. diff --git a/ambient_toolbox/__init__.py b/ambient_toolbox/__init__.py index d65a5ff..efada71 100644 --- a/ambient_toolbox/__init__.py +++ b/ambient_toolbox/__init__.py @@ -1,3 +1,3 @@ """Python toolbox of Ambient Digital containing an abundance of useful tools and gadgets.""" -__version__ = '9.1.6' +__version__ = "9.1.6" diff --git a/ambient_toolbox/admin/model_admins/classes.py b/ambient_toolbox/admin/model_admins/classes.py index 2516272..eebd983 100644 --- a/ambient_toolbox/admin/model_admins/classes.py +++ b/ambient_toolbox/admin/model_admins/classes.py @@ -14,10 +14,10 @@ def get_readonly_fields(self, request, obj=None): ] return self.readonly_fields - def changeform_view(self, request, object_id=None, form_url='', extra_context=None): + def changeform_view(self, request, object_id=None, form_url="", extra_context=None): extra_context = extra_context or {} - extra_context['show_save_and_continue'] = False - extra_context['show_save'] = False + extra_context["show_save_and_continue"] = False + extra_context["show_save"] = False return super().changeform_view(request, object_id, extra_context=extra_context) def has_add_permission(self, request): @@ -39,8 +39,8 @@ class EditableOnlyAdmin(admin.ModelAdmin): def get_actions(self, request): # Disable delete actions = super().get_actions(request) - if 'delete_selected' in actions: - del actions['delete_selected'] + if "delete_selected" in actions: + del actions["delete_selected"] return actions def has_add_permission(self, request): diff --git a/ambient_toolbox/admin/model_admins/inlines.py b/ambient_toolbox/admin/model_admins/inlines.py index c50a276..e1b7d4e 100644 --- a/ambient_toolbox/admin/model_admins/inlines.py +++ b/ambient_toolbox/admin/model_admins/inlines.py @@ -25,5 +25,5 @@ def get_readonly_fields(self, request, obj=None): + [field.name for field in self.opts.local_many_to_many] ) ) - result.remove('id') + result.remove("id") return result diff --git a/ambient_toolbox/admin/model_admins/mixins.py b/ambient_toolbox/admin/model_admins/mixins.py index 537f5e4..37af0d3 100644 --- a/ambient_toolbox/admin/model_admins/mixins.py +++ b/ambient_toolbox/admin/model_admins/mixins.py @@ -16,7 +16,7 @@ class AdminCreateFormMixin: def get_form(self, request, obj=None, **kwargs): defaults = {} if obj is None: - defaults['form'] = self.add_form + defaults["form"] = self.add_form defaults.update(kwargs) return super().get_form(request, obj, **defaults) @@ -58,7 +58,7 @@ def _resolve_url(request): def get_parent_object_from_request(self, request): resolved = self._resolve_url(request) if resolved.kwargs: - return self.parent_model.objects.get(pk=resolved.kwargs.get('object_id', None)) + return self.parent_model.objects.get(pk=resolved.kwargs.get("object_id", None)) return None def get_formset(self, request, obj=None, **kwargs): @@ -75,7 +75,7 @@ class FetchObjectMixin: def get_object_from_request(self, request): resolved = resolve(request.path_info) if resolved.kwargs: - return self.model.objects.get(pk=resolved.kwargs.get('object_id', None)) + return self.model.objects.get(pk=resolved.kwargs.get("object_id", None)) return None @@ -90,10 +90,10 @@ def get_readonly_fields(self, request, obj=None): Set the fields CommonInfo handles to readonly to avoid users fiddling around with them. """ return super().get_readonly_fields(request, obj) + ( - 'created_by', - 'lastmodified_by', - 'created_at', - 'lastmodified_at', + "created_by", + "lastmodified_by", + "created_at", + "lastmodified_at", ) def get_user_obj(self, request) -> Optional[AbstractUser]: @@ -145,7 +145,7 @@ def change_view(self, request, *args, **kwargs): else: opts = self.model._meta url = reverse( - 'admin:{app}_{model}_changelist'.format( + "admin:{app}_{model}_changelist".format( app=opts.app_label, model=opts.model_name, ) diff --git a/ambient_toolbox/admin/views/forms.py b/ambient_toolbox/admin/views/forms.py index 764e99f..d4e01a0 100644 --- a/ambient_toolbox/admin/views/forms.py +++ b/ambient_toolbox/admin/views/forms.py @@ -9,24 +9,24 @@ class AdminCrispyForm(forms.Form): Base crispy form to be used in custom views within the django admin. """ - section_title = _('No title defined') - button_label = _('Save') + section_title = _("No title defined") + button_label = _("Save") def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Build fieldset - fieldset_list = [''] + fieldset_list = [""] for field in self.fields: - fieldset_list.append(Div(field, css_class='form-row field-name')) # noqa: PERF401 + fieldset_list.append(Div(field, css_class="form-row field-name")) # noqa: PERF401 # Crispy self.helper = FormHelper() - self.helper.form_method = 'post' - self.helper.add_input(Submit('submit', self.button_label, css_class="button btn-primary")) + self.helper.form_method = "post" + self.helper.add_input(Submit("submit", self.button_label, css_class="button btn-primary")) self.helper.layout = Layout( Div( - Div(HTML(f'

{self.section_title}

'), Fieldset(*fieldset_list), css_class='module aligned'), - css_class='custom-form', + Div(HTML(f"

{self.section_title}

"), Fieldset(*fieldset_list), css_class="module aligned"), + css_class="custom-form", ), ) diff --git a/ambient_toolbox/admin/views/mixins.py b/ambient_toolbox/admin/views/mixins.py index 6581455..59fbd1f 100644 --- a/ambient_toolbox/admin/views/mixins.py +++ b/ambient_toolbox/admin/views/mixins.py @@ -8,7 +8,7 @@ class AdminViewMixin: """ model = None - admin_page_title = '' + admin_page_title = "" def has_view_permission(self, user, **kwargs) -> bool: """ @@ -39,23 +39,23 @@ def get_context_data(self, **kwargs): admin_site = self.get_admin_site() context.update( { - 'site_header': admin_site.site_header, - 'site_title': admin_site.site_title, - 'title': self.admin_page_title, - 'name': self.admin_page_title, - 'original': self.admin_page_title, - 'is_nav_sidebar_enabled': True, - 'available_apps': admin.site.get_app_list(self.request), - 'opts': { - 'app_label': self.model._meta.app_label, - 'verbose_name': self.model._meta.verbose_name, - 'verbose_name_plural': self.model._meta.verbose_name_plural, - 'model_name': self.model._meta.model_name, - 'app_config': { - 'verbose_name': self.model._meta.app_config.verbose_name, + "site_header": admin_site.site_header, + "site_title": admin_site.site_title, + "title": self.admin_page_title, + "name": self.admin_page_title, + "original": self.admin_page_title, + "is_nav_sidebar_enabled": True, + "available_apps": admin.site.get_app_list(self.request), + "opts": { + "app_label": self.model._meta.app_label, + "verbose_name": self.model._meta.verbose_name, + "verbose_name_plural": self.model._meta.verbose_name_plural, + "model_name": self.model._meta.model_name, + "app_config": { + "verbose_name": self.model._meta.app_config.verbose_name, }, }, - 'has_permission': admin_site.has_permission(request=self.request), + "has_permission": admin_site.has_permission(request=self.request), } ) return context diff --git a/ambient_toolbox/apps.py b/ambient_toolbox/apps.py index e84b645..b36e674 100644 --- a/ambient_toolbox/apps.py +++ b/ambient_toolbox/apps.py @@ -3,5 +3,5 @@ class AmbientToolboxConfig(AppConfig): - name = 'ambient_toolbox' - verbose_name = _('Ambient Toolbox') + name = "ambient_toolbox" + verbose_name = _("Ambient Toolbox") diff --git a/ambient_toolbox/context_processors.py b/ambient_toolbox/context_processors.py index 4b1652e..75770b9 100644 --- a/ambient_toolbox/context_processors.py +++ b/ambient_toolbox/context_processors.py @@ -2,4 +2,4 @@ def server_settings(request): - return {'DEBUG_MODE': settings.DEBUG, 'SERVER_URL': settings.SERVER_URL} + return {"DEBUG_MODE": settings.DEBUG, "SERVER_URL": settings.SERVER_URL} diff --git a/ambient_toolbox/drf/fields.py b/ambient_toolbox/drf/fields.py index 1fcab78..f9004f2 100644 --- a/ambient_toolbox/drf/fields.py +++ b/ambient_toolbox/drf/fields.py @@ -17,7 +17,7 @@ def to_representation(self, value): # parent serializer. # Explanation: With `many=True` DRF creates an intermediate `ListSerializer`. It has `many=True`, so we'll end # up in the first if-case. If we do not use `many=True`, the "many" attribute is not set. - if getattr(self.parent, 'many', False): + if getattr(self.parent, "many", False): parent = self.parent.parent else: parent = self.parent diff --git a/ambient_toolbox/drf/serializers.py b/ambient_toolbox/drf/serializers.py index 778cba1..c3aa9b8 100644 --- a/ambient_toolbox/drf/serializers.py +++ b/ambient_toolbox/drf/serializers.py @@ -23,12 +23,12 @@ class CommonInfoSerializer(BaseModelSerializer): def validate(self, data): data = super().validate(data) - request = self.context.get('request', None) + request = self.context.get("request", None) if request.user: - data['lastmodified_by'] = request.user + data["lastmodified_by"] = request.user if not self.instance: # If this is a new instance, set created_by - data['created_by'] = request.user + data["created_by"] = request.user return data diff --git a/ambient_toolbox/drf/tests.py b/ambient_toolbox/drf/tests.py index 834b4fe..6b3a3c9 100644 --- a/ambient_toolbox/drf/tests.py +++ b/ambient_toolbox/drf/tests.py @@ -45,12 +45,12 @@ def execute_request( # noqa: PLR0913 *, url, view_kwargs=None, - method='get', + method="get", data=None, view_class=None, user=None, viewset_kwargs=None, - data_format='json', + data_format="json", ) -> Response: """ Helper method which wraps all relevant setup to execute a request to the backends api diff --git a/ambient_toolbox/gitlab/coverage.py b/ambient_toolbox/gitlab/coverage.py index 97ef130..83a928e 100644 --- a/ambient_toolbox/gitlab/coverage.py +++ b/ambient_toolbox/gitlab/coverage.py @@ -18,41 +18,41 @@ def __init__(self) -> None: super().__init__() # Get ENV variables - self.current_pipeline_id: int = int(os.environ.get('CI_PIPELINE_ID')) - self.base_api_url: str = os.environ.get('CI_API_V4_URL') - self.current_branch: str = os.environ.get('CI_COMMIT_REF_NAME') - self.token: str = os.environ.get('GITLAB_CI_COVERAGE_PIPELINE_TOKEN') - self.project_id: int = int(os.environ.get('CI_PROJECT_ID')) - self.job_name: str = os.environ.get('CI_COVERAGE_JOB_NAME', '') - self.target_branch: str = os.environ.get('GITLAB_CI_COVERAGE_TARGET_BRANCH', 'develop') + self.current_pipeline_id: int = int(os.environ.get("CI_PIPELINE_ID")) + self.base_api_url: str = os.environ.get("CI_API_V4_URL") + self.current_branch: str = os.environ.get("CI_COMMIT_REF_NAME") + self.token: str = os.environ.get("GITLAB_CI_COVERAGE_PIPELINE_TOKEN") + self.project_id: int = int(os.environ.get("CI_PROJECT_ID")) + self.job_name: str = os.environ.get("CI_COVERAGE_JOB_NAME", "") + self.target_branch: str = os.environ.get("GITLAB_CI_COVERAGE_TARGET_BRANCH", "develop") self.pipelines_url = ( - f'{self.base_api_url}/projects/{self.project_id}/pipelines?ref={self.target_branch}&status=success' + f"{self.base_api_url}/projects/{self.project_id}/pipelines?ref={self.target_branch}&status=success" ) - self.pipelines_url_with_token = f'{self.pipelines_url}&private_token={self.token}' + self.pipelines_url_with_token = f"{self.pipelines_url}&private_token={self.token}" - self.disable_coverage: bool = os.environ.get('GITLAB_CI_DISABLE_COVERAGE', False) + self.disable_coverage: bool = os.environ.get("GITLAB_CI_DISABLE_COVERAGE", False) def get_latest_target_branch_commit_sha(self) -> str: """ Get the latest commit which is in the current branch and the target compare branch. """ result = subprocess.run( - ['git', 'merge-base', '--fork-point', f'origin/{self.target_branch}'], stdout=subprocess.PIPE, check=True + ["git", "merge-base", "--fork-point", f"origin/{self.target_branch}"], stdout=subprocess.PIPE, check=True ) return result.stdout.decode("utf-8").strip() def get_pipeline_id_by_commit_sha(self, sha: str) -> int | None: - pipeline_url = f'{self.pipelines_url_with_token}&sha={sha}' + pipeline_url = f"{self.pipelines_url_with_token}&sha={sha}" response = httpx.get(pipeline_url) status_code = response.status_code if status_code == HTTPStatus.OK: pipelines = json.loads(response.content) if pipelines and len(pipelines) > 0: - return pipelines[0].get('id', None) + return pipelines[0].get("id", None) else: - print('\n### ERROR: No pipelines found for SHA1 ###\n') - print(f'Pipeline URL: {self.pipelines_url}&sha={sha}') + print("\n### ERROR: No pipelines found for SHA1 ###\n") + print(f"Pipeline URL: {self.pipelines_url}&sha={sha}") print(response.content) return None @@ -60,39 +60,39 @@ def get_coverage_from_pipeline(self, pipeline_id: int, job_name: str) -> (float, """ Get coverage from given pipeline (by id) """ - jobs_url = f'{self.base_api_url}/projects/{self.project_id}/pipelines/{pipeline_id}/jobs' - jobs_with_token_url = f'{jobs_url}?private_token={self.token}' + jobs_url = f"{self.base_api_url}/projects/{self.project_id}/pipelines/{pipeline_id}/jobs" + jobs_with_token_url = f"{jobs_url}?private_token={self.token}" - print(f'Jobs-API-URL: {jobs_url}') + print(f"Jobs-API-URL: {jobs_url}") jobs_response = httpx.get(jobs_with_token_url) jobs_status_code = jobs_response.status_code if jobs_status_code != HTTPStatus.OK: - raise ConnectionError(f'Call to jobs api endpoint failed with status code {jobs_status_code}') + raise ConnectionError(f"Call to jobs api endpoint failed with status code {jobs_status_code}") jobs = json.loads(jobs_response.content) coverages = { - job['name']: {'id': job['id'], 'coverage': float(job['coverage']), 'web_url': job['web_url']} + job["name"]: {"id": job["id"], "coverage": float(job["coverage"]), "web_url": job["web_url"]} for job in jobs - if job.get('coverage') + if job.get("coverage") } - pipeline_url = f'{self.base_api_url}/projects/{self.project_id}/pipelines/{pipeline_id}' - pipeline_with_token_url = f'{pipeline_url}?private_token={self.token}' + pipeline_url = f"{self.base_api_url}/projects/{self.project_id}/pipelines/{pipeline_id}" + pipeline_with_token_url = f"{pipeline_url}?private_token={self.token}" pipeline_response = httpx.get(pipeline_with_token_url) pipeline_status_code = pipeline_response.status_code if pipeline_status_code != HTTPStatus.OK: - raise ConnectionError(f'Call to pipeline api endpoint failed with status code {pipeline_status_code}') + raise ConnectionError(f"Call to pipeline api endpoint failed with status code {pipeline_status_code}") pipeline = json.loads(pipeline_response.content) - coverages_total = float(pipeline['coverage'] if pipeline['coverage'] else 0.0) - print(f'Pipeline-API-URL: {pipeline_url}') + coverages_total = float(pipeline["coverage"] if pipeline["coverage"] else 0.0) + print(f"Pipeline-API-URL: {pipeline_url}") print(f'Pipeline-URL: {pipeline["web_url"]}') - if job_name == '': + if job_name == "": print( - '\033[91mATTN: No CI_COVERAGE_JOB_NAME provided, using Total Coverage and skipping Coverage Diff\033[0m' + "\033[91mATTN: No CI_COVERAGE_JOB_NAME provided, using Total Coverage and skipping Coverage Diff\033[0m" ) return coverages_total, coverages_total, None @@ -101,23 +101,23 @@ def get_coverage_from_pipeline(self, pipeline_id: int, job_name: str) -> (float, print(f'Job-URL: {coverage_job["web_url"]}') job_url = f'{self.base_api_url}/projects/{self.project_id}/jobs/{coverage_job["id"]}/trace' - job_with_token_url = f'{job_url}?private_token={self.token}' + job_with_token_url = f"{job_url}?private_token={self.token}" job_response = httpx.get(job_with_token_url) job_status_code = job_response.status_code if job_status_code != HTTPStatus.OK: - raise ConnectionError(f'Call to job api endpoint failed with status code {job_status_code}') + raise ConnectionError(f"Call to job api endpoint failed with status code {job_status_code}") - print(f'Job-Log-URL: {job_url}') + print(f"Job-Log-URL: {job_url}") job_log = re.search( - r'Name\s+Stmts\s+Miss\s+Branch\s+BrPart\s+Cover\s+Missing.*files skipped due to complete coverage\.', - job_response.content.decode('utf-8'), + r"Name\s+Stmts\s+Miss\s+Branch\s+BrPart\s+Cover\s+Missing.*files skipped due to complete coverage\.", + job_response.content.decode("utf-8"), re.DOTALL | re.MULTILINE, ) # print(job_log.group()) - return coverage_job['coverage'] if coverage_job else 0.0, coverages_total, job_log.group() + return coverage_job["coverage"] if coverage_job else 0.0, coverages_total, job_log.group() @staticmethod def color_text(sign: int, prefix: str, target: float, current: float, diff: float): @@ -135,9 +135,9 @@ def color_text(sign: int, prefix: str, target: float, current: float, diff: floa :return: fully assembled and colored summary text """ change = { - -1: {'text': 'dropped', 'color': '\033[91m'}, - 0: {'text': 'unchanged', 'color': ''}, - 1: {'text': 'climbed', 'color': '\033[92m'}, + -1: {"text": "dropped", "color": "\033[91m"}, + 0: {"text": "unchanged", "color": ""}, + 1: {"text": "climbed", "color": "\033[92m"}, } return ( f'{change[sign]["color"]} {prefix} {change[sign]["text"]} ' @@ -150,31 +150,31 @@ def print_diff(target_job_log, current_job_log): Print a diff between the coverage reports of Current and Target branch """ diff = ndiff(target_job_log.splitlines(keepends=True), current_job_log.splitlines(keepends=True)) - print('\n############################## Coverage Diff ##############################') - print('# \033[91m- Target Branch\033[0m #') - print('# \033[92m+ Current Branch\033[0m #') - print('###########################################################################') + print("\n############################## Coverage Diff ##############################") + print("# \033[91m- Target Branch\033[0m #") + print("# \033[92m+ Current Branch\033[0m #") + print("###########################################################################") for _idx, line in enumerate(diff): match = re.match( - r'^\s*-+\s*$|' - r'^\s*Name\s+Stmts\s+Miss\s+Branch\s+BrPart\s+Cover\s+Missing|' # first line of the report - r'^.*files skipped due to complete coverage.$|' # Final line of the report - r'^[+\-?]', # Line starts with +,-,$ to indicate changes + r"^\s*-+\s*$|" + r"^\s*Name\s+Stmts\s+Miss\s+Branch\s+BrPart\s+Cover\s+Missing|" # first line of the report + r"^.*files skipped due to complete coverage.$|" # Final line of the report + r"^[+\-?]", # Line starts with +,-,$ to indicate changes line, ) if match: - if line[0] == '-': - print('\033[91m', end="") - if line[0] == '+': - print('\033[92m', end="") + if line[0] == "-": + print("\033[91m", end="") + if line[0] == "+": + print("\033[92m", end="") print(line, end="") - if line[0] in ['+', '-']: - print('\033[0m', end="") + if line[0] in ["+", "-"]: + print("\033[0m", end="") - print('\n###########################################################################') - print('# \033[91m- Target Branch\033[0m #') - print('# \033[92m+ Current Branch\033[0m #') - print('############################## Coverage Diff ##############################\n') + print("\n###########################################################################") + print("# \033[91m- Target Branch\033[0m #") + print("# \033[92m+ Current Branch\033[0m #") + print("############################## Coverage Diff ##############################\n") def process(self): """ @@ -184,58 +184,58 @@ def process(self): # Check, if coverage is supposed to run. If not, inform the user and return early. if self.disable_coverage: - print('Coverage was skipped!') + print("Coverage was skipped!") sys.exit(0) - print('\n###########################################################################\n') - print('DEBUG INFO:') + print("\n###########################################################################\n") + print("DEBUG INFO:") # Get the latest commit SHA which is also in develop commit_sha = self.get_latest_target_branch_commit_sha() # Try to find the latest successful pipeline for "TARGET_BRANCH" where our SHA was in - print('Trying base branch for comparison.') + print("Trying base branch for comparison.") target_pipeline_id = None if commit_sha: print(f'Found latest target branch commit SHA "{commit_sha}".') target_pipeline_id = self.get_pipeline_id_by_commit_sha(commit_sha) - print(f'Target branch pipeline ID identified: {target_pipeline_id}.') + print(f"Target branch pipeline ID identified: {target_pipeline_id}.") # Get target pipeline id (from develop branch) if we were not successful the first time if not target_pipeline_id: print("Didn't work. Using default branch for comparison.") response = httpx.get(self.pipelines_url_with_token) status_code = response.status_code - print(f'Pipelines-API-URL: {self.pipelines_url}') + print(f"Pipelines-API-URL: {self.pipelines_url}") # Ensure call did not go sideways if status_code != HTTPStatus.OK: - raise ConnectionError(f'Call to global pipeline api endpoint failed with status code {status_code}') + raise ConnectionError(f"Call to global pipeline api endpoint failed with status code {status_code}") # Read target pipeline ID from content try: - target_pipeline_id = json.loads(response.content)[0]['id'] + target_pipeline_id = json.loads(response.content)[0]["id"] except IndexError: # This happens when there are zero `target_branch` pipelines target_pipeline_id = 0 - print(f'Default branch pipeline ID identified: {target_pipeline_id}.') + print(f"Default branch pipeline ID identified: {target_pipeline_id}.") # Get coverage from target pipeline - print(f'Target Pipeline ID: {target_pipeline_id}') + print(f"Target Pipeline ID: {target_pipeline_id}") target_job_coverage, target_total_coverage, target_job_log = self.get_coverage_from_pipeline( target_pipeline_id, self.job_name ) # Get coverage from this pipeline - print(f'Current pipeline ID: {self.current_pipeline_id}') + print(f"Current pipeline ID: {self.current_pipeline_id}") current_job_coverage, current_total_coverage, current_job_log = self.get_coverage_from_pipeline( self.current_pipeline_id, self.job_name ) if target_job_log is None or current_job_log is None: - print('\n\n\033[91m***************************************************************************\033[0m') - print(' \033[91m**/!\\** Coverage log not found. Skipping diff. **/!\\**\033[0m ') - print('\033[91m***************************************************************************\033[0m\n\n') + print("\n\n\033[91m***************************************************************************\033[0m") + print(" \033[91m**/!\\** Coverage log not found. Skipping diff. **/!\\**\033[0m ") + print("\033[91m***************************************************************************\033[0m\n\n") else: self.print_diff(target_job_log, current_job_log) @@ -250,41 +250,41 @@ def process(self): diff_total_coverage = current_total_coverage - target_total_coverage coverage = { - 'total': { - 'target': target_total_coverage, - 'current': current_total_coverage, - 'sign': sign_total_coverage, - 'diff': diff_total_coverage, - 'prefix': 'Total coverage', + "total": { + "target": target_total_coverage, + "current": current_total_coverage, + "sign": sign_total_coverage, + "diff": diff_total_coverage, + "prefix": "Total coverage", }, - 'job': { - 'target': target_job_coverage, - 'current': current_job_coverage, - 'sign': sign_job_coverage, - 'diff': diff_job_coverage, - 'prefix': 'Job coverage', + "job": { + "target": target_job_coverage, + "current": current_job_coverage, + "sign": sign_job_coverage, + "diff": diff_job_coverage, + "prefix": "Job coverage", }, } # Print results print( self.color_text( - coverage['total']['sign'], - coverage['total']['prefix'], - coverage['total']['target'], - coverage['total']['current'], - coverage['total']['diff'], + coverage["total"]["sign"], + coverage["total"]["prefix"], + coverage["total"]["target"], + coverage["total"]["current"], + coverage["total"]["diff"], ) ) print( self.color_text( - coverage['job']['sign'], - coverage['job']['prefix'], - coverage['job']['target'], - coverage['job']['current'], - coverage['job']['diff'], + coverage["job"]["sign"], + coverage["job"]["prefix"], + coverage["job"]["target"], + coverage["job"]["current"], + coverage["job"]["diff"], ) ) - if coverage['job']['sign'] == -1: + if coverage["job"]["sign"] == -1: sys.exit(1) diff --git a/ambient_toolbox/graphql/forms/mutations.py b/ambient_toolbox/graphql/forms/mutations.py index 42211e3..c667672 100644 --- a/ambient_toolbox/graphql/forms/mutations.py +++ b/ambient_toolbox/graphql/forms/mutations.py @@ -30,7 +30,7 @@ def on_resolve(payload): result = cls.mutate_and_get_payload(root, info, **input) if result.errors: - err_msg = '' + err_msg = "" for err in result.errors: err_msg += f"Field '{err.field}': {err.messages[0]} " @@ -42,7 +42,7 @@ def on_resolve(payload): return on_resolve(result) -@method_decorator(login_required, name='perform_mutate') +@method_decorator(login_required, name="perform_mutate") class LoginRequiredDjangoModelFormMutation(DjangoValidatedModelFormMutation): """ Ensures that you need to be logged in with GraphQL JWT (json web token) authentication diff --git a/ambient_toolbox/graphql/schemes/mutations.py b/ambient_toolbox/graphql/schemes/mutations.py index 983cef8..350de85 100644 --- a/ambient_toolbox/graphql/schemes/mutations.py +++ b/ambient_toolbox/graphql/schemes/mutations.py @@ -21,7 +21,7 @@ class Input: @classmethod def __init_subclass_with_meta__(cls, resolver=None, output=None, arguments=None, _meta=None, model=None, **options): if not model: - raise AttributeError('DeleteMutation needs a valid model to be set.') + raise AttributeError("DeleteMutation needs a valid model to be set.") super().__init_subclass_with_meta__(resolver, output, arguments, _meta, **options) cls.model = model @@ -45,10 +45,10 @@ def mutate_and_get_payload(cls, root, info, **input_data): Ensure custom validation, fetch object and delete it afterwards. """ if not cls.validate(info.context): - raise GraphQLError('Delete method not allowed.') + raise GraphQLError("Delete method not allowed.") # Get object id - object_id = int(input_data.get('id', None)) + object_id = int(input_data.get("id", None)) # Find and delete object obj = cls.get_queryset(info.context).get(pk=object_id) @@ -58,7 +58,7 @@ def mutate_and_get_payload(cls, root, info, **input_data): return DeleteMutation() -@method_decorator(login_required, name='mutate_and_get_payload') +@method_decorator(login_required, name="mutate_and_get_payload") class LoginRequiredDeleteMutation(DeleteMutation): """ Deletes an object from the database. diff --git a/ambient_toolbox/graphql/sentry/utils.py b/ambient_toolbox/graphql/sentry/utils.py index 3a0290d..73b20ef 100644 --- a/ambient_toolbox/graphql/sentry/utils.py +++ b/ambient_toolbox/graphql/sentry/utils.py @@ -9,4 +9,4 @@ def ignore_graphene_logger(): Test for: * sentry_sdk >= 0.13.0 """ - ignore_logger('graphql.execution.utils') + ignore_logger("graphql.execution.utils") diff --git a/ambient_toolbox/graphql/tests/base_test.py b/ambient_toolbox/graphql/tests/base_test.py index 9c7a293..5a7ce03 100644 --- a/ambient_toolbox/graphql/tests/base_test.py +++ b/ambient_toolbox/graphql/tests/base_test.py @@ -9,7 +9,7 @@ class GraphQLTestCase(TestCase): """ # URL to graphql endpoint - GRAPHQL_URL = '/graphql/' + GRAPHQL_URL = "/graphql/" # Here you need to set your graphql schema for the tests GRAPHQL_SCHEMA = None @@ -18,7 +18,7 @@ def setUpClass(cls): super().setUpClass() if not cls.GRAPHQL_SCHEMA: - raise AttributeError('Variable GRAPHQL_SCHEMA not defined in GraphQLTestCase.') + raise AttributeError("Variable GRAPHQL_SCHEMA not defined in GraphQLTestCase.") cls._client = Client(cls.GRAPHQL_SCHEMA) @@ -31,13 +31,13 @@ def query(self, query: str, op_name: str = None, input_data: dict = None): :return: Response object from client """ - body = {'query': query} + body = {"query": query} if op_name: - body['operation_name'] = op_name + body["operation_name"] = op_name if input_data: - body['variables'] = {'input': input_data} + body["variables"] = {"input": input_data} - resp = self._client.post(self.GRAPHQL_URL, json.dumps(body), content_type='application/json') + resp = self._client.post(self.GRAPHQL_URL, json.dumps(body), content_type="application/json") return resp def assertResponseNoErrors(self, resp): # noqa: N802 @@ -48,7 +48,7 @@ def assertResponseNoErrors(self, resp): # noqa: N802 """ content = json.loads(resp.content) self.assertEqual(resp.status_code, 200) - self.assertNotIn('errors', list(content.keys())) + self.assertNotIn("errors", list(content.keys())) def assertResponseHasErrors(self, resp): # noqa: N802 """ @@ -56,4 +56,4 @@ def assertResponseHasErrors(self, resp): # noqa: N802 :resp HttpResponse: Response """ content = json.loads(resp.content) - self.assertIn('errors', list(content.keys())) + self.assertIn("errors", list(content.keys())) diff --git a/ambient_toolbox/mail/backends/whitelist_smtp.py b/ambient_toolbox/mail/backends/whitelist_smtp.py index 3127420..e55860c 100644 --- a/ambient_toolbox/mail/backends/whitelist_smtp.py +++ b/ambient_toolbox/mail/backends/whitelist_smtp.py @@ -23,7 +23,7 @@ def get_domain_whitelist() -> list: Getter for configuration variable from the settings. Will return a list of domains: ['ambient.digital', 'ambient.digital'] """ - return getattr(settings, 'EMAIL_BACKEND_DOMAIN_WHITELIST', []) + return getattr(settings, "EMAIL_BACKEND_DOMAIN_WHITELIST", []) @staticmethod def get_email_regex(): @@ -31,8 +31,8 @@ def get_email_regex(): Getter for configuration variable from the settings. Will return a RegEX to match email whitelisted domains. """ - return r'^[\w\-\.]+@(%s)$' % '|'.join(x for x in WhitelistEmailBackend.get_domain_whitelist()).replace( - '.', r'\.' + return r"^[\w\-\.]+@(%s)$" % "|".join(x for x in WhitelistEmailBackend.get_domain_whitelist()).replace( + ".", r"\." ) @staticmethod @@ -56,7 +56,7 @@ def whitify_mail_addresses(mail_address_list: list) -> list: allowed_recipients.append(to) elif WhitelistEmailBackend.get_backend_redirect_address(): # Send not allowed emails to the configured redirect address (with CATCHALL) - allowed_recipients.append(WhitelistEmailBackend.get_backend_redirect_address() % to.replace('@', '_')) + allowed_recipients.append(WhitelistEmailBackend.get_backend_redirect_address() % to.replace("@", "_")) return allowed_recipients def _process_recipients(self, email_messages): diff --git a/ambient_toolbox/management/commands/install_permission_fixtures.py b/ambient_toolbox/management/commands/install_permission_fixtures.py index 8c3b2c7..7038619 100644 --- a/ambient_toolbox/management/commands/install_permission_fixtures.py +++ b/ambient_toolbox/management/commands/install_permission_fixtures.py @@ -18,14 +18,14 @@ def add_arguments(self, parser): ) def handle(self, *args, **options): - dry_run = options.get('dry_run') + dry_run = options.get("dry_run") if dry_run: print('Starting in "dry-run" mode...') try: fixture_declaration_list = settings.GROUP_PERMISSION_FIXTURES except AttributeError: - print('No fixtures found in Django settings.') + print("No fixtures found in Django settings.") fixture_declaration_list = [] for declaration_path in fixture_declaration_list: @@ -34,11 +34,11 @@ def handle(self, *args, **options): assert isinstance( declaration_class, type(GroupPermissionDeclaration) - ), f"Could\'t load group declaration \"{declaration_path}\"." + ), f'Could\'t load group declaration "{declaration_path}".' print(f'> Installing permissions of group "{declaration_class.name}"...') service = PermissionSetupService(group_declaration=declaration_class, dry_run=dry_run) new_permissions, removed_permissions = service.process() - print(f'> Newly installed permissions: {new_permissions}') - print(f'> Removed permissions: {removed_permissions}\n') + print(f"> Newly installed permissions: {new_permissions}") + print(f"> Removed permissions: {removed_permissions}\n") diff --git a/ambient_toolbox/managers.py b/ambient_toolbox/managers.py index 47be914..31431e3 100644 --- a/ambient_toolbox/managers.py +++ b/ambient_toolbox/managers.py @@ -10,13 +10,13 @@ class AbstractPermissionMixin: """ def visible_for(self, user): - raise NotImplementedError('Please implement this method') + raise NotImplementedError("Please implement this method") def editable_for(self, user): - raise NotImplementedError('Please implement this method') + raise NotImplementedError("Please implement this method") def deletable_for(self, user): - raise NotImplementedError('Please implement this method') + raise NotImplementedError("Please implement this method") class AbstractUserSpecificQuerySet(QuerySet, AbstractPermissionMixin): @@ -28,13 +28,13 @@ def default(self, user): return self def visible_for(self, user): - raise NotImplementedError('Please implement this method') + raise NotImplementedError("Please implement this method") def editable_for(self, user): - raise NotImplementedError('Please implement this method') + raise NotImplementedError("Please implement this method") def deletable_for(self, user): - raise NotImplementedError('Please implement this method') + raise NotImplementedError("Please implement this method") class AbstractUserSpecificManager(Manager, AbstractPermissionMixin): diff --git a/ambient_toolbox/middleware/current_request.py b/ambient_toolbox/middleware/current_request.py index ce18c21..8bfe969 100644 --- a/ambient_toolbox/middleware/current_request.py +++ b/ambient_toolbox/middleware/current_request.py @@ -4,7 +4,7 @@ if TYPE_CHECKING: from django.http import HttpRequest, HttpResponse -_request_cv: ContextVar[Optional['HttpRequest']] = ContextVar('request', default=None) +_request_cv: ContextVar[Optional["HttpRequest"]] = ContextVar("request", default=None) class CurrentRequestMiddleware: @@ -12,10 +12,10 @@ class CurrentRequestMiddleware: Middleware which stores the current request in a thread-safe manner. """ - def __init__(self, get_response: Callable[['HttpRequest'], 'HttpResponse']): + def __init__(self, get_response: Callable[["HttpRequest"], "HttpResponse"]): self.get_response = get_response - def __call__(self, request: 'HttpRequest') -> 'HttpResponse': + def __call__(self, request: "HttpRequest") -> "HttpResponse": token = _request_cv.set(request) response = self.get_response(request) _request_cv.reset(token) diff --git a/ambient_toolbox/middleware/current_user.py b/ambient_toolbox/middleware/current_user.py index afbe8fd..277d309 100644 --- a/ambient_toolbox/middleware/current_user.py +++ b/ambient_toolbox/middleware/current_user.py @@ -19,7 +19,7 @@ class CurrentUserMiddleware(CurrentRequestMiddleware): # of one of the next major releases, then fully dropping support for # CurrentUserMiddleware. - def __init__(self, get_response: Callable[['HttpRequest'], 'HttpResponse']): + def __init__(self, get_response: Callable[["HttpRequest"], "HttpResponse"]): warnings.warn( "CurrentUserMiddleware is deprecated. Use CurrentRequestMiddleware instead.", category=DeprecationWarning, diff --git a/ambient_toolbox/mixins/bleacher.py b/ambient_toolbox/mixins/bleacher.py index bd8dcd7..021e814 100644 --- a/ambient_toolbox/mixins/bleacher.py +++ b/ambient_toolbox/mixins/bleacher.py @@ -32,35 +32,35 @@ class BleacherMixin: BLEACH_FIELD_LIST = [] DEFAULT_ALLOWED_ATTRIBUTES = { - '*': ['class', 'style', 'id'], - 'a': ['href', 'rel'], - 'img': ['alt', 'src'], + "*": ["class", "style", "id"], + "a": ["href", "rel"], + "img": ["alt", "src"], } DEFAULT_ALLOWED_TAGS = bleach.ALLOWED_TAGS + [ - 'span', - 'p', - 'h1', - 'h2', - 'h3', - 'h4', - 'h5', - 'h6', - 'img', - 'div', - 'u', - 'br', - 'blockquote', + "span", + "p", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "img", + "div", + "u", + "br", + "blockquote", ] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields_to_bleach = getattr(self, 'BLEACH_FIELD_LIST', []) - self.allowed_tags = getattr(self, 'ALLOWED_TAGS', self.DEFAULT_ALLOWED_TAGS) - self.allowed_attributes = getattr(self, 'ALLOWED_ATTRIBUTES', self.DEFAULT_ALLOWED_ATTRIBUTES) + self.fields_to_bleach = getattr(self, "BLEACH_FIELD_LIST", []) + self.allowed_tags = getattr(self, "ALLOWED_TAGS", self.DEFAULT_ALLOWED_TAGS) + self.allowed_attributes = getattr(self, "ALLOWED_ATTRIBUTES", self.DEFAULT_ALLOWED_ATTRIBUTES) def _bleach_field(self, field_name): - str_to_bleach = getattr(self, field_name, '') + str_to_bleach = getattr(self, field_name, "") if str_to_bleach: cleaned_value = bleach.clean(str_to_bleach, tags=self.allowed_tags, attributes=self.allowed_attributes) setattr(self, field_name, cleaned_value) diff --git a/ambient_toolbox/models.py b/ambient_toolbox/models.py index 0106686..3c311e5 100644 --- a/ambient_toolbox/models.py +++ b/ambient_toolbox/models.py @@ -57,7 +57,7 @@ def save(self, force_insert=False, force_update=False, using=None, update_fields # Handle case that somebody only wants to update some fields if update_fields is not None and self.ALWAYS_UPDATE_FIELDS: - update_fields = {'lastmodified_at', 'lastmodified_by', 'created_at', 'created_by'}.union(update_fields) + update_fields = {"lastmodified_at", "lastmodified_by", "created_at", "created_by"}.union(update_fields) super().save( force_insert=force_insert, diff --git a/ambient_toolbox/permissions/fixtures/helpers.py b/ambient_toolbox/permissions/fixtures/helpers.py index fe69f28..f2e29c4 100644 --- a/ambient_toolbox/permissions/fixtures/helpers.py +++ b/ambient_toolbox/permissions/fixtures/helpers.py @@ -3,8 +3,8 @@ def generate_default_permissions(model_name: str) -> List[str]: return [ - f'add_{model_name}', - f'change_{model_name}', - f'delete_{model_name}', - f'view_{model_name}', + f"add_{model_name}", + f"change_{model_name}", + f"delete_{model_name}", + f"view_{model_name}", ] diff --git a/ambient_toolbox/permissions/fixtures/services.py b/ambient_toolbox/permissions/fixtures/services.py index 99c0eff..60dc84a 100644 --- a/ambient_toolbox/permissions/fixtures/services.py +++ b/ambient_toolbox/permissions/fixtures/services.py @@ -48,7 +48,7 @@ def process(self) -> (List[Permission], List[Permission]): # Add permission object to list if new_permission in defined_permission_list: - raise ValueError(f'Permission {new_permission} declared twice.') + raise ValueError(f"Permission {new_permission} declared twice.") defined_permission_list.append(new_permission) # Check if permission is already set in the group diff --git a/ambient_toolbox/sentry/helpers.py b/ambient_toolbox/sentry/helpers.py index 45f0db7..c4c33c1 100644 --- a/ambient_toolbox/sentry/helpers.py +++ b/ambient_toolbox/sentry/helpers.py @@ -22,11 +22,11 @@ def __init__(self, denylist: Optional[List[str]] = None, standard_denylist: Opti self.denylist = [] if denylist is None else denylist self.standard_denylist = ( [ - 'username', - 'email', - 'ip_address', - 'serializer', - 'admin', + "username", + "email", + "ip_address", + "serializer", + "admin", ] if standard_denylist else [] @@ -49,15 +49,15 @@ def strip_sensitive_data_from_sentry_event(event, hint): Requires "sentry-sdk>=1.5.0" to work. """ try: - del event['user']['username'] + del event["user"]["username"] except KeyError: pass try: - del event['user']['email'] + del event["user"]["email"] except KeyError: pass try: - del event['user']['ip_address'] + del event["user"]["ip_address"] except KeyError: pass return event diff --git a/ambient_toolbox/services/custom_scrubber.py b/ambient_toolbox/services/custom_scrubber.py index 50b3dfd..6432290 100644 --- a/ambient_toolbox/services/custom_scrubber.py +++ b/ambient_toolbox/services/custom_scrubber.py @@ -13,7 +13,7 @@ class ScrubbingError(RuntimeError): class AbstractScrubbingService: - DEFAULT_USER_PASSWORD = 'Admin0404!' + DEFAULT_USER_PASSWORD = "Admin0404!" # Overwritable values keep_session_data = False @@ -23,32 +23,32 @@ class AbstractScrubbingService: post_scrub_functions = [] def __init__(self): - self._logger = logging.getLogger('django_scrubber') + self._logger = logging.getLogger("django_scrubber") def _get_hashed_default_password(self): return make_password(self.DEFAULT_USER_PASSWORD) def _validation(self): if not settings.DEBUG: - self._logger.warning('Attention! Has to run in DEBUG mode!') + self._logger.warning("Attention! Has to run in DEBUG mode!") return False - if 'django_scrubber' not in settings.INSTALLED_APPS: - self._logger.warning('Attention! django-scrubber needs to be installed!') + if "django_scrubber" not in settings.INSTALLED_APPS: + self._logger.warning("Attention! django-scrubber needs to be installed!") return False - if 'django_scrubber' not in list(settings.LOGGING['loggers'].keys()): - self._logger.warning('Attention! Logging for django-scrubber is not activated!') + if "django_scrubber" not in list(settings.LOGGING["loggers"].keys()): + self._logger.warning("Attention! Logging for django-scrubber is not activated!") return True def process(self): - self._logger.info('Start scrubbing process...') + self._logger.info("Start scrubbing process...") - self._logger.info('Validating setup...') + self._logger.info("Validating setup...") if not self._validation(): - self._logger.warning('Aborting process!') - raise ScrubbingError('Scrubber settings validation failed') + self._logger.warning("Aborting process!") + raise ScrubbingError("Scrubber settings validation failed") # Custom pre-scrubbing for name in self.pre_scrub_functions: @@ -57,7 +57,7 @@ def process(self): method() self._logger.info('Scrubbing data with "scrub_data"...') - call_command('scrub_data') + call_command("scrub_data") # Custom post-scrubbing for name in self.post_scrub_functions: @@ -81,9 +81,9 @@ def process(self): self._logger.info('Clearing data from "django_scrubber_fakedata" ...') # We truncate and don't scrub because the table is huge and clearing on object-level might take a while. # Furthermore can we avoid having a direct dependency to django-scrubber this way. - cursor = connections['default'].cursor() - cursor.execute('TRUNCATE TABLE django_scrubber_fakedata;') + cursor = connections["default"].cursor() + cursor.execute("TRUNCATE TABLE django_scrubber_fakedata;") - self._logger.info('Scrubbing finished!') + self._logger.info("Scrubbing finished!") return True diff --git a/ambient_toolbox/templatetags/ai_email_tags.py b/ambient_toolbox/templatetags/ai_email_tags.py index 303b6b2..13b6018 100644 --- a/ambient_toolbox/templatetags/ai_email_tags.py +++ b/ambient_toolbox/templatetags/ai_email_tags.py @@ -6,7 +6,7 @@ def obfuscate_string(value): - return ''.join([f'&#{str(ord(char)):s};' for char in value]) + return "".join([f"&#{str(ord(char)):s};" for char in value]) @register.filter @@ -25,4 +25,4 @@ def obfuscate_mailto(value, text=False): else: link_text = mail - return mark_safe('{:s}'.format(obfuscate_string('mailto:'), mail, link_text)) + return mark_safe('{:s}'.format(obfuscate_string("mailto:"), mail, link_text)) diff --git a/ambient_toolbox/templatetags/ai_file_tags.py b/ambient_toolbox/templatetags/ai_file_tags.py index 45c6f04..5a208eb 100644 --- a/ambient_toolbox/templatetags/ai_file_tags.py +++ b/ambient_toolbox/templatetags/ai_file_tags.py @@ -17,7 +17,7 @@ def filename(value, max_length=25): """ name = os.path.basename(value.url) if len(name) > max_length: - ext = name.split('.')[-1] + ext = name.split(".")[-1] name = f"{name[:max_length]}[..].{ext}" return name diff --git a/ambient_toolbox/templatetags/ai_number_tags.py b/ambient_toolbox/templatetags/ai_number_tags.py index 8ae142b..bfc4fe1 100644 --- a/ambient_toolbox/templatetags/ai_number_tags.py +++ b/ambient_toolbox/templatetags/ai_number_tags.py @@ -3,7 +3,7 @@ register = template.Library() -@register.filter(name='multiply') +@register.filter(name="multiply") def multiply(value, arg): """ Multiplies the arg and the value @@ -16,7 +16,7 @@ def multiply(value, arg): return None -@register.filter(name='subtract') +@register.filter(name="subtract") def subtract(value, arg): """ Subtracts the arg from the value @@ -26,7 +26,7 @@ def subtract(value, arg): return int(value) - int(arg) -@register.filter(name='divide') +@register.filter(name="divide") def divide(value, arg): """ Divides the value by the arg @@ -37,7 +37,7 @@ def divide(value, arg): return None -@register.filter(name='to_int') +@register.filter(name="to_int") def to_int(value): """ Parses a string to int value diff --git a/ambient_toolbox/templatetags/ai_object_tags.py b/ambient_toolbox/templatetags/ai_object_tags.py index 3f95a27..75b5aea 100644 --- a/ambient_toolbox/templatetags/ai_object_tags.py +++ b/ambient_toolbox/templatetags/ai_object_tags.py @@ -12,9 +12,9 @@ def dict_key_lookup(the_dict, key): :param key: :return: str """ - return the_dict.get(key, '') + return the_dict.get(key, "") -@register.filter(name='label') +@register.filter(name="label") def label(value): return value.field.__class__.__name__ diff --git a/ambient_toolbox/templatetags/ai_string_tags.py b/ambient_toolbox/templatetags/ai_string_tags.py index 25f9f99..3227bcf 100644 --- a/ambient_toolbox/templatetags/ai_string_tags.py +++ b/ambient_toolbox/templatetags/ai_string_tags.py @@ -4,7 +4,7 @@ register = template.Library() -@register.filter(name='get_first_char') +@register.filter(name="get_first_char") def get_first_char(value): """ Returns the first char of the given string @@ -14,7 +14,7 @@ def get_first_char(value): return value[:1] -@register.filter(name='concat') +@register.filter(name="concat") def concat(obj, value: str) -> str: """ Concatenates the two given strings diff --git a/ambient_toolbox/tests/mixins.py b/ambient_toolbox/tests/mixins.py index 250db7c..de7a1ae 100644 --- a/ambient_toolbox/tests/mixins.py +++ b/ambient_toolbox/tests/mixins.py @@ -35,8 +35,8 @@ def _get_response(self, method, user, data, url_params=None, *args, **kwargs): factory = self.factory_class() req_kwargs = {} if data: - req_kwargs.update({'data': data}) - request = getattr(factory, method)('/', **req_kwargs) + req_kwargs.update({"data": data}) + request = getattr(factory, method)("/", **req_kwargs) # Annotate a request object with a session middleware = SessionMiddleware(get_response=HttpResponse(status=200)) @@ -55,15 +55,15 @@ def _get_response(self, method, user, data, url_params=None, *args, **kwargs): def get(self, user=None, data=None, url_params=None, *args, **kwargs): """Returns response for a GET request.""" - return self._get_response('get', user, data, url_params, *args, **kwargs) + return self._get_response("get", user, data, url_params, *args, **kwargs) def post(self, user=None, data=None, url_params=None, *args, **kwargs): """Returns response for a POST request.""" - return self._get_response('post', user, data, url_params, *args, **kwargs) + return self._get_response("post", user, data, url_params, *args, **kwargs) def delete(self, user=None, data=None, url_params=None, *args, **kwargs): """Returns response for a DELETE request.""" - return self._get_response('delete', user, data, url_params, *args, **kwargs) + return self._get_response("delete", user, data, url_params, *args, **kwargs) class RequestProviderMixin: @@ -75,13 +75,13 @@ class RequestProviderMixin: @staticmethod def get_request( - user: Union[AbstractBaseUser, AnonymousUser, None] = None, method: str = 'GET', url: Optional[str] = None + user: Union[AbstractBaseUser, AnonymousUser, None] = None, method: str = "GET", url: Optional[str] = None ): """ Creates and returns a django request. """ # Determine URL - url = url if url else '/' + url = url if url else "/" # Create test request factory = RequestFactory() @@ -92,7 +92,7 @@ def get_request( if user is None or isinstance(user, AbstractBaseUser) or isinstance(user, AnonymousUser): # noqa: PLR1701 request.user = user else: - raise ValueError(_('Please pass a user object to RequestProviderMixin.')) + raise ValueError(_("Please pass a user object to RequestProviderMixin.")) # Annotate a request object with a session session_middleware = SessionMiddleware(get_response=HttpResponse(status=200)) diff --git a/ambient_toolbox/tests/structure_validator/settings.py b/ambient_toolbox/tests/structure_validator/settings.py index 315164a..7460e17 100644 --- a/ambient_toolbox/tests/structure_validator/settings.py +++ b/ambient_toolbox/tests/structure_validator/settings.py @@ -5,7 +5,7 @@ try: TEST_STRUCTURE_VALIDATOR_BASE_DIR = settings.BASE_DIR except AttributeError: - TEST_STRUCTURE_VALIDATOR_BASE_DIR = '' -TEST_STRUCTURE_VALIDATOR_BASE_APP_NAME = 'apps' + TEST_STRUCTURE_VALIDATOR_BASE_DIR = "" +TEST_STRUCTURE_VALIDATOR_BASE_APP_NAME = "apps" TEST_STRUCTURE_VALIDATOR_APP_LIST = settings.INSTALLED_APPS TEST_STRUCTURE_VALIDATOR_IGNORED_DIRECTORY_LIST = [] diff --git a/ambient_toolbox/tests/structure_validator/test_structure_validator.py b/ambient_toolbox/tests/structure_validator/test_structure_validator.py index 8b895e6..680f478 100644 --- a/ambient_toolbox/tests/structure_validator/test_structure_validator.py +++ b/ambient_toolbox/tests/structure_validator/test_structure_validator.py @@ -18,7 +18,7 @@ def __init__(self): @staticmethod def _get_file_whitelist() -> list: - default_whitelist = ['__init__'] + default_whitelist = ["__init__"] try: return default_whitelist + settings.TEST_STRUCTURE_VALIDATOR_FILE_WHITELIST except AttributeError: @@ -40,7 +40,7 @@ def _get_base_app_name() -> str: @staticmethod def _get_ignored_directory_list() -> list: - default_dir_list = ['__pycache__'] + default_dir_list = ["__pycache__"] try: return default_dir_list + settings.TEST_STRUCTURE_VALIDATOR_IGNORED_DIRECTORY_LIST except AttributeError: @@ -54,21 +54,21 @@ def _get_app_list() -> Union[list, tuple]: return toolbox_settings.TEST_STRUCTURE_VALIDATOR_APP_LIST def _check_missing_test_prefix(self, *, root: str, file: str, filename: str, extension: str) -> bool: - if extension == '.py' and not filename[0:5] == "test_" and filename not in self.file_whitelist: - file_path = f"{root}\\{file}".replace('\\', '/') + if extension == ".py" and not filename[0:5] == "test_" and filename not in self.file_whitelist: + file_path = f"{root}\\{file}".replace("\\", "/") self.issue_list.append(f'Python file without "test_" prefix found: {file_path!r}.') return False return True def _check_missing_init(self, *, root: str, init_found: bool, number_of_py_files: int) -> bool: if not init_found and number_of_py_files > 0: - path = root.replace('\\', '/') + path = root.replace("\\", "/") self.issue_list.append(f"__init__.py missing in {path!r}.") return False return True def _build_path_to_test_package(self, app: str) -> Path: - return self._get_base_dir() / Path(app.replace('.', '/')) / 'tests' + return self._get_base_dir() / Path(app.replace(".", "/")) / "tests" def process(self) -> None: # noqa: PLR0912 backend_package = self._get_base_app_name() @@ -79,7 +79,7 @@ def process(self) -> None: # noqa: PLR0912 continue app_path = self._build_path_to_test_package(app=app) for root, dirs, files in os.walk(app_path): - cleaned_root = root.replace('\\', '/') + cleaned_root = root.replace("\\", "/") print(f"Inspecting {cleaned_root!r}...") init_found = False number_of_py_files = 0 @@ -118,7 +118,7 @@ def process(self) -> None: # noqa: PLR0912 print("=======================") if number_of_issues: - print(f'Checking test structure failed with {number_of_issues} issue(s).') + print(f"Checking test structure failed with {number_of_issues} issue(s).") sys.exit(1) else: print("0 issues detected. Yeah!") diff --git a/ambient_toolbox/utils/date.py b/ambient_toolbox/utils/date.py index fa8b193..62523c3 100644 --- a/ambient_toolbox/utils/date.py +++ b/ambient_toolbox/utils/date.py @@ -66,12 +66,12 @@ def first_day_of_month(source_date: datetime.date) -> datetime.date: def get_formatted_date_str(source_date: Union[datetime.date, datetime.datetime]) -> str: - return source_date.strftime('%d.%m.%Y') + return source_date.strftime("%d.%m.%Y") def get_time_from_seconds(seconds: int) -> str: if seconds < 0: - raise ValueError(_('Seconds must be positive.')) + raise ValueError(_("Seconds must be positive.")) hours = seconds // 3600 minutes = (seconds - (hours * 3600)) // 60 seconds = seconds - ((hours * 3600) + (minutes * 60)) @@ -93,7 +93,7 @@ def get_start_and_end_date_from_calendar_week(year: int, calendar_week: int) -> """ Returns the first and last day of a given calendar week """ - monday = datetime.datetime.strptime(f'{year}-{calendar_week}-1', "%Y-%W-%w").astimezone().date() + monday = datetime.datetime.strptime(f"{year}-{calendar_week}-1", "%Y-%W-%w").astimezone().date() return monday, monday + datetime.timedelta(days=6.9) @@ -124,7 +124,7 @@ def date_month_delta(start_date: datetime.date, end_date: datetime.date) -> floa """ # If `start_date` is greater, this logic doesn't make any sense if start_date > end_date: - raise NotImplementedError('Start date > end date') + raise NotImplementedError("Start date > end date") # Calculate date difference between dates date_diff = (end_date - start_date).days diff --git a/ambient_toolbox/utils/file.py b/ambient_toolbox/utils/file.py index e9a260f..19b59f2 100644 --- a/ambient_toolbox/utils/file.py +++ b/ambient_toolbox/utils/file.py @@ -8,12 +8,12 @@ def get_filename_without_ending(file_path: str) -> str: """ # if filename has file_path parts - if '/' in file_path: - filename = file_path.rsplit('/')[-1] + if "/" in file_path: + filename = file_path.rsplit("/")[-1] else: filename = file_path - return filename.rsplit('.', 1)[0] + return filename.rsplit(".", 1)[0] def crc(file_path: str) -> str: @@ -40,7 +40,7 @@ def md5_checksum(file_path: str) -> str: :param file_path: the file for which the MD5 hashsum should be calculated. :return: returns the MD5 of the file in hexadecimal format. """ - with open(file_path, 'rb') as fh: + with open(file_path, "rb") as fh: m = hashlib.md5() while True: data = fh.read(8192) diff --git a/ambient_toolbox/utils/log_whodid.py b/ambient_toolbox/utils/log_whodid.py index 0b0259e..7fd145f 100644 --- a/ambient_toolbox/utils/log_whodid.py +++ b/ambient_toolbox/utils/log_whodid.py @@ -5,8 +5,8 @@ def log_whodid(obj: models.Model, user) -> None: """ Stores the given user as creator or editor of the given object """ - if hasattr(obj, 'created_by') and obj.created_by is None: + if hasattr(obj, "created_by") and obj.created_by is None: obj.created_by = user - if hasattr(obj, 'lastmodified_by'): + if hasattr(obj, "lastmodified_by"): obj.lastmodified_by = user diff --git a/ambient_toolbox/utils/model.py b/ambient_toolbox/utils/model.py index 3917156..d1c57e3 100644 --- a/ambient_toolbox/utils/model.py +++ b/ambient_toolbox/utils/model.py @@ -12,7 +12,7 @@ def object_to_dict(obj, blacklisted_fields: list = None, include_id: bool = Fals # Add default django primary key to blacklist if not include_id: - blacklisted_fields.append('id') + blacklisted_fields.append("id") data = vars(obj) valid_data = {} @@ -22,7 +22,7 @@ def object_to_dict(obj, blacklisted_fields: list = None, include_id: bool = Fals if type(f) != ForeignKey: valid_fields.append(f.name) else: - valid_fields.append(f'{f.name}_id') + valid_fields.append(f"{f.name}_id") for key, value in list(data.items()): if key in valid_fields and key not in blacklisted_fields: diff --git a/ambient_toolbox/utils/named_tuple.py b/ambient_toolbox/utils/named_tuple.py index 4eaac65..4d6ca31 100644 --- a/ambient_toolbox/utils/named_tuple.py +++ b/ambient_toolbox/utils/named_tuple.py @@ -105,7 +105,7 @@ def get_value_from_tuple_by_key(choices: tuple, key) -> Any: try: return dict(choices)[key] except KeyError: - return '-' + return "-" def get_key_from_tuple_by_value(choices: tuple, value) -> Any: @@ -117,4 +117,4 @@ def get_key_from_tuple_by_value(choices: tuple, value) -> Any: try: return [x[0] for x in choices if x[1] == value][0] except IndexError: - return '-' + return "-" diff --git a/ambient_toolbox/utils/string.py b/ambient_toolbox/utils/string.py index 7fd0e5e..f81c667 100644 --- a/ambient_toolbox/utils/string.py +++ b/ambient_toolbox/utils/string.py @@ -21,13 +21,13 @@ def slugify_file_name(file_name: str, length: int = 40) -> str: Slugify the given file name """ name, ext = os.path.splitext(file_name) - name = smart_str(slugify(name).replace('-', '_')) + name = smart_str(slugify(name).replace("-", "_")) ext = smart_str(slugify(ext)) - result = '{}{}{}'.format(name[:length], "." if ext else "", ext) + result = "{}{}{}".format(name[:length], "." if ext else "", ext) return result -def smart_truncate(text: Optional[str], max_length: int = 100, suffix: str = '...') -> str: +def smart_truncate(text: Optional[str], max_length: int = 100, suffix: str = "...") -> str: """ Returns a string of at most `max_length` characters, cutting only at word-boundaries. If the string was truncated, `suffix` @@ -36,7 +36,7 @@ def smart_truncate(text: Optional[str], max_length: int = 100, suffix: str = '.. can choose a custom suffix. """ if text is None: - return '' + return "" # Return the string itself if length is smaller or equal to the limit if len(text) <= max_length: @@ -46,10 +46,10 @@ def smart_truncate(text: Optional[str], max_length: int = 100, suffix: str = '.. value = text[:max_length] # Break into words and remove the last - words = value.split(' ')[:-1] + words = value.split(" ")[:-1] # Join the words and return - return ' '.join(words) + suffix + return " ".join(words) + suffix def float_to_string(value: Optional[float], replacement: str = "0,00") -> str: @@ -59,7 +59,7 @@ def float_to_string(value: Optional[float], replacement: str = "0,00") -> str: # todo thousand separator would be nice If the passed object is None, it will return `replacement`. """ - return ("%.2f" % value).replace('.', ',') if value is not None else replacement + return ("%.2f" % value).replace(".", ",") if value is not None else replacement def date_to_string(value: Optional[datetime.date], replacement: str = "-", str_format: str = "%d.%m.%Y") -> str: @@ -102,8 +102,8 @@ def encode_to_xml(text: str) -> str: Encodes ampersand, greater and lower characters in a given string to HTML-entities. """ text_str = str(text) - text_str = text_str.replace('&', '&') - text_str = text_str.replace('<', '<') - text_str = text_str.replace('>', '>') + text_str = text_str.replace("&", "&") + text_str = text_str.replace("<", "<") + text_str = text_str.replace(">", ">") return text_str diff --git a/ambient_toolbox/view_layer/form_mixins.py b/ambient_toolbox/view_layer/form_mixins.py index 5730e6c..e678564 100644 --- a/ambient_toolbox/view_layer/form_mixins.py +++ b/ambient_toolbox/view_layer/form_mixins.py @@ -11,12 +11,12 @@ class CrispyLayoutFormMixin: def __init__(self, *args, **kwargs): # Crispy self.helper = FormHelper() - self.helper.form_class = 'form-horizontal form-bordered form-row-stripped' - self.helper.form_method = 'post' - self.helper.add_input(Submit('submit_button', _('Save'))) + self.helper.form_class = "form-horizontal form-bordered form-row-stripped" + self.helper.form_method = "post" + self.helper.add_input(Submit("submit_button", _("Save"))) self.helper.form_tag = True - self.helper.label_class = 'col-md-3' - self.helper.field_class = 'col-md-9' - self.helper.label_size = ' col-md-offset-3' + self.helper.label_class = "col-md-3" + self.helper.field_class = "col-md-9" + self.helper.label_size = " col-md-offset-3" super().__init__(*args, **kwargs) diff --git a/ambient_toolbox/view_layer/formset_mixins.py b/ambient_toolbox/view_layer/formset_mixins.py index 89651f2..d5a7d82 100644 --- a/ambient_toolbox/view_layer/formset_mixins.py +++ b/ambient_toolbox/view_layer/formset_mixins.py @@ -7,6 +7,6 @@ def get_number_of_children(self): # Count all choices which are not being deleted right now no_choices = 0 for form in self.forms: - if getattr(form, 'cleaned_data', None) and not form.cleaned_data.get('DELETE'): + if getattr(form, "cleaned_data", None) and not form.cleaned_data.get("DELETE"): no_choices += 1 return no_choices diff --git a/ambient_toolbox/view_layer/formset_view_mixin.py b/ambient_toolbox/view_layer/formset_view_mixin.py index 704fbee..3eea19b 100644 --- a/ambient_toolbox/view_layer/formset_view_mixin.py +++ b/ambient_toolbox/view_layer/formset_view_mixin.py @@ -13,11 +13,11 @@ class _FormsetMixin: def get_formset_kwargs(self): # may be overridden or extended - return {'instance': self.object} + return {"instance": self.object} def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['formset'] = self.formset_class(**self.get_formset_kwargs()) + context["formset"] = self.formset_class(**self.get_formset_kwargs()) return context def form_valid(self, form, formset): @@ -28,7 +28,7 @@ def form_valid(self, form, formset): formset.instance = self.object formset.save() - if hasattr(self, 'additional_is_valid'): + if hasattr(self, "additional_is_valid"): self.additional_is_valid(form, formset) # Return response (a redirect) @@ -47,8 +47,8 @@ def post(self, request, *args, **kwargs): context = self.get_context_data() # Update form and formset variables - context['form'] = form - context['formset'] = formset + context["form"] = form + context["formset"] = formset # Pass all data to template return render(request, self.get_template_names(), context) diff --git a/ambient_toolbox/view_layer/htmx_mixins.py b/ambient_toolbox/view_layer/htmx_mixins.py index eb54081..2c791fd 100644 --- a/ambient_toolbox/view_layer/htmx_mixins.py +++ b/ambient_toolbox/view_layer/htmx_mixins.py @@ -22,13 +22,13 @@ def dispatch(self, request, *args, **kwargs): # Set redirect header if set if hx_redirect_url: - response['HX-Redirect'] = hx_redirect_url + response["HX-Redirect"] = hx_redirect_url # Set trigger header if set if isinstance(hx_trigger, dict): - response['HX-Trigger'] = json.dumps(hx_trigger) + response["HX-Trigger"] = json.dumps(hx_trigger) elif isinstance(hx_trigger, str): - response['HX-Trigger'] = hx_trigger + response["HX-Trigger"] = hx_trigger # Return augmented response return response diff --git a/ambient_toolbox/view_layer/mixins.py b/ambient_toolbox/view_layer/mixins.py index 586bf0c..bd8e693 100644 --- a/ambient_toolbox/view_layer/mixins.py +++ b/ambient_toolbox/view_layer/mixins.py @@ -11,14 +11,14 @@ class DjangoPermissionRequiredMixin: permission_list = None login_required = True - login_view_name = 'login-view' + login_view_name = "login-view" def __init__(self): super().__init__() if self.permission_list is None: raise RuntimeError( - _('Class-based view using DjangoPermissionRequiredMixin without defining a permission list.') + _("Class-based view using DjangoPermissionRequiredMixin without defining a permission list.") ) def get_login_url(self) -> str: @@ -54,7 +54,7 @@ def dispatch(self, request, *args, **kwargs): # Validate that user has all required permissions if not self.has_permissions(request.user): - return render(request, '403.html', status=403) + return render(request, "403.html", status=403) # If everything goes well, we'll continue to the view return super().dispatch(request, *args, **kwargs) diff --git a/ambient_toolbox/view_layer/tests/mixins.py b/ambient_toolbox/view_layer/tests/mixins.py index 49299e3..ab729ae 100644 --- a/ambient_toolbox/view_layer/tests/mixins.py +++ b/ambient_toolbox/view_layer/tests/mixins.py @@ -24,7 +24,7 @@ def setUpTestData(cls): @classmethod def get_test_user(cls): - return get_user_model().objects.create(username='test_user', email='test.user@ambient-toolbox.com') + return get_user_model().objects.create(username="test_user", email="test.user@ambient-toolbox.com") def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) @@ -33,7 +33,7 @@ def __init__(self, *args, **kwargs) -> None: raise TestSetupConfigurationError(_('BaseViewPermissionTestMixin used without setting a "view_class".')) def get_view_instance( - self, *, user: Union[AbstractBaseUser, AnonymousUser], kwargs: dict = None, method: str = 'GET' + self, *, user: Union[AbstractBaseUser, AnonymousUser], kwargs: dict = None, method: str = "GET" ): """ Creates an instance of the given view class and injects a valid request. @@ -49,8 +49,8 @@ def test_view_class_inherits_mixin(self): def test_permissions_are_equal(self): # Sanity checks - self.assertIsNotNone(self.permission_list, msg='Missing permission list declaration in test.') - self.assertIsNotNone(self.view_class.permission_list, msg='Missing permission list declaration in view.') + self.assertIsNotNone(self.permission_list, msg="Missing permission list declaration in test.") + self.assertIsNotNone(self.view_class.permission_list, msg="Missing permission list declaration in view.") # Assert same amount of permissions self.assertEqual(len(self.permission_list), len(self.view_class.permission_list)) @@ -65,11 +65,11 @@ def test_permissions_are_equal(self): def test_permissions_exist_in_database(self): for permission in self.permission_list: - if '.' not in permission: + if "." not in permission: raise TestSetupConfigurationError( f'View "{self.view_class}" contains ill-formatted permission ' f'"{permission}".' ) - app_label, codename = permission.split('.') + app_label, codename = permission.split(".") permission_qs = Permission.objects.filter(content_type__app_label=app_label, codename=codename) if not permission_qs.exists(): @@ -78,7 +78,7 @@ def test_permissions_exist_in_database(self): ) def test_passes_login_barrier_is_called(self): - with mock.patch.object(self.view_class, 'passes_login_barrier', return_value=False) as mock_method: + with mock.patch.object(self.view_class, "passes_login_barrier", return_value=False) as mock_method: view = self.get_view_instance(user=AnonymousUser()) response = view.dispatch(request=view.request, **view.kwargs) # If a user is not logged in, he'll be forwarded to the login view @@ -87,7 +87,7 @@ def test_passes_login_barrier_is_called(self): mock_method.assert_called_once() def test_has_permissions_is_called(self): - with mock.patch.object(self.view_class, 'has_permissions', return_value=False) as mock_method: + with mock.patch.object(self.view_class, "has_permissions", return_value=False) as mock_method: view = self.get_view_instance(user=self.user) response = view.dispatch(request=view.request, **view.kwargs) self.assertEqual(response.status_code, 403) diff --git a/ambient_toolbox/view_layer/views.py b/ambient_toolbox/view_layer/views.py index 844ffce..5805c58 100644 --- a/ambient_toolbox/view_layer/views.py +++ b/ambient_toolbox/view_layer/views.py @@ -29,7 +29,7 @@ class RequestInFormKwargsMixin: def get_form_kwargs(self): kwargs = super().get_form_kwargs() - kwargs.update({'request': self.request}) + kwargs.update({"request": self.request}) return kwargs @@ -41,7 +41,7 @@ class UserInFormKwargsMixin: def get_form_kwargs(self): kwargs = super().get_form_kwargs() - kwargs.update({'user': self.request.user}) + kwargs.update({"user": self.request.user}) return kwargs @@ -53,7 +53,7 @@ class ToggleView(SingleObjectMixin, generic.View): """ object = None - http_method_names = ('post',) + http_method_names = ("post",) def post(self, request, *args, **kwargs): raise NotImplementedError diff --git a/docs/conf.py b/docs/conf.py index b4b43b5..a38601e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -16,18 +16,18 @@ import django from django.conf import settings -sys.path.insert(0, os.path.abspath('..')) # so that we can access the "ambient_toolbox" package +sys.path.insert(0, os.path.abspath("..")) # so that we can access the "ambient_toolbox" package settings.configure( INSTALLED_APPS=[ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'ambient_toolbox', + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "ambient_toolbox", ], - SECRET_KEY='ASDFjklö123456890', + SECRET_KEY="ASDFjklö123456890", ) django.setup() @@ -35,32 +35,32 @@ # -- Project information ----------------------------------------------------- -project = 'ambient-toolbox' -copyright = '2023, Ambient Innovation: GmbH' # noqa: A001 -author = 'Ambient Innovation: GmbH ' +project = "ambient-toolbox" +copyright = "2023, Ambient Innovation: GmbH" # noqa: A001 +author = "Ambient Innovation: GmbH " version = __version__ release = __version__ # -- General configuration --------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# extensions coming with Sphinx (named "sphinx.ext.*") or your custom # ones. extensions = [ - 'sphinx_rtd_theme', - 'sphinx.ext.autodoc', - 'm2r2', + "sphinx_rtd_theme", + "sphinx.ext.autodoc", + "m2r2", ] -source_suffix = ['.rst', '.md'] +source_suffix = [".rst", ".md"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # -- Options for HTML output ------------------------------------------------- @@ -68,17 +68,17 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -# html_theme = 'alabaster' -html_theme = 'sphinx_rtd_theme' +# html_theme = "alabaster" +html_theme = "sphinx_rtd_theme" html_theme_options = { - 'display_version': False, - 'style_external_links': False, + "display_version": False, + "style_external_links": False, } # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # Set master doc file -master_doc = 'index' +master_doc = "index" diff --git a/manage.py b/manage.py index 1b243ab..9e94ce3 100644 --- a/manage.py +++ b/manage.py @@ -6,7 +6,7 @@ def main(): """Run administrative tasks.""" - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings') + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings") try: from django.core.management import execute_from_command_line except ImportError as exc: @@ -18,5 +18,5 @@ def main(): execute_from_command_line(sys.argv) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/pyproject.toml b/pyproject.toml index 0aadc19..2a3e819 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,12 +44,12 @@ dev = [ 'pytest-mock~=3.10', 'coverage~=7.3', 'pre-commit~=3.5', - 'black~=23.10', + 'ruff~=0.1', 'sphinx==4.2.0', 'sphinx-rtd-theme==1.0.0', 'm2r2==0.3.1', 'mistune<2.0.0', - 'ambient-package-update~=23.10.5', + 'ambient-package-update~=23.10.6', 'gevent~=22.10', ] drf = [ @@ -76,15 +76,6 @@ name = "ambient_toolbox" 'Bugtracker' = 'https://github.com/ambient-innovation/ambient-toolbox/issues' 'Changelog' = 'https://ambient-toolbox.readthedocs.io/en/latest/features/changelog.html' - -[tool.black] -# use force-exclude, so that black also applies exclude when run using pre-commit: https://github.com/psf/black/issues/395 -force-exclude = '''.*/migrations/.*''' -line-length = 120 -multi_line_output = 3 -skip-string-normalization = true -include_trailing_comma = true - [tool.ruff] select = [ "E", # pycodestyle errors @@ -173,6 +164,19 @@ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" # Assume Python 3.12 target-version = "py312" +[tool.ruff.format] +# Like Black, use double quotes for strings. +quote-style = "double" + +# Like Black, indent with spaces, rather than tabs. +indent-style = "space" + +# Like Black, respect magic trailing commas. +skip-magic-trailing-comma = false + +# Like Black, automatically detect the appropriate line ending. +line-ending = "auto" + [tool.tox] legacy_tox_ini = """ [tox] diff --git a/settings.py b/settings.py index 116bd94..7774b84 100644 --- a/settings.py +++ b/settings.py @@ -3,64 +3,64 @@ BASE_PATH = Path(__file__).resolve(strict=True).parent INSTALLED_APPS = ( - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'testapp', + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "testapp", ) DEBUG = False -ALLOWED_HOSTS = ['localhost:8000'] +ALLOWED_HOSTS = ["localhost:8000"] -SECRET_KEY = 'ASDFjklö123456890' +SECRET_KEY = "ASDFjklö123456890" # Routing -ROOT_URLCONF = 'testapp.urls' +ROOT_URLCONF = "testapp.urls" -DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': 'db.sqlite', + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": "db.sqlite", } } TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': ['templates'], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": ["templates"], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", ], - 'debug': True, + "debug": True, }, }, ] MIDDLEWARE = ( - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", ) # Mail backend -EMAIL_BACKEND_DOMAIN_WHITELIST = '' -EMAIL_BACKEND_REDIRECT_ADDRESS = '' +EMAIL_BACKEND_DOMAIN_WHITELIST = "" +EMAIL_BACKEND_REDIRECT_ADDRESS = "" -TIME_ZONE = 'UTC' +TIME_ZONE = "UTC" -LOCALE_PATHS = [str(BASE_PATH) + '/ambient_toolbox/locale'] +LOCALE_PATHS = [str(BASE_PATH) + "/ambient_toolbox/locale"] diff --git a/testapp/api/serializers.py b/testapp/api/serializers.py index 9e01499..7a18592 100644 --- a/testapp/api/serializers.py +++ b/testapp/api/serializers.py @@ -7,6 +7,6 @@ class MySingleSignalModelSerializer(serializers.ModelSerializer): class Meta: model = MySingleSignalModel fields = [ - 'id', - 'value', + "id", + "value", ] diff --git a/testapp/api/urls.py b/testapp/api/urls.py index 5d2a516..24c0724 100644 --- a/testapp/api/urls.py +++ b/testapp/api/urls.py @@ -3,4 +3,4 @@ from testapp.api.views import MySingleSignalModelViewSet model_router = DefaultRouter() -model_router.register(r'my-single-signal-model', MySingleSignalModelViewSet, basename='my-single-signal-model') +model_router.register(r"my-single-signal-model", MySingleSignalModelViewSet, basename="my-single-signal-model") diff --git a/testapp/forms.py b/testapp/forms.py index 1d5eead..96ddefc 100644 --- a/testapp/forms.py +++ b/testapp/forms.py @@ -6,4 +6,4 @@ class CommonInfoBasedModelTestForm(forms.ModelForm): class Meta: model = CommonInfoBasedModel - fields = ('value',) + fields = ("value",) diff --git a/testapp/models.py b/testapp/models.py index 36bc0ad..324a97a 100644 --- a/testapp/models.py +++ b/testapp/models.py @@ -22,7 +22,7 @@ def __str__(self): class ForeignKeyRelatedModel(models.Model): single_signal = models.ForeignKey( - MySingleSignalModel, on_delete=models.CASCADE, related_name='foreign_key_related_models' + MySingleSignalModel, on_delete=models.CASCADE, related_name="foreign_key_related_models" ) objects = GloballyVisibleQuerySet.as_manager() @@ -43,7 +43,7 @@ def __str__(self): return str(self.value) -@receiver(pre_save, sender=MyMultipleSignalModel, dispatch_uid='test.mysinglesignalmodel.increase_value_with_uuid') +@receiver(pre_save, sender=MyMultipleSignalModel, dispatch_uid="test.mysinglesignalmodel.increase_value_with_uuid") def increase_value_with_dispatch_uid(sender, instance, **kwargs): instance.value += 1 @@ -51,7 +51,7 @@ def increase_value_with_dispatch_uid(sender, instance, **kwargs): @receiver(post_save, sender=MyMultipleSignalModel) def send_email(sender, instance, **kwargs): msg = EmailMultiAlternatives( - 'Test Mail', 'I am content', from_email='test@example.com', to=['random.dude@example.com'] + "Test Mail", "I am content", from_email="test@example.com", to=["random.dude@example.com"] ) msg.send() @@ -75,14 +75,14 @@ def __str__(self): class ModelWithFkToSelf(models.Model): - parent = models.ForeignKey('self', blank=True, null=True, related_name='children', on_delete=models.CASCADE) + parent = models.ForeignKey("self", blank=True, null=True, related_name="children", on_delete=models.CASCADE) def __str__(self): return str(self.id) class ModelWithOneToOneToSelf(models.Model): - peer = models.OneToOneField('self', blank=True, null=True, related_name='related_peer', on_delete=models.CASCADE) + peer = models.OneToOneField("self", blank=True, null=True, related_name="related_peer", on_delete=models.CASCADE) def __str__(self): return str(self.id) diff --git a/testapp/permissions.py b/testapp/permissions.py index e83147c..a465a20 100644 --- a/testapp/permissions.py +++ b/testapp/permissions.py @@ -2,11 +2,11 @@ class TestGroupDeclaration(GroupPermissionDeclaration): - name = ('group_1',) + name = ("group_1",) permission_list = [ PermissionModelDeclaration( - app_label='testapp', - codename_list=['view_mysinglesignalmodel'], - model='mysinglesignalmodel', + app_label="testapp", + codename_list=["view_mysinglesignalmodel"], + model="mysinglesignalmodel", ), ] diff --git a/testapp/urls.py b/testapp/urls.py index b24d26b..ca9e2c7 100644 --- a/testapp/urls.py +++ b/testapp/urls.py @@ -10,9 +10,9 @@ urlpatterns = [ # django Admin - path('admin/', admin.site.urls), + path("admin/", admin.site.urls), # REST Viewsets - path('api/v1/', include(router.urls)), + path("api/v1/", include(router.urls)), # Custom login view - path("other/login/", TemplateView.as_view(template_name="testapp/test_template.html"), name='other-login-view'), + path("other/login/", TemplateView.as_view(template_name="testapp/test_template.html"), name="other-login-view"), ] diff --git a/tests/admin/model_admin_mixins/test_admin_common_info_mixin.py b/tests/admin/model_admin_mixins/test_admin_common_info_mixin.py index c27585d..bc5dff9 100644 --- a/tests/admin/model_admin_mixins/test_admin_common_info_mixin.py +++ b/tests/admin/model_admin_mixins/test_admin_common_info_mixin.py @@ -13,7 +13,7 @@ class CommonInfoBasedModelForm(forms.ModelForm): class Meta: model = CommonInfoBasedModel - fields = ('value',) + fields = ("value",) class TestCommonInfoAdminMixinAdmin(CommonInfoAdminMixin, admin.ModelAdmin): @@ -25,7 +25,7 @@ class CommonInfoAdminMixinTest(RequestProviderMixin, TestCase): def setUpTestData(cls): super().setUpTestData() - cls.user = User.objects.create(username='my_user') + cls.user = User.objects.create(username="my_user") cls.request = cls.get_request(cls.user) admin.site.register(CommonInfoBasedModel, TestCommonInfoAdminMixinAdmin) @@ -39,11 +39,11 @@ def tearDownClass(cls): def test_readonly_fields_are_set(self): model_admin = TestCommonInfoAdminMixinAdmin(model=CommonInfoBasedModel, admin_site=admin.site) - self.assertIn('created_by', model_admin.get_readonly_fields(self.request)) - self.assertIn('created_at', model_admin.get_readonly_fields(self.request)) + self.assertIn("created_by", model_admin.get_readonly_fields(self.request)) + self.assertIn("created_at", model_admin.get_readonly_fields(self.request)) - self.assertIn('lastmodified_by', model_admin.get_readonly_fields(self.request)) - self.assertIn('lastmodified_at', model_admin.get_readonly_fields(self.request)) + self.assertIn("lastmodified_by", model_admin.get_readonly_fields(self.request)) + self.assertIn("lastmodified_at", model_admin.get_readonly_fields(self.request)) def test_get_user_obj_regular(self): model_admin = TestCommonInfoAdminMixinAdmin(model=CommonInfoBasedModel, admin_site=admin.site) @@ -61,8 +61,8 @@ def test_created_by_is_set_on_creation(self): def test_created_by_is_not_altered_on_update(self): model_admin = TestCommonInfoAdminMixinAdmin(model=CommonInfoBasedModel, admin_site=admin.site) - other_user = User.objects.create(username='other_user') - with mock.patch.object(CommonInfoBasedModel, 'get_current_user', return_value=other_user): + other_user = User.objects.create(username="other_user") + with mock.patch.object(CommonInfoBasedModel, "get_current_user", return_value=other_user): obj = CommonInfoBasedModel.objects.create(value=1, created_by=other_user, lastmodified_by=other_user) form = CommonInfoBasedModelForm(instance=obj) diff --git a/tests/admin/model_admin_mixins/test_admin_create_form_mixin.py b/tests/admin/model_admin_mixins/test_admin_create_form_mixin.py index 368262c..0c7a44b 100644 --- a/tests/admin/model_admin_mixins/test_admin_create_form_mixin.py +++ b/tests/admin/model_admin_mixins/test_admin_create_form_mixin.py @@ -22,7 +22,7 @@ class AdminCreateFormMixinTest(RequestProviderMixin, TestCase): def setUpTestData(cls): super().setUpTestData() - cls.super_user = User.objects.create(username='super_user', is_superuser=True) + cls.super_user = User.objects.create(username="super_user", is_superuser=True) admin.site.register(ForeignKeyRelatedModel, TestAdminCreateFormMixinAdmin) diff --git a/tests/admin/model_admin_mixins/test_admin_no_inlines_for_create_mixin.py b/tests/admin/model_admin_mixins/test_admin_no_inlines_for_create_mixin.py index a249ffa..0505441 100644 --- a/tests/admin/model_admin_mixins/test_admin_no_inlines_for_create_mixin.py +++ b/tests/admin/model_admin_mixins/test_admin_no_inlines_for_create_mixin.py @@ -20,7 +20,7 @@ class AdminNoInlinesForCreateMixinTest(RequestProviderMixin, TestCase): def setUpTestData(cls): super().setUpTestData() - cls.super_user = User.objects.create(username='super_user', is_superuser=True) + cls.super_user = User.objects.create(username="super_user", is_superuser=True) admin.site.register(MySingleSignalModel, TestAdminNoInlinesForCreateMixinAdmin) diff --git a/tests/admin/model_admin_mixins/test_admin_request_in_form_mixin.py b/tests/admin/model_admin_mixins/test_admin_request_in_form_mixin.py index 4a18390..15d76f1 100644 --- a/tests/admin/model_admin_mixins/test_admin_request_in_form_mixin.py +++ b/tests/admin/model_admin_mixins/test_admin_request_in_form_mixin.py @@ -17,7 +17,7 @@ class AdminRequestInFormMixinTest(RequestProviderMixin, TestCase): def setUpTestData(cls): super().setUpTestData() - cls.super_user = User.objects.create(username='super_user', is_superuser=True) + cls.super_user = User.objects.create(username="super_user", is_superuser=True) admin.site.register(MySingleSignalModel, TestAdminRequestInFormMixinAdmin) diff --git a/tests/admin/model_admin_mixins/test_deactivatable_change_view_admin_mixin.py b/tests/admin/model_admin_mixins/test_deactivatable_change_view_admin_mixin.py index 1cdc7bb..0095d1d 100644 --- a/tests/admin/model_admin_mixins/test_deactivatable_change_view_admin_mixin.py +++ b/tests/admin/model_admin_mixins/test_deactivatable_change_view_admin_mixin.py @@ -33,14 +33,14 @@ def test_can_see_change_view_negative_flag(self): def test_get_list_display_links_can_see_method_called(self): admin_cls = TestAdmin(admin_site=None, model=User) - with mock.patch.object(admin_cls, 'can_see_change_view', return_value=True) as mock_method: - admin_cls.get_list_display_links(request=self.get_request(user=self.user), list_display=('first_name',)) + with mock.patch.object(admin_cls, "can_see_change_view", return_value=True) as mock_method: + admin_cls.get_list_display_links(request=self.get_request(user=self.user), list_display=("first_name",)) mock_method.assert_called_once() def test_get_list_display_links_can_see_method_positive_flag(self): admin_cls = TestAdmin(admin_site=None, model=User) - field_tuple = ('first_name',) + field_tuple = ("first_name",) self.assertEqual( list(field_tuple), admin_cls.get_list_display_links(request=self.get_request(user=self.user), list_display=field_tuple), @@ -50,13 +50,13 @@ def test_get_list_display_links_can_see_method_negative_flag(self): admin_cls = TestAdmin(admin_site=None, model=User) admin_cls.enable_change_view = False self.assertIsNone( - admin_cls.get_list_display_links(request=self.get_request(user=self.user), list_display=('first_name',)) + admin_cls.get_list_display_links(request=self.get_request(user=self.user), list_display=("first_name",)) ) def test_change_view_can_see_method_called_because_of_positive_flag(self): admin_cls = TestAdmin(admin_site=None, model=User) - with mock.patch.object(admin_cls, 'can_see_change_view', return_value=True) as mocked_can_see_method: - with mock.patch('django.contrib.admin.ModelAdmin.change_view') as mocked_base_change_view: + with mock.patch.object(admin_cls, "can_see_change_view", return_value=True) as mocked_can_see_method: + with mock.patch("django.contrib.admin.ModelAdmin.change_view") as mocked_base_change_view: admin_cls.change_view(request=self.get_request(user=self.super_user), object_id=str(self.user.id)) mocked_can_see_method.assert_called_once() @@ -64,8 +64,8 @@ def test_change_view_can_see_method_called_because_of_positive_flag(self): def test_change_view_can_see_method_not_called_because_of_negative_flag(self): admin_cls = TestAdmin(admin_site=None, model=User) - with mock.patch.object(admin_cls, 'can_see_change_view', return_value=False) as mocked_can_see_method: - with mock.patch('django.contrib.admin.ModelAdmin.change_view') as mocked_base_change_view: + with mock.patch.object(admin_cls, "can_see_change_view", return_value=False) as mocked_can_see_method: + with mock.patch("django.contrib.admin.ModelAdmin.change_view") as mocked_base_change_view: admin_cls.change_view(request=self.get_request(user=self.super_user), object_id=str(self.user.id)) mocked_can_see_method.assert_called_once() diff --git a/tests/admin/model_admin_mixins/test_fetch_object_mixin.py b/tests/admin/model_admin_mixins/test_fetch_object_mixin.py index 8d19756..2b919cc 100644 --- a/tests/admin/model_admin_mixins/test_fetch_object_mixin.py +++ b/tests/admin/model_admin_mixins/test_fetch_object_mixin.py @@ -22,7 +22,7 @@ class FetchObjectMixinTest(RequestProviderMixin, TestCase): def setUpTestData(cls): super().setUpTestData() - cls.super_user = User.objects.create(username='super_user', is_superuser=True) + cls.super_user = User.objects.create(username="super_user", is_superuser=True) admin.site.register(MySingleSignalModel, TestFetchObjectMixinAdmin) @@ -39,8 +39,8 @@ def test_model_is_set(self): request = self.get_request(self.super_user) return_obj = MockResolverResponse() - return_obj.kwargs = {'object_id': obj.id} - with mock.patch('ambient_toolbox.admin.model_admins.mixins.resolve', return_value=return_obj): + return_obj.kwargs = {"object_id": obj.id} + with mock.patch("ambient_toolbox.admin.model_admins.mixins.resolve", return_value=return_obj): obj_from_request = model_admin.get_object_from_request(request) self.assertEqual(obj_from_request, obj) diff --git a/tests/admin/model_admin_mixins/test_fetch_parent_object_inline_mixin.py b/tests/admin/model_admin_mixins/test_fetch_parent_object_inline_mixin.py index d13cef6..610881a 100644 --- a/tests/admin/model_admin_mixins/test_fetch_parent_object_inline_mixin.py +++ b/tests/admin/model_admin_mixins/test_fetch_parent_object_inline_mixin.py @@ -26,7 +26,7 @@ class FetchParentObjectInlineMixinTest(RequestProviderMixin, TestCase): def setUpTestData(cls): super().setUpTestData() - cls.super_user = User.objects.create(username='super_user', is_superuser=True) + cls.super_user = User.objects.create(username="super_user", is_superuser=True) admin.site.register(MySingleSignalModel, TestFetchParentObjectInlineMixinAdmin) @@ -48,8 +48,8 @@ def test_parent_model_is_set(self): inline = inline_list[0](parent_model=MySingleSignalModel, admin_site=admin.site) return_obj = MockResolverResponse() - return_obj.kwargs = {'object_id': obj.id} - with mock.patch.object(model_admin.inlines[0], '_resolve_url', return_value=return_obj): + return_obj.kwargs = {"object_id": obj.id} + with mock.patch.object(model_admin.inlines[0], "_resolve_url", return_value=return_obj): inline.get_formset(request=request, obj=obj) self.assertEqual(inline.parent_object, obj) diff --git a/tests/ambient_toolbox/test_test_structure_validator.py b/tests/ambient_toolbox/test_test_structure_validator.py index 9444093..1cfcf79 100644 --- a/tests/ambient_toolbox/test_test_structure_validator.py +++ b/tests/ambient_toolbox/test_test_structure_validator.py @@ -11,21 +11,21 @@ class TestStructureValidatorTest(TestCase): def test_init_regular(self): service = TestStructureValidator() - self.assertEqual(service.file_whitelist, ['__init__']) + self.assertEqual(service.file_whitelist, ["__init__"]) self.assertEqual(service.issue_list, []) - @override_settings(TEST_STRUCTURE_VALIDATOR_FILE_WHITELIST=['my_file']) + @override_settings(TEST_STRUCTURE_VALIDATOR_FILE_WHITELIST=["my_file"]) def test_get_file_whitelist_from_settings(self): service = TestStructureValidator() file_whitelist = service._get_file_whitelist() - self.assertEqual(file_whitelist, ['__init__', 'my_file']) + self.assertEqual(file_whitelist, ["__init__", "my_file"]) def test_get_file_whitelist_fallback(self): service = TestStructureValidator() file_whitelist = service._get_file_whitelist() - self.assertEqual(file_whitelist, ['__init__']) + self.assertEqual(file_whitelist, ["__init__"]) @override_settings(TEST_STRUCTURE_VALIDATOR_BASE_DIR=settings.BASE_PATH) def test_get_base_dir_from_settings(self): @@ -38,27 +38,27 @@ def test_get_base_dir_fallback(self): service = TestStructureValidator() base_dir = service._get_base_dir() - self.assertEqual(base_dir, '') + self.assertEqual(base_dir, "") - @override_settings(TEST_STRUCTURE_VALIDATOR_BASE_APP_NAME='my_project') + @override_settings(TEST_STRUCTURE_VALIDATOR_BASE_APP_NAME="my_project") def test_get_base_app_name_from_settings(self): service = TestStructureValidator() base_app_name = service._get_base_app_name() - self.assertEqual(base_app_name, 'my_project') + self.assertEqual(base_app_name, "my_project") def test_get_base_app_name_fallback(self): service = TestStructureValidator() base_app_name = service._get_base_app_name() - self.assertEqual(base_app_name, 'apps') + self.assertEqual(base_app_name, "apps") - @override_settings(TEST_STRUCTURE_VALIDATOR_APP_LIST=['apps.my_app', 'apps.other_app']) + @override_settings(TEST_STRUCTURE_VALIDATOR_APP_LIST=["apps.my_app", "apps.other_app"]) def test_get_app_list_from_settings(self): service = TestStructureValidator() base_app_name = service._get_app_list() - self.assertEqual(base_app_name, ['apps.my_app', 'apps.other_app']) + self.assertEqual(base_app_name, ["apps.my_app", "apps.other_app"]) def test_get_app_list_fallback(self): service = TestStructureValidator() @@ -66,39 +66,39 @@ def test_get_app_list_fallback(self): self.assertEqual(base_app_name, settings.INSTALLED_APPS) - @override_settings(TEST_STRUCTURE_VALIDATOR_IGNORED_DIRECTORY_LIST=['my_dir', 'other_dir']) + @override_settings(TEST_STRUCTURE_VALIDATOR_IGNORED_DIRECTORY_LIST=["my_dir", "other_dir"]) def test_get_ignored_directory_list_from_settings(self): service = TestStructureValidator() dir_list = service._get_ignored_directory_list() - self.assertEqual(dir_list, ['__pycache__', 'my_dir', 'other_dir']) + self.assertEqual(dir_list, ["__pycache__", "my_dir", "other_dir"]) def test_get_ignored_directory_list_fallback(self): service = TestStructureValidator() dir_list = service._get_ignored_directory_list() - self.assertEqual(dir_list, ['__pycache__']) + self.assertEqual(dir_list, ["__pycache__"]) def test_check_missing_test_prefix_correct_prefix(self): service = TestStructureValidator() result = service._check_missing_test_prefix( - root='root/path', - file='missing_prefix', - filename='test_my_file', - extension='.py', + root="root/path", + file="missing_prefix", + filename="test_my_file", + extension=".py", ) self.assertTrue(result) self.assertEqual(len(service.issue_list), 0) - @override_settings(TEST_STRUCTURE_VALIDATOR_FILE_WHITELIST=['my_file']) + @override_settings(TEST_STRUCTURE_VALIDATOR_FILE_WHITELIST=["my_file"]) def test_check_missing_test_prefix_wrong_prefix_but_whitelisted(self): service = TestStructureValidator() result = service._check_missing_test_prefix( - root='root/path', - file='missing_prefix', - filename='my_file', - extension='.py', + root="root/path", + file="missing_prefix", + filename="my_file", + extension=".py", ) self.assertTrue(result) @@ -107,10 +107,10 @@ def test_check_missing_test_prefix_wrong_prefix_but_whitelisted(self): def test_check_missing_test_prefix_wrong_prefix_but_not_py_file(self): service = TestStructureValidator() result = service._check_missing_test_prefix( - root='root/path', - file='missing_prefix', - filename='missing_prefix', - extension='.txt', + root="root/path", + file="missing_prefix", + filename="missing_prefix", + extension=".txt", ) self.assertTrue(result) @@ -119,10 +119,10 @@ def test_check_missing_test_prefix_wrong_prefix_but_not_py_file(self): def test_check_missing_test_prefix_wrong_prefix(self): service = TestStructureValidator() result = service._check_missing_test_prefix( - root='root/path', - file='missing_prefix', - filename='missing_prefix', - extension='.py', + root="root/path", + file="missing_prefix", + filename="missing_prefix", + extension=".py", ) self.assertFalse(result) @@ -130,54 +130,54 @@ def test_check_missing_test_prefix_wrong_prefix(self): def test_check_missing_init_init_found_files_in_dir(self): service = TestStructureValidator() - result = service._check_missing_init(root='root/path', init_found=True, number_of_py_files=1) + result = service._check_missing_init(root="root/path", init_found=True, number_of_py_files=1) self.assertTrue(result) self.assertEqual(len(service.issue_list), 0) def test_check_missing_init_no_init_no_files(self): service = TestStructureValidator() - result = service._check_missing_init(root='root/path', init_found=False, number_of_py_files=0) + result = service._check_missing_init(root="root/path", init_found=False, number_of_py_files=0) self.assertTrue(result) self.assertEqual(len(service.issue_list), 0) def test_check_missing_init_no_init_but_files(self): service = TestStructureValidator() - result = service._check_missing_init(root='root/path', init_found=False, number_of_py_files=1) + result = service._check_missing_init(root="root/path", init_found=False, number_of_py_files=1) self.assertFalse(result) self.assertEqual(len(service.issue_list), 1) @override_settings( - TEST_STRUCTURE_VALIDATOR_BASE_DIR=Path('/src/ambient_toolbox/'), - TEST_STRUCTURE_VALIDATOR_BASE_APP_NAME='my_project', + TEST_STRUCTURE_VALIDATOR_BASE_DIR=Path("/src/ambient_toolbox/"), + TEST_STRUCTURE_VALIDATOR_BASE_APP_NAME="my_project", ) def test_build_path_to_test_package_with_settings_path(self): service = TestStructureValidator() - path = service._build_path_to_test_package(app='my_project.my_app') + path = service._build_path_to_test_package(app="my_project.my_app") - self.assertEqual(path, Path('/src/ambient_toolbox/my_project/my_app/tests')) + self.assertEqual(path, Path("/src/ambient_toolbox/my_project/my_app/tests")) @override_settings( - TEST_STRUCTURE_VALIDATOR_BASE_DIR='/src/ambient_toolbox/', TEST_STRUCTURE_VALIDATOR_BASE_APP_NAME='my_project' + TEST_STRUCTURE_VALIDATOR_BASE_DIR="/src/ambient_toolbox/", TEST_STRUCTURE_VALIDATOR_BASE_APP_NAME="my_project" ) def test_build_path_to_test_package_with_settings_str(self): service = TestStructureValidator() - path = service._build_path_to_test_package(app='my_project.my_app') + path = service._build_path_to_test_package(app="my_project.my_app") - self.assertEqual(path, Path('/src/ambient_toolbox/my_project/my_app/tests')) + self.assertEqual(path, Path("/src/ambient_toolbox/my_project/my_app/tests")) def test_build_path_to_test_package_with_defaults(self): service = TestStructureValidator() - path = service._build_path_to_test_package(app='my_project.my_app') + path = service._build_path_to_test_package(app="my_project.my_app") - self.assertEqual(path, Path('my_project/my_app/tests')) + self.assertEqual(path, Path("my_project/my_app/tests")) @override_settings( TEST_STRUCTURE_VALIDATOR_BASE_DIR=settings.BASE_PATH, - TEST_STRUCTURE_VALIDATOR_APP_LIST=['testapp'], - TEST_STRUCTURE_VALIDATOR_BASE_APP_NAME='', + TEST_STRUCTURE_VALIDATOR_APP_LIST=["testapp"], + TEST_STRUCTURE_VALIDATOR_BASE_APP_NAME="", ) def test_process_functional(self): service = TestStructureValidator() @@ -189,12 +189,12 @@ def test_process_functional(self): complaint_list = sorted(service.issue_list) self.assertIn('Python file without "test_" prefix found:', complaint_list[0]) - self.assertIn('testapp/tests/subdirectory/missing_test_prefix.py', complaint_list[0]) + self.assertIn("testapp/tests/subdirectory/missing_test_prefix.py", complaint_list[0]) - self.assertIn('__init__.py missing in', complaint_list[1]) - self.assertIn('testapp/tests/missing_init', complaint_list[1]) + self.assertIn("__init__.py missing in", complaint_list[1]) + self.assertIn("testapp/tests/missing_init", complaint_list[1]) - @mock.patch.object(TestStructureValidator, "_get_app_list", return_value=['invalidly_located_app']) + @mock.patch.object(TestStructureValidator, "_get_app_list", return_value=["invalidly_located_app"]) def test_process_invalidly_located_app(self, mocked_get_app_list): service = TestStructureValidator() diff --git a/tests/drf/test_fields.py b/tests/drf/test_fields.py index 7a9f54e..83e4742 100644 --- a/tests/drf/test_fields.py +++ b/tests/drf/test_fields.py @@ -15,8 +15,8 @@ class TestManyTrueSerializer(serializers.ModelSerializer): class Meta: model = ModelWithFkToSelf fields = [ - 'id', - 'children', + "id", + "children", ] @@ -27,8 +27,8 @@ class TestManyFalseSerializer(serializers.ModelSerializer): class Meta: model = ModelWithOneToOneToSelf fields = [ - 'id', - 'peer', + "id", + "peer", ] @@ -50,9 +50,9 @@ def test_create_super_called(self, mocked_create): def test_many_true_regular(self): serializer = TestManyTrueSerializer() - self.assertIn('children', serializer.fields) - self.assertIsInstance(serializer.fields['children'], ListSerializer) - self.assertIsInstance(serializer.fields['children'].child, RecursiveField) + self.assertIn("children", serializer.fields) + self.assertIsInstance(serializer.fields["children"], ListSerializer) + self.assertIsInstance(serializer.fields["children"].child, RecursiveField) def test_many_true_representation(self): mwfts_1 = ModelWithFkToSelf.objects.create(parent=None) @@ -62,16 +62,16 @@ def test_many_true_representation(self): representation = serializer.to_representation(instance=mwfts_1) self.assertIsInstance(representation, dict) - self.assertIn('children', representation) - self.assertEqual(len(representation['children']), 1) - self.assertEqual(representation['children'][0]['id'], mwfts_2.id) - self.assertEqual(representation['children'][0]['children'], []) + self.assertIn("children", representation) + self.assertEqual(len(representation["children"]), 1) + self.assertEqual(representation["children"][0]["id"], mwfts_2.id) + self.assertEqual(representation["children"][0]["children"], []) def test_many_false_regular(self): serializer = TestManyFalseSerializer() - self.assertIn('peer', serializer.fields) - self.assertIsInstance(serializer.fields['peer'], RecursiveField) + self.assertIn("peer", serializer.fields) + self.assertIsInstance(serializer.fields["peer"], RecursiveField) def test_many_false_representation(self): mwotos_no_peer = ModelWithOneToOneToSelf.objects.create(peer=None) @@ -81,7 +81,7 @@ def test_many_false_representation(self): representation = serializer.to_representation(instance=mwotos_has_peer) self.assertIsInstance(representation, dict) - self.assertIn('peer', representation) - self.assertEqual(len(representation['peer']), 2) - self.assertEqual(representation['peer']['id'], mwotos_no_peer.id) - self.assertEqual(representation['peer']['peer'], None) + self.assertIn("peer", representation) + self.assertEqual(len(representation["peer"]), 2) + self.assertEqual(representation["peer"]["id"], mwotos_no_peer.id) + self.assertEqual(representation["peer"]["peer"], None) diff --git a/tests/mixins/test_validation.py b/tests/mixins/test_validation.py index c873940..212296c 100644 --- a/tests/mixins/test_validation.py +++ b/tests/mixins/test_validation.py @@ -12,7 +12,7 @@ def test_clean_regular(self): def test_clean_is_called(self): obj = ModelWithCleanMixin() - with mock.patch.object(obj, 'clean') as mocked_method: + with mock.patch.object(obj, "clean") as mocked_method: obj.save() mocked_method.assert_called_once() diff --git a/tests/permissions/fixtures/test_declarations.py b/tests/permissions/fixtures/test_declarations.py index 840d937..f76eda8 100644 --- a/tests/permissions/fixtures/test_declarations.py +++ b/tests/permissions/fixtures/test_declarations.py @@ -6,25 +6,25 @@ class PermissionFixtureDeclarationTest(TestCase): def test_permission_model_declaration_regular(self): permission = PermissionModelDeclaration( - app_label='my_app', - codename_list=['view_mymodel'], - model='mymodel', + app_label="my_app", + codename_list=["view_mymodel"], + model="mymodel", ) - self.assertEqual(permission.app_label, 'my_app') - self.assertEqual(permission.codename_list, ['view_mymodel']) - self.assertEqual(permission.model, 'mymodel') + self.assertEqual(permission.app_label, "my_app") + self.assertEqual(permission.codename_list, ["view_mymodel"]) + self.assertEqual(permission.model, "mymodel") def test_group_permission_declaration_regular(self): permission = PermissionModelDeclaration( - app_label='my_app', - codename_list=['view_mymodel'], - model='mymodel', + app_label="my_app", + codename_list=["view_mymodel"], + model="mymodel", ) group = GroupPermissionDeclaration( - name='my_group', + name="my_group", permission_list=[permission], ) - self.assertEqual(group.name, 'my_group') + self.assertEqual(group.name, "my_group") self.assertEqual(group.permission_list, [permission]) diff --git a/tests/permissions/fixtures/test_helpers.py b/tests/permissions/fixtures/test_helpers.py index 1f3f441..e738ca8 100644 --- a/tests/permissions/fixtures/test_helpers.py +++ b/tests/permissions/fixtures/test_helpers.py @@ -5,10 +5,10 @@ class PermissionFixtureHelperTest(TestCase): def test_generate_default_permissions_regular(self): - permission_list = generate_default_permissions('mymodel') + permission_list = generate_default_permissions("mymodel") self.assertEqual(len(permission_list), 4) - self.assertIn('add_mymodel', permission_list) - self.assertIn('change_mymodel', permission_list) - self.assertIn('delete_mymodel', permission_list) - self.assertIn('view_mymodel', permission_list) + self.assertIn("add_mymodel", permission_list) + self.assertIn("change_mymodel", permission_list) + self.assertIn("delete_mymodel", permission_list) + self.assertIn("view_mymodel", permission_list) diff --git a/tests/permissions/fixtures/test_services_setup_service.py b/tests/permissions/fixtures/test_services_setup_service.py index a78d80d..47cc81a 100644 --- a/tests/permissions/fixtures/test_services_setup_service.py +++ b/tests/permissions/fixtures/test_services_setup_service.py @@ -10,17 +10,17 @@ class PermissionSetupServiceTest(TestCase): def setUpTestData(cls): super().setUpTestData() - cls.group, created = Group.objects.get_or_create(name='my_group') + cls.group, created = Group.objects.get_or_create(name="my_group") cls.permission_view = Permission.objects.get_by_natural_key( - app_label='testapp', codename='view_mysinglesignalmodel', model='mysinglesignalmodel' + app_label="testapp", codename="view_mysinglesignalmodel", model="mysinglesignalmodel" ) cls.permission_change = Permission.objects.get_by_natural_key( - app_label='testapp', codename='change_mysinglesignalmodel', model='mysinglesignalmodel' + app_label="testapp", codename="change_mysinglesignalmodel", model="mysinglesignalmodel" ) def test_init_regular(self): - group_declaration = GroupPermissionDeclaration(name='my_group', permission_list=[]) + group_declaration = GroupPermissionDeclaration(name="my_group", permission_list=[]) service = PermissionSetupService(group_declaration=group_declaration) self.assertEqual(service.group_declaration, group_declaration) @@ -28,10 +28,10 @@ def test_init_regular(self): def test_process_add_permission(self): group_declaration = GroupPermissionDeclaration( - name='my_group', + name="my_group", permission_list=[ PermissionModelDeclaration( - app_label='testapp', codename_list=['change_mysinglesignalmodel'], model='mysinglesignalmodel' + app_label="testapp", codename_list=["change_mysinglesignalmodel"], model="mysinglesignalmodel" ) ], ) @@ -49,7 +49,7 @@ def test_process_add_permission(self): def test_process_remove_permission(self): self.group.permissions.add(self.permission_view) - group_declaration = GroupPermissionDeclaration(name='my_group', permission_list=[]) + group_declaration = GroupPermissionDeclaration(name="my_group", permission_list=[]) service = PermissionSetupService(group_declaration=group_declaration) new_permissions, removed_permissions = service.process() @@ -64,10 +64,10 @@ def test_process_no_changes_permission(self): self.group.permissions.add(self.permission_view) group_declaration = GroupPermissionDeclaration( - name='my_group', + name="my_group", permission_list=[ PermissionModelDeclaration( - app_label='testapp', codename_list=['view_mysinglesignalmodel'], model='mysinglesignalmodel' + app_label="testapp", codename_list=["view_mysinglesignalmodel"], model="mysinglesignalmodel" ) ], ) @@ -86,10 +86,10 @@ def test_process_invalid_permission(self): self.group.permissions.add(self.permission_view) group_declaration = GroupPermissionDeclaration( - name='my_group', + name="my_group", permission_list=[ PermissionModelDeclaration( - app_label='testapp', codename_list=['invalid_permission'], model='mysinglesignalmodel' + app_label="testapp", codename_list=["invalid_permission"], model="mysinglesignalmodel" ) ], ) @@ -104,10 +104,10 @@ def test_process_invalid_app(self): self.group.permissions.add(self.permission_view) group_declaration = GroupPermissionDeclaration( - name='my_group', + name="my_group", permission_list=[ PermissionModelDeclaration( - app_label='invalid_app', codename_list=['view_mysinglesignalmodel'], model='mysinglesignalmodel' + app_label="invalid_app", codename_list=["view_mysinglesignalmodel"], model="mysinglesignalmodel" ) ], ) @@ -120,10 +120,10 @@ def test_process_invalid_model(self): self.group.permissions.add(self.permission_view) group_declaration = GroupPermissionDeclaration( - name='my_group', + name="my_group", permission_list=[ PermissionModelDeclaration( - app_label='testapp', codename_list=['view_mysinglesignalmodel'], model='invalid_model' + app_label="testapp", codename_list=["view_mysinglesignalmodel"], model="invalid_model" ) ], ) @@ -136,29 +136,29 @@ def test_process_duplicated_permission_declaration(self): self.group.permissions.add(self.permission_view) group_declaration = GroupPermissionDeclaration( - name='my_group', + name="my_group", permission_list=[ PermissionModelDeclaration( - app_label='testapp', codename_list=['view_mysinglesignalmodel'], model='mysinglesignalmodel' + app_label="testapp", codename_list=["view_mysinglesignalmodel"], model="mysinglesignalmodel" ), PermissionModelDeclaration( - app_label='testapp', codename_list=['view_mysinglesignalmodel'], model='mysinglesignalmodel' + app_label="testapp", codename_list=["view_mysinglesignalmodel"], model="mysinglesignalmodel" ), ], ) service = PermissionSetupService(group_declaration=group_declaration) - with self.assertRaisesMessage(ValueError, f'Permission {self.permission_view} declared twice.'): + with self.assertRaisesMessage(ValueError, f"Permission {self.permission_view} declared twice."): service.process() def test_process_dry_run_not_persisting(self): self.group.permissions.add(self.permission_view) group_declaration = GroupPermissionDeclaration( - name='my_group', + name="my_group", permission_list=[ PermissionModelDeclaration( - app_label='testapp', codename_list=['change_mysinglesignalmodel'], model='mysinglesignalmodel' + app_label="testapp", codename_list=["change_mysinglesignalmodel"], model="mysinglesignalmodel" ) ], ) diff --git a/tests/permissions/test_install_permission_fixtures_command.py b/tests/permissions/test_install_permission_fixtures_command.py index 9cb2074..36d8832 100644 --- a/tests/permissions/test_install_permission_fixtures_command.py +++ b/tests/permissions/test_install_permission_fixtures_command.py @@ -22,22 +22,22 @@ def test_add_arguments_regular(self): self.assertTrue("--dry-run" in [action.option_strings[0] for action in parser._actions]) - @override_settings(GROUP_PERMISSION_FIXTURES=['testapp.permissions.TestGroupDeclaration']) - @mock.patch.object(PermissionSetupService, 'process', return_value=([], [])) + @override_settings(GROUP_PERMISSION_FIXTURES=["testapp.permissions.TestGroupDeclaration"]) + @mock.patch.object(PermissionSetupService, "process", return_value=([], [])) def test_run_command_regular(self, mocked_process): command = Command() command.handle() mocked_process.assert_called_once() - @mock.patch.object(PermissionSetupService, 'process') + @mock.patch.object(PermissionSetupService, "process") def test_run_command_no_settings_variable(self, mocked_process): command = Command() command.handle() mocked_process.assert_not_called() - @mock.patch.object(PermissionSetupService, 'process') + @mock.patch.object(PermissionSetupService, "process") def test_run_command_dry_run(self, mocked_process): command = Command() command.handle(dry_run=True) diff --git a/tests/sentry/mock_data.py b/tests/sentry/mock_data.py index 2e1a845..05121b9 100644 --- a/tests/sentry/mock_data.py +++ b/tests/sentry/mock_data.py @@ -1,136 +1,136 @@ SENTRY_EVENT = { - 'level': 'error', - 'exception': { - 'values': [ + "level": "error", + "exception": { + "values": [ { - 'module': None, - 'type': 'ZeroDivisionError', - 'value': 'division by zero', - 'mechanism': {'type': 'django', 'handled': False}, - 'stacktrace': { - 'frames': [ + "module": None, + "type": "ZeroDivisionError", + "value": "division by zero", + "mechanism": {"type": "django", "handled": False}, + "stacktrace": { + "frames": [ { - 'filename': 'test/account/api/views.py', - 'abs_path': '/opt/project/backend/test/account/api/views.py', - 'function': 'perform_update', - 'module': 'test.account.api.views', - 'lineno': 123, - 'pre_context': ['test = 1/0'], - 'vars': { - 'self': '', - 'serializer': 'TestDetailSerializer()', - '__class__': "", - 'admin': '', - 'test_data': '123', + "filename": "test/account/api/views.py", + "abs_path": "/opt/project/backend/test/account/api/views.py", + "function": "perform_update", + "module": "test.account.api.views", + "lineno": 123, + "pre_context": ["test = 1/0"], + "vars": { + "self": "", + "serializer": "TestDetailSerializer()", + "__class__": "", + "admin": "", + "test_data": "123", }, - 'in_app': True, + "in_app": True, } ] }, } ] }, - 'request': { - 'url': 'http://localhost:8000/api/v2/test/17/', - 'query_string': '', - 'method': 'PUT', - 'env': {'SERVER_NAME': 'cdc3cb5b00af', 'SERVER_PORT': '8000', 'REMOTE_ADDR': '172.22.0.1'}, - 'headers': { - 'Content-Length': '1202', - 'Content-Type': 'application/json', - 'Host': 'localhost:8000', - 'User-Agent': 'Mozilla/5.0 (Macintosh;) Gecko/20100101 Firefox/112.0', - 'Accept': 'application/json, text/plain, */*', - 'Accept-Language': 'en', - 'Accept-Encoding': 'gzip, deflate, br', - 'Authorization': 'Token 123123123123123123123123123123123123abcd', - 'Origin': 'http://127.0.0.1:3000', - 'Dnt': '1', - 'Connection': 'keep-alive', - 'Referer': 'http://127.0.0.1:3000/', - 'Sec-Fetch-Dest': 'empty', - 'Sec-Fetch-Mode': 'cors', - 'Sec-Fetch-Site': 'cross-site', + "request": { + "url": "http://localhost:8000/api/v2/test/17/", + "query_string": "", + "method": "PUT", + "env": {"SERVER_NAME": "cdc3cb5b00af", "SERVER_PORT": "8000", "REMOTE_ADDR": "172.22.0.1"}, + "headers": { + "Content-Length": "1202", + "Content-Type": "application/json", + "Host": "localhost:8000", + "User-Agent": "Mozilla/5.0 (Macintosh;) Gecko/20100101 Firefox/112.0", + "Accept": "application/json, text/plain, */*", + "Accept-Language": "en", + "Accept-Encoding": "gzip, deflate, br", + "Authorization": "Token 123123123123123123123123123123123123abcd", + "Origin": "http://127.0.0.1:3000", + "Dnt": "1", + "Connection": "keep-alive", + "Referer": "http://127.0.0.1:3000/", + "Sec-Fetch-Dest": "empty", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Site": "cross-site", }, - 'cookies': {}, - 'data': '', + "cookies": {}, + "data": "", }, - 'user': {'email': 'test@test.local', 'id': '1337', 'ip_address': '172.22.0.1', 'username': 'test@test.local'}, + "user": {"email": "test@test.local", "id": "1337", "ip_address": "172.22.0.1", "username": "test@test.local"}, } SCRUBBED_SENTRY_EVENT = { - 'level': 'error', - 'exception': { - 'values': [ + "level": "error", + "exception": { + "values": [ { - 'module': None, - 'type': 'ZeroDivisionError', - 'value': 'division by zero', - 'mechanism': {'type': 'django', 'handled': False}, - 'stacktrace': { - 'frames': [ + "module": None, + "type": "ZeroDivisionError", + "value": "division by zero", + "mechanism": {"type": "django", "handled": False}, + "stacktrace": { + "frames": [ { - 'filename': 'test/account/api/views.py', - 'abs_path': '/opt/project/backend/test/account/api/views.py', - 'function': 'perform_update', - 'module': 'test.account.api.views', - 'lineno': 123, - 'pre_context': ['test = 1/0'], - 'vars': { - 'self': "''", - 'serializer': '[Filtered]', # filtered due to standard filter - '__class__': '""', - 'admin': '[Filtered]', # filtered due to standard filter - 'test_data': "'123'", + "filename": "test/account/api/views.py", + "abs_path": "/opt/project/backend/test/account/api/views.py", + "function": "perform_update", + "module": "test.account.api.views", + "lineno": 123, + "pre_context": ["test = 1/0"], + "vars": { + "self": "''", + "serializer": "[Filtered]", # filtered due to standard filter + "__class__": "\"\"", + "admin": "[Filtered]", # filtered due to standard filter + "test_data": "'123'", }, - 'in_app': True, + "in_app": True, } ] }, } ] }, - 'request': { - 'url': 'http://localhost:8000/api/v2/test/17/', - 'query_string': '', - 'method': 'PUT', - 'env': {'SERVER_NAME': 'cdc3cb5b00af', 'SERVER_PORT': '8000', 'REMOTE_ADDR': '172.22.0.1'}, - 'headers': { - 'Content-Length': '1202', - 'Content-Type': 'application/json', - 'Host': 'localhost:8000', - 'User-Agent': 'Mozilla/5.0 (Macintosh;) Gecko/20100101 Firefox/112.0', - 'Accept': 'application/json, text/plain, */*', - 'Accept-Language': 'en', - 'Accept-Encoding': 'gzip, deflate, br', - 'Authorization': '[Filtered]', # filtered due to default sentry filter - 'Origin': 'http://127.0.0.1:3000', - 'Dnt': '1', - 'Connection': 'keep-alive', - 'Referer': 'http://127.0.0.1:3000/', - 'Sec-Fetch-Dest': 'empty', - 'Sec-Fetch-Mode': 'cors', - 'Sec-Fetch-Site': 'cross-site', + "request": { + "url": "http://localhost:8000/api/v2/test/17/", + "query_string": "", + "method": "PUT", + "env": {"SERVER_NAME": "cdc3cb5b00af", "SERVER_PORT": "8000", "REMOTE_ADDR": "172.22.0.1"}, + "headers": { + "Content-Length": "1202", + "Content-Type": "application/json", + "Host": "localhost:8000", + "User-Agent": "Mozilla/5.0 (Macintosh;) Gecko/20100101 Firefox/112.0", + "Accept": "application/json, text/plain, */*", + "Accept-Language": "en", + "Accept-Encoding": "gzip, deflate, br", + "Authorization": "[Filtered]", # filtered due to default sentry filter + "Origin": "http://127.0.0.1:3000", + "Dnt": "1", + "Connection": "keep-alive", + "Referer": "http://127.0.0.1:3000/", + "Sec-Fetch-Dest": "empty", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Site": "cross-site", }, - 'cookies': {}, - 'data': '', + "cookies": {}, + "data": "", }, - 'user': { - 'email': '[Filtered]', # filtered due to default sentry filter - 'id': '1337', - 'ip_address': '[Filtered]', # filtered due to default sentry filter - 'username': '[Filtered]', # filtered due to default sentry filter + "user": { + "email": "[Filtered]", # filtered due to default sentry filter + "id": "1337", + "ip_address": "[Filtered]", # filtered due to default sentry filter + "username": "[Filtered]", # filtered due to default sentry filter }, - '_meta': { - 'exception': { - 'values': { - '0': { - 'stacktrace': { - 'frames': { - '0': { - 'vars': { - 'serializer': {'': {'rem': [['!config', 's']]}}, - 'admin': {'': {'rem': [['!config', 's']]}}, + "_meta": { + "exception": { + "values": { + "0": { + "stacktrace": { + "frames": { + "0": { + "vars": { + "serializer": {"": {"rem": [["!config", "s"]]}}, + "admin": {"": {"rem": [["!config", "s"]]}}, } } } @@ -138,11 +138,11 @@ } } }, - 'request': {'headers': {'Authorization': {'': {'rem': [['!config', 's']]}}}}, - 'user': { - 'email': {'': {'rem': [['!config', 's']]}}, - 'ip_address': {'': {'rem': [['!config', 's']]}}, - 'username': {'': {'rem': [['!config', 's']]}}, + "request": {"headers": {"Authorization": {"": {"rem": [["!config", "s"]]}}}}, + "user": { + "email": {"": {"rem": [["!config", "s"]]}}, + "ip_address": {"": {"rem": [["!config", "s"]]}}, + "username": {"": {"rem": [["!config", "s"]]}}, }, }, } diff --git a/tests/sentry/test_sentry_helper.py b/tests/sentry/test_sentry_helper.py index e0a165f..344df32 100644 --- a/tests/sentry/test_sentry_helper.py +++ b/tests/sentry/test_sentry_helper.py @@ -8,22 +8,22 @@ class SentryHelperTest(TestCase): def test_strip_sensitive_data_from_sentry_event_regular(self): - event = {'user': {'email': 'mymail@example.com', 'ip_address': '127.0.0.1', 'username': 'my-user'}} + event = {"user": {"email": "mymail@example.com", "ip_address": "127.0.0.1", "username": "my-user"}} self.assertIsInstance(strip_sensitive_data_from_sentry_event(event, None), dict) def test_strip_sensitive_data_from_sentry_event_missing_key_email(self): - event = {'user': {'ip_address': '127.0.0.1', 'username': 'my-user'}} + event = {"user": {"ip_address": "127.0.0.1", "username": "my-user"}} self.assertIsInstance(strip_sensitive_data_from_sentry_event(event, None), dict) def test_strip_sensitive_data_from_sentry_event_missing_key_ip_address(self): - event = {'user': {'email': 'mymail@example.com', 'username': 'my-user'}} + event = {"user": {"email": "mymail@example.com", "username": "my-user"}} self.assertIsInstance(strip_sensitive_data_from_sentry_event(event, None), dict) def test_strip_sensitive_data_from_sentry_event_missing_key_username(self): - event = {'user': {'email': 'mymail@example.com', 'ip_address': '127.0.0.1'}} + event = {"user": {"email": "mymail@example.com", "ip_address": "127.0.0.1"}} self.assertIsInstance(strip_sensitive_data_from_sentry_event(event, None), dict) diff --git a/tests/test_admin_forms.py b/tests/test_admin_forms.py index 2190395..f198cb9 100644 --- a/tests/test_admin_forms.py +++ b/tests/test_admin_forms.py @@ -12,4 +12,4 @@ def test_admin_crispy_form_regular(self): self.assertIsInstance(form.helper, FormHelper) self.assertIsInstance(form.helper.layout, Layout) - self.assertEqual(form.helper.form_method, 'post') + self.assertEqual(form.helper.form_method, "post") diff --git a/tests/test_admin_inlines.py b/tests/test_admin_inlines.py index f9cc5ab..db16d86 100644 --- a/tests/test_admin_inlines.py +++ b/tests/test_admin_inlines.py @@ -16,7 +16,7 @@ class AdminInlineTest(RequestProviderMixin, TestCase): def setUpTestData(cls): super().setUpTestData() - cls.super_user = User.objects.create(username='super_user', is_superuser=True) + cls.super_user = User.objects.create(username="super_user", is_superuser=True) def test_read_only_tabular_inline_admin_all_fields_readonly(self): obj = MySingleSignalModel(value=1) @@ -26,7 +26,7 @@ def test_read_only_tabular_inline_admin_all_fields_readonly(self): readonly_fields = admin_class.get_readonly_fields(request=self.get_request(), obj=fk_related_obj) self.assertEqual(len(readonly_fields), 1) - self.assertIn('single_signal', readonly_fields) + self.assertIn("single_signal", readonly_fields) def test_read_only_admin_tabular_inline_no_change_permissions(self): admin_class = TestReadOnlyTabularInline(parent_model=MySingleSignalModel, admin_site=admin.site) diff --git a/tests/test_admin_model_admins_classes.py b/tests/test_admin_model_admins_classes.py index 9f75d3c..cc643e2 100644 --- a/tests/test_admin_model_admins_classes.py +++ b/tests/test_admin_model_admins_classes.py @@ -20,7 +20,7 @@ class AdminClassesTest(RequestProviderMixin, TestCase): def setUpTestData(cls): super().setUpTestData() - cls.super_user = User.objects.create(username='super_user', is_superuser=True) + cls.super_user = User.objects.create(username="super_user", is_superuser=True) admin.site.register(MySingleSignalModel, TestReadOnlyAdmin) admin.site.register(MyMultipleSignalModel, TestEditableOnlyAdmin) @@ -39,8 +39,8 @@ def test_read_only_admin_all_fields_readonly(self): readonly_fields = admin_class.get_readonly_fields(request=self.get_request(), obj=obj) self.assertEqual(len(readonly_fields), 2) - self.assertIn('id', readonly_fields) - self.assertIn('value', readonly_fields) + self.assertIn("id", readonly_fields) + self.assertIn("value", readonly_fields) def test_read_only_admin_no_change_permissions(self): admin_class = TestReadOnlyAdmin(model=MySingleSignalModel, admin_site=admin.site) @@ -58,7 +58,7 @@ def test_editable_only_admin_delete_action_removed(self): request = self.get_request(self.super_user) actions = admin_class.get_actions(request=request) - self.assertNotIn('delete_selected', actions) + self.assertNotIn("delete_selected", actions) def test_editable_only_admin_no_change_permissions(self): admin_class = TestEditableOnlyAdmin(model=MyMultipleSignalModel, admin_site=admin.site) diff --git a/tests/test_admin_view_mixins.py b/tests/test_admin_view_mixins.py index 9c15593..947674b 100644 --- a/tests/test_admin_view_mixins.py +++ b/tests/test_admin_view_mixins.py @@ -11,8 +11,8 @@ class TestView(AdminViewMixin, generic.TemplateView): model = MySingleSignalModel - admin_page_title = 'My fancy title' - template_name = 'testapp/test_template.html' + admin_page_title = "My fancy title" + template_name = "testapp/test_template.html" class AdminViewMixinTest(RequestProviderMixin, TestCase): @@ -22,8 +22,8 @@ def setUpTestData(cls): cls.view = TestView() - cls.super_user = User.objects.create(username='super_user', is_superuser=True) - cls.regular_user = User.objects.create(username='test_user', is_superuser=False) + cls.super_user = User.objects.create(username="super_user", is_superuser=True) + cls.regular_user = User.objects.create(username="test_user", is_superuser=False) # View needs a request since django 3.2 request = cls.get_request(cls.super_user) @@ -54,17 +54,17 @@ def test_admin_view_mixin_get_context_data_regular(self): context_data = self.view.get_context_data() # Simply assert custom fields are available - self.assertIn('site_header', context_data) - self.assertIn('site_title', context_data) - self.assertIn('name', context_data) - self.assertIn('original', context_data) - self.assertIn('is_nav_sidebar_enabled', context_data) - self.assertIn('available_apps', context_data) - self.assertIn('opts', context_data) - self.assertIn('app_label', context_data['opts']) - self.assertIn('verbose_name', context_data['opts']) - self.assertIn('verbose_name_plural', context_data['opts']) - self.assertIn('model_name', context_data['opts']) - self.assertIn('app_config', context_data['opts']) - self.assertIn('verbose_name', context_data['opts']['app_config']) - self.assertIn('has_permission', context_data) + self.assertIn("site_header", context_data) + self.assertIn("site_title", context_data) + self.assertIn("name", context_data) + self.assertIn("original", context_data) + self.assertIn("is_nav_sidebar_enabled", context_data) + self.assertIn("available_apps", context_data) + self.assertIn("opts", context_data) + self.assertIn("app_label", context_data["opts"]) + self.assertIn("verbose_name", context_data["opts"]) + self.assertIn("verbose_name_plural", context_data["opts"]) + self.assertIn("model_name", context_data["opts"]) + self.assertIn("app_config", context_data["opts"]) + self.assertIn("verbose_name", context_data["opts"]["app_config"]) + self.assertIn("has_permission", context_data) diff --git a/tests/test_context_manager.py b/tests/test_context_manager.py index ce3bcf3..ade087f 100644 --- a/tests/test_context_manager.py +++ b/tests/test_context_manager.py @@ -19,9 +19,9 @@ def test_single_signal_executed_regular(self): def test_single_signal_not_executed(self): kwargs = { - 'signal': signals.pre_save, - 'receiver': increase_value_no_dispatch_uid, - 'sender': MySingleSignalModel, + "signal": signals.pre_save, + "receiver": increase_value_no_dispatch_uid, + "sender": MySingleSignalModel, } with TempDisconnectSignal(**kwargs): @@ -31,15 +31,15 @@ def test_single_signal_not_executed(self): def test_multiple_signals_not_executed(self): kwargs_pre = { - 'signal': signals.pre_save, - 'receiver': increase_value_with_dispatch_uid, - 'sender': MyMultipleSignalModel, - 'dispatch_uid': 'test.mysinglesignalmodel.increase_value_with_uuid', + "signal": signals.pre_save, + "receiver": increase_value_with_dispatch_uid, + "sender": MyMultipleSignalModel, + "dispatch_uid": "test.mysinglesignalmodel.increase_value_with_uuid", } kwargs_post = { - 'signal': signals.post_save, - 'receiver': send_email, - 'sender': MyMultipleSignalModel, + "signal": signals.post_save, + "receiver": send_email, + "sender": MyMultipleSignalModel, } with TempDisconnectSignal(**kwargs_pre): @@ -53,10 +53,10 @@ def test_multiple_signals_not_executed(self): def test_multiple_signals_one_still_active(self): kwargs_pre = { - 'signal': signals.pre_save, - 'receiver': increase_value_with_dispatch_uid, - 'sender': MyMultipleSignalModel, - 'dispatch_uid': 'test.mysinglesignalmodel.increase_value_with_uuid', + "signal": signals.pre_save, + "receiver": increase_value_with_dispatch_uid, + "sender": MyMultipleSignalModel, + "dispatch_uid": "test.mysinglesignalmodel.increase_value_with_uuid", } with TempDisconnectSignal(**kwargs_pre): diff --git a/tests/test_managers.py b/tests/test_managers.py index c703712..6a553a6 100644 --- a/tests/test_managers.py +++ b/tests/test_managers.py @@ -10,7 +10,7 @@ def setUpTestData(cls): super().setUpTestData() # Create test user - cls.user = User.objects.create(username='my-username') + cls.user = User.objects.create(username="my-username") # Create list of objects cls.object_list = [ diff --git a/tests/test_middleware.py b/tests/test_middleware.py index 3e0a3f9..d5a06ff 100644 --- a/tests/test_middleware.py +++ b/tests/test_middleware.py @@ -18,13 +18,13 @@ def test_current_user_is_none_if_request_user_is_none(self): self.assertEqual(response.status_code, HTTPStatus.NO_CONTENT) def test_current_user_is_same_as_request_user(self): - new_user = Mock(user_name='test_user') + new_user = Mock(user_name="test_user") response = set_current_user(user=new_user) self.assertEqual(response.status_code, HTTPStatus.OK) def test_current_user_is_thread_safe(self): - user1 = Mock(user_name='user1') - user2 = Mock(user_name='user2') + user1 = Mock(user_name="user1") + user2 = Mock(user_name="user2") current_users = [] ready_event = threading.Event() proceed_event = threading.Event() @@ -43,12 +43,12 @@ def test_current_user_is_thread_safe(self): proceed_event.set() first_thread.join() self.assertEqual(current_users[0], user2) - self.assertEqual(current_users[0].user_name, 'user2') + self.assertEqual(current_users[0].user_name, "user2") self.assertEqual(current_users[1], user1) - self.assertEqual(current_users[1].user_name, 'user1') + self.assertEqual(current_users[1].user_name, "user1") def test_user_is_cleared_after_request(self): - user = Mock(user_name='test_user') + user = Mock(user_name="test_user") request = Mock(user=user) middleware = CurrentUserMiddleware(get_response=lambda request: HttpResponse(status=HTTPStatus.OK)) response = middleware(request) @@ -63,7 +63,7 @@ def test_replaced_user_is_reflected_in_middleware(self): # This should ideally be taken into account in our middleware since it # is also used to provide the user for `CommonInfo.lastmodified_by`. def get_response(request): - replaced_user = Mock(user_name='replaced_user') + replaced_user = Mock(user_name="replaced_user") request.user = replaced_user user_from_mw = CurrentUserMiddleware.get_current_user() if user_from_mw is not replaced_user: diff --git a/tests/test_models.py b/tests/test_models.py index 1c775b6..b87110d 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -9,7 +9,7 @@ class CommonInfoTest(TestCase): - @freeze_time('2022-06-26 10:00') + @freeze_time("2022-06-26 10:00") def test_save_created_at_set(self): obj = CommonInfoBasedModel.objects.create(value=1, value_b=1) obj.created_at = None @@ -17,9 +17,9 @@ def test_save_created_at_set(self): self.assertEqual(obj.created_at, timezone.now()) - @freeze_time('2022-06-26 10:00') + @freeze_time("2022-06-26 10:00") def test_save_update_fields_common_fields_set(self): - with freeze_time('2020-09-19'): + with freeze_time("2020-09-19"): obj = CommonInfoBasedModel.objects.create(value=1, value_b=1) obj.value = 2 obj.value_b = 999 @@ -29,7 +29,7 @@ def test_save_update_fields_common_fields_set(self): False, # default for force_insert False, # default for force_update None, # default for using - (x for x in ['value']), # update_fields is supposed to accept any Iterable[str] + (x for x in ["value"]), # update_fields is supposed to accept any Iterable[str] ) obj.save(*args) @@ -38,22 +38,22 @@ def test_save_update_fields_common_fields_set(self): self.assertEqual(obj.value_b, 1, "value_b should not have changed") self.assertEqual(obj.lastmodified_at, datetime.datetime(2022, 6, 26, 10)) - @patch('testapp.models.CommonInfoBasedModel.ALWAYS_UPDATE_FIELDS', new_callable=PropertyMock) - @freeze_time('2022-06-26 10:00') + @patch("testapp.models.CommonInfoBasedModel.ALWAYS_UPDATE_FIELDS", new_callable=PropertyMock) + @freeze_time("2022-06-26 10:00") def test_save_update_fields_common_fields_set_without_always_update(self, always_update_mock): always_update_mock.return_value = False - with freeze_time('2020-09-19'): + with freeze_time("2020-09-19"): obj = CommonInfoBasedModel.objects.create(value=1) obj.value = 2 - obj.save(update_fields=('value',)) + obj.save(update_fields=("value",)) obj.refresh_from_db() self.assertEqual(obj.value, 2) self.assertEqual(obj.lastmodified_at, datetime.datetime(2020, 9, 19)) - @freeze_time('2022-06-26 10:00') + @freeze_time("2022-06-26 10:00") def test_save_common_fields_set_without_update_fields(self): - with freeze_time('2020-09-19'): + with freeze_time("2020-09-19"): obj = CommonInfoBasedModel.objects.create(value=1) obj.value = 2 obj.save() diff --git a/tests/test_rest_api_mixins.py b/tests/test_rest_api_mixins.py index 16d8793..2cd042d 100644 --- a/tests/test_rest_api_mixins.py +++ b/tests/test_rest_api_mixins.py @@ -10,7 +10,7 @@ class BaseApiTest(BaseViewSetTestMixin, TestCase): def get_default_api_user(self) -> AbstractUser: - return User.objects.create(username='my-username', is_active=True) + return User.objects.create(username="my-username", is_active=True) class MySingleSignalModelApiViewTest(BaseApiTest): @@ -29,20 +29,20 @@ def setUpTestData(cls): def test_action_not_activated(self): with self.assertRaises(AttributeError): self.execute_request( - method='post', - url=reverse('my-single-signal-model-list'), - viewset_kwargs={'post': 'create'}, + method="post", + url=reverse("my-single-signal-model-list"), + viewset_kwargs={"post": "create"}, user=self.default_api_user, ) def test_list_authentication_required(self): - self.validate_authentication_required(url=reverse('my-single-signal-model-list'), method='get', view='list') + self.validate_authentication_required(url=reverse("my-single-signal-model-list"), method="get", view="list") def test_list_regular(self): response = self.execute_request( - method='get', - url=reverse('my-single-signal-model-list'), - viewset_kwargs={'get': 'list'}, + method="get", + url=reverse("my-single-signal-model-list"), + viewset_kwargs={"get": "list"}, user=self.default_api_user, ) diff --git a/tests/test_utils_date.py b/tests/test_utils_date.py index 0465a2e..2ce6439 100644 --- a/tests/test_utils_date.py +++ b/tests/test_utils_date.py @@ -118,7 +118,7 @@ def test_tz_today_as_object_tz_not_active(self): def test_tz_today_as_str(self): frozen_date = datetime.datetime(year=2019, month=9, day=19, hour=10) with freeze_time(frozen_date): - self.assertEqual(tz_today('%d.%m.%Y'), '19.09.2019') + self.assertEqual(tz_today("%d.%m.%Y"), "19.09.2019") def test_add_months_one_month(self): source_date = datetime.date(year=2020, month=6, day=26) @@ -162,7 +162,7 @@ def test_add_minutes_negative_minutes(self): add_minutes(source_datetime, -2), datetime.datetime(year=2020, month=6, day=26, hour=7, minute=58) ) - @freeze_time('2020-06-26') + @freeze_time("2020-06-26") def test_get_next_month_regular(self): self.assertEqual(get_next_month(), datetime.date(year=2020, month=7, day=26)) @@ -172,40 +172,40 @@ def test_first_day_of_month_regular(self): def test_get_formatted_date_str_regular(self): source_date = datetime.date(year=2020, month=6, day=26) - self.assertEqual(get_formatted_date_str(source_date), '26.06.2020') + self.assertEqual(get_formatted_date_str(source_date), "26.06.2020") def test_get_time_from_seconds_one_hour(self): - self.assertEqual(get_time_from_seconds(3600), '01:00:00') + self.assertEqual(get_time_from_seconds(3600), "01:00:00") def test_get_time_from_seconds_one_minute(self): - self.assertEqual(get_time_from_seconds(60), '00:01:00') + self.assertEqual(get_time_from_seconds(60), "00:01:00") def test_get_time_from_seconds_big_hours(self): - self.assertEqual(get_time_from_seconds(3600 * 99), '99:00:00') + self.assertEqual(get_time_from_seconds(3600 * 99), "99:00:00") def test_get_time_from_seconds_huge_hours(self): - self.assertEqual(get_time_from_seconds(3600 * 1000), '1000:00:00') + self.assertEqual(get_time_from_seconds(3600 * 1000), "1000:00:00") def test_get_time_from_seconds_negative_seconds(self): with self.assertRaises(ValueError): get_time_from_seconds(-1) - @override_settings(TIME_ZONE='UTC') + @override_settings(TIME_ZONE="UTC") def test_datetime_format_regular(self): source_date = datetime.datetime(year=2020, month=6, day=26, hour=8, tzinfo=pytz.UTC) - self.assertEqual(datetime_format(source_date, '%d.%m.%Y %H:%M'), '26.06.2020 08:00') + self.assertEqual(datetime_format(source_date, "%d.%m.%Y %H:%M"), "26.06.2020 08:00") - @override_settings(TIME_ZONE='Europe/Cologne') + @override_settings(TIME_ZONE="Europe/Cologne") def test_datetime_format_wrong_timezone(self): source_date = datetime.datetime(year=2020, month=6, day=26, hour=8, tzinfo=datetime.timezone.utc) - self.assertEqual(datetime_format(source_date, '%d.%m.%Y %H:%M'), '26.06.2020 08:00') + self.assertEqual(datetime_format(source_date, "%d.%m.%Y %H:%M"), "26.06.2020 08:00") - @override_settings(TIME_ZONE='Europe/Berlin') + @override_settings(TIME_ZONE="Europe/Berlin") def test_datetime_format_different_timezone(self): source_date = datetime.datetime(year=2020, month=6, day=26, hour=8, tzinfo=pytz.UTC) - self.assertEqual(datetime_format(source_date, '%d.%m.%Y %H:%M'), '26.06.2020 10:00') + self.assertEqual(datetime_format(source_date, "%d.%m.%Y %H:%M"), "26.06.2020 10:00") - @freeze_time('2022-12-14') + @freeze_time("2022-12-14") def test_get_first_and_last_of_month_in_december(self): first_of_month, last_of_month = get_first_and_last_of_month() expected_first_of_month = datetime.date(day=1, month=12, year=2022) @@ -214,7 +214,7 @@ def test_get_first_and_last_of_month_in_december(self): self.assertEqual(expected_first_of_month, first_of_month) self.assertEqual(expected_last_of_month, last_of_month) - @freeze_time('2020-02-14') + @freeze_time("2020-02-14") def test_get_first_and_last_of_month_in_february_leap_year(self): first_of_month, last_of_month = get_first_and_last_of_month() expected_first_of_month = datetime.date(day=1, month=2, year=2020) @@ -223,7 +223,7 @@ def test_get_first_and_last_of_month_in_february_leap_year(self): self.assertEqual(expected_first_of_month, first_of_month) self.assertEqual(expected_last_of_month, last_of_month) - @freeze_time('2022-02-14') + @freeze_time("2022-02-14") def test_get_first_and_last_of_month_in_february_non_leap_year(self): first_of_month, last_of_month = get_first_and_last_of_month() expected_first_of_month = datetime.date(day=1, month=2, year=2022) @@ -232,7 +232,7 @@ def test_get_first_and_last_of_month_in_february_non_leap_year(self): self.assertEqual(expected_first_of_month, first_of_month) self.assertEqual(expected_last_of_month, last_of_month) - @freeze_time('2022-04-04') + @freeze_time("2022-04-04") def test_get_first_and_last_of_month_in_april(self): first_of_month, last_of_month = get_first_and_last_of_month() expected_first_of_month = datetime.date(day=1, month=4, year=2022) @@ -244,25 +244,25 @@ def test_get_first_and_last_of_month_in_april(self): def test_get_first_and_last_of_month_with_date_objects_passed(self): date_mapping = { datetime.date(day=14, month=12, year=2022): { - 'first': datetime.date(day=1, month=12, year=2022), - 'last': datetime.date(day=31, month=12, year=2022), + "first": datetime.date(day=1, month=12, year=2022), + "last": datetime.date(day=31, month=12, year=2022), }, datetime.date(day=14, month=2, year=2020): { - 'first': datetime.date(day=1, month=2, year=2020), - 'last': datetime.date(day=29, month=2, year=2020), + "first": datetime.date(day=1, month=2, year=2020), + "last": datetime.date(day=29, month=2, year=2020), }, datetime.date(day=14, month=2, year=2022): { - 'first': datetime.date(day=1, month=2, year=2022), - 'last': datetime.date(day=28, month=2, year=2022), + "first": datetime.date(day=1, month=2, year=2022), + "last": datetime.date(day=28, month=2, year=2022), }, datetime.date(day=4, month=4, year=2022): { - 'first': datetime.date(day=1, month=4, year=2022), - 'last': datetime.date(day=30, month=4, year=2022), + "first": datetime.date(day=1, month=4, year=2022), + "last": datetime.date(day=30, month=4, year=2022), }, } for date_object in date_mapping: first_of_month, last_of_month = get_first_and_last_of_month(date_object=date_object) - self.assertEqual(date_mapping[date_object]['first'], first_of_month) - self.assertEqual(date_mapping[date_object]['last'], last_of_month) + self.assertEqual(date_mapping[date_object]["first"], first_of_month) + self.assertEqual(date_mapping[date_object]["last"], last_of_month) diff --git a/tests/test_utils_file.py b/tests/test_utils_file.py index 376af73..f3ff725 100644 --- a/tests/test_utils_file.py +++ b/tests/test_utils_file.py @@ -4,30 +4,30 @@ def test_get_filename_without_ending_full_path(): - assert get_filename_without_ending('path/to/my/text-file.txt') == "text-file" + assert get_filename_without_ending("path/to/my/text-file.txt") == "text-file" def test_get_filename_without_ending_only_filename(): - assert get_filename_without_ending('text-file.txt') == "text-file" + assert get_filename_without_ending("text-file.txt") == "text-file" @pytest.fixture def gen_test_file(tmp_path): def inner(content): - test_file = tmp_path / 'test_file.txt' + test_file = tmp_path / "test_file.txt" test_file.write_text(content) return test_file return inner -@pytest.mark.parametrize('test_func', [crc, md5_checksum]) +@pytest.mark.parametrize("test_func", [crc, md5_checksum]) def test_closes_file(mocker, test_func): """ Tests if the CRC and MD5 checksum functions use a context manager to open the file, to guarantee that the opened file descriptor is closed. """ - open_mock = mocker.patch('ambient_toolbox.utils.file.open') + open_mock = mocker.patch("ambient_toolbox.utils.file.open") open_mock.return_value.__enter__.return_value.read.return_value = None # to make f.read() return None. file_mock = mocker.Mock() test_func(file_mock) @@ -36,11 +36,11 @@ def test_closes_file(mocker, test_func): @pytest.mark.parametrize( - 'content, crc_result, md5_result', + "content, crc_result, md5_result", [ - ('The answer to life, the universe, and everything.', '31F49620', 'f81ab2f7fb6cacf50f973b0dc8faff44'), - ('The quick brown fox jumps over the lazy dog', '414FA339', '9e107d9d372bb6826bd81d3542a419d6'), - ('', '00000000', 'd41d8cd98f00b204e9800998ecf8427e'), + ("The answer to life, the universe, and everything.", "31F49620", "f81ab2f7fb6cacf50f973b0dc8faff44"), + ("The quick brown fox jumps over the lazy dog", "414FA339", "9e107d9d372bb6826bd81d3542a419d6"), + ("", "00000000", "d41d8cd98f00b204e9800998ecf8427e"), ], ) def test_crc_and_md5(gen_test_file, content, crc_result, md5_result): diff --git a/tests/test_utils_model.py b/tests/test_utils_model.py index d058116..16e3638 100644 --- a/tests/test_utils_model.py +++ b/tests/test_utils_model.py @@ -7,19 +7,19 @@ class UtilModelTest(TestCase): def test_object_to_dict_regular(self): obj = MySingleSignalModel.objects.create(value=17) - self.assertEqual(object_to_dict(obj), {'value': obj.value}) + self.assertEqual(object_to_dict(obj), {"value": obj.value}) def test_object_to_dict_blacklist(self): obj = MySingleSignalModel.objects.create(value=17) - self.assertEqual(object_to_dict(obj, ['value']), {}) + self.assertEqual(object_to_dict(obj, ["value"]), {}) def test_object_to_dict_with_id_with_blacklist(self): obj = MySingleSignalModel.objects.create(value=17) - self.assertEqual(object_to_dict(obj, ['value'], True), {'id': obj.id}) + self.assertEqual(object_to_dict(obj, ["value"], True), {"id": obj.id}) def test_with_id_no_blacklist(self): obj = MySingleSignalModel.objects.create(value=17) - self.assertEqual(object_to_dict(obj, include_id=True), {'id': obj.id, 'value': obj.value}) + self.assertEqual(object_to_dict(obj, include_id=True), {"id": obj.id, "value": obj.value}) def test_object_to_dict_valid_fields_append(self): obj = MySingleSignalModel.objects.create(value=17) @@ -27,5 +27,5 @@ def test_object_to_dict_valid_fields_append(self): valid_data = object_to_dict(dummy_instance) - self.assertIn('single_signal_id', valid_data) - self.assertEqual(valid_data['single_signal_id'], obj.id) + self.assertIn("single_signal_id", valid_data) + self.assertEqual(valid_data["single_signal_id"], obj.id) diff --git a/tests/test_utils_named_tuple.py b/tests/test_utils_named_tuple.py index f4c1c62..30977bf 100644 --- a/tests/test_utils_named_tuple.py +++ b/tests/test_utils_named_tuple.py @@ -21,10 +21,10 @@ def setUpClass(cls): ) cls.colors_choices = get_namedtuple_choices( - 'COLORS', + "COLORS", ( - (1, 'black', 'Black'), - (2, 'white', 'White'), + (1, "black", "Black"), + (2, "white", "White"), ), ) @@ -33,39 +33,39 @@ def test_get_namedtuple_choices_regular(self): self.assertEqual(self.colors_choices.white, 2) def test_get_namedtuple_choices_get_choices_regular(self): - self.assertEqual(self.colors_choices.get_choices(), [(1, 'Black'), (2, 'White')]) + self.assertEqual(self.colors_choices.get_choices(), [(1, "Black"), (2, "White")]) def test_get_namedtuple_choices_get_choices_dict_regular(self): - self.assertEqual(self.colors_choices.get_choices_dict(), OrderedDict([(1, 'Black'), (2, 'White')])) + self.assertEqual(self.colors_choices.get_choices_dict(), OrderedDict([(1, "Black"), (2, "White")])) def test_get_namedtuple_choices_get_all_regular(self): for index, color in enumerate(self.colors_choices.get_all()): expected_tuple = "invalid_data" if index == 0: - expected_tuple = (1, 'black', 'Black') + expected_tuple = (1, "black", "Black") elif index == 1: - expected_tuple = (2, 'white', 'White') + expected_tuple = (2, "white", "White") self.assertEqual(color, expected_tuple) def test_get_namedtuple_choices_get_choices_tuple_regular(self): - self.assertEqual(self.colors_choices.get_choices_tuple(), ((1, 'black', 'Black'), (2, 'white', 'White'))) + self.assertEqual(self.colors_choices.get_choices_tuple(), ((1, "black", "Black"), (2, "white", "White"))) def test_get_namedtuple_choices_get_values_regular(self): self.assertEqual(self.colors_choices.get_values(), [1, 2]) def test_get_namedtuple_choices_get_value_by_name_regular(self): - self.assertEqual(self.colors_choices.get_value_by_name('black'), 1) - self.assertEqual(self.colors_choices.get_value_by_name('white'), 2) - self.assertFalse(self.colors_choices.get_value_by_name('no-existing')) + self.assertEqual(self.colors_choices.get_value_by_name("black"), 1) + self.assertEqual(self.colors_choices.get_value_by_name("white"), 2) + self.assertFalse(self.colors_choices.get_value_by_name("no-existing")) def test_get_namedtuple_choices_get_desc_by_value_regular(self): - self.assertEqual(self.colors_choices.get_desc_by_value(1), 'Black') - self.assertEqual(self.colors_choices.get_desc_by_value(2), 'White') + self.assertEqual(self.colors_choices.get_desc_by_value(1), "Black") + self.assertEqual(self.colors_choices.get_desc_by_value(2), "White") self.assertFalse(self.colors_choices.get_desc_by_value(-1)) def test_get_namedtuple_choices_get_name_by_value_regular(self): - self.assertEqual(self.colors_choices.get_name_by_value(1), 'black') - self.assertEqual(self.colors_choices.get_name_by_value(2), 'white') + self.assertEqual(self.colors_choices.get_name_by_value(1), "black") + self.assertEqual(self.colors_choices.get_name_by_value(2), "white") self.assertFalse(self.colors_choices.get_name_by_value(-1)) def test_get_namedtuple_choices_is_valid_regular(self): @@ -74,24 +74,24 @@ def test_get_namedtuple_choices_is_valid_regular(self): self.assertFalse(self.colors_choices.is_valid(-1)) def test_get_value_from_tuple_by_key_found(self): - self.assertEqual(get_value_from_tuple_by_key(self.MY_CHOICE_LIST, self.MY_CHOICE_TWO), 'Choice 2') + self.assertEqual(get_value_from_tuple_by_key(self.MY_CHOICE_LIST, self.MY_CHOICE_TWO), "Choice 2") def test_get_value_from_tuple_by_key_not_found(self): - self.assertEqual(get_value_from_tuple_by_key(self.MY_CHOICE_LIST, 99), '-') + self.assertEqual(get_value_from_tuple_by_key(self.MY_CHOICE_LIST, 99), "-") def test_get_key_from_tuple_by_value_found(self): - self.assertEqual(get_key_from_tuple_by_value(self.MY_CHOICE_LIST, 'Choice 2'), self.MY_CHOICE_TWO) + self.assertEqual(get_key_from_tuple_by_value(self.MY_CHOICE_LIST, "Choice 2"), self.MY_CHOICE_TWO) def test_get_key_from_tuple_by_value_not_found(self): - self.assertEqual(get_key_from_tuple_by_value(self.MY_CHOICE_LIST, 'Something odd'), '-') + self.assertEqual(get_key_from_tuple_by_value(self.MY_CHOICE_LIST, "Something odd"), "-") def test_get_values_case_is_instance(self): choices = get_namedtuple_choices( - 'TestChoices', + "TestChoices", ( - (0, 'zero', 'Zero'), - (1, 'one', 'One'), - ([2, 3], 'two_three', 'Two Three'), + (0, "zero", "Zero"), + (1, "one", "One"), + ([2, 3], "two_three", "Two Three"), ), ) diff --git a/tests/test_utils_string.py b/tests/test_utils_string.py index d6c1be8..122bc6e 100644 --- a/tests/test_utils_string.py +++ b/tests/test_utils_string.py @@ -18,119 +18,119 @@ class UtilsStringTest(TestCase): def test_distinct_regular(self): - not_distinct_list = ['Beer', 'Wine', 'Whiskey', 'Beer'] + not_distinct_list = ["Beer", "Wine", "Whiskey", "Beer"] distinct_list = distinct(not_distinct_list) self.assertEqual(len(distinct_list), 3) - self.assertIn('Beer', distinct_list) - self.assertIn('Whiskey', distinct_list) - self.assertIn('Wine', distinct_list) + self.assertIn("Beer", distinct_list) + self.assertIn("Whiskey", distinct_list) + self.assertIn("Wine", distinct_list) def test_slugify_file_name_regular(self): - filename = 'hola and hello.txt' + filename = "hola and hello.txt" slug = slugify_file_name(filename) - self.assertEqual(slug, 'hola_and_hello.txt') + self.assertEqual(slug, "hola_and_hello.txt") def test_slugify_file_name_nothing_to_slugify(self): - filename = 'hola.txt' + filename = "hola.txt" slug = slugify_file_name(filename) self.assertEqual(slug, filename) def test_slugify_file_name_max_length(self): - filename = 'a very long filename.txt' + filename = "a very long filename.txt" slug = slugify_file_name(filename, 6) - self.assertEqual(slug, 'a_very.txt') + self.assertEqual(slug, "a_very.txt") def test_smart_truncate_in_word(self): - my_sentence = 'I am a very interesting sentence.' + my_sentence = "I am a very interesting sentence." truncated_str = smart_truncate(my_sentence, 10) - self.assertEqual(truncated_str, 'I am a...') + self.assertEqual(truncated_str, "I am a...") def test_smart_truncate_after_word(self): - my_sentence = 'I am a very interesting sentence.' + my_sentence = "I am a very interesting sentence." truncated_str = smart_truncate(my_sentence, 14) - self.assertEqual(truncated_str, 'I am a very...') + self.assertEqual(truncated_str, "I am a very...") def test_smart_truncate_changed_postfix(self): - my_sentence = 'I am a very interesting sentence.' - truncated_str = smart_truncate(my_sentence, 10, '[...]') - self.assertEqual(truncated_str, 'I am a[...]') + my_sentence = "I am a very interesting sentence." + truncated_str = smart_truncate(my_sentence, 10, "[...]") + self.assertEqual(truncated_str, "I am a[...]") def test_smart_truncate_not_cutting_on_too_short_strings(self): - my_sentence = 'I am a very interesting sentence.' - truncated_str = smart_truncate(my_sentence, 100, '---') + my_sentence = "I am a very interesting sentence." + truncated_str = smart_truncate(my_sentence, 100, "---") self.assertEqual(truncated_str, my_sentence) def test_smart_truncate_no_text(self): - truncated_str = smart_truncate(None, 100, '---') + truncated_str = smart_truncate(None, 100, "---") self.assertEqual(truncated_str, "") def test_float_to_string_regular(self): - self.assertEqual(float_to_string(5.61), '5,61') + self.assertEqual(float_to_string(5.61), "5,61") def test_float_to_string_value_replacement_not_used(self): - self.assertEqual(float_to_string(4.41, '-'), '4,41') + self.assertEqual(float_to_string(4.41, "-"), "4,41") def test_float_to_string_no_value_replacement_used(self): - self.assertEqual(float_to_string(None, 'Heureka'), 'Heureka') + self.assertEqual(float_to_string(None, "Heureka"), "Heureka") def test_float_to_string_value_greater_thousand(self): - self.assertEqual(float_to_string(1234.56), '1234,56') + self.assertEqual(float_to_string(1234.56), "1234,56") def test_date_to_string_regular(self): - self.assertEqual(date_to_string(datetime.date(2020, 9, 19)), '19.09.2020') + self.assertEqual(date_to_string(datetime.date(2020, 9, 19)), "19.09.2020") def test_date_to_string_other_format(self): - self.assertEqual(date_to_string(datetime.date(2020, 9, 19), str_format='%Y-%m-%d'), '2020-09-19') + self.assertEqual(date_to_string(datetime.date(2020, 9, 19), str_format="%Y-%m-%d"), "2020-09-19") def test_date_to_string_replacement_undefined(self): - self.assertEqual(date_to_string(None), '-') + self.assertEqual(date_to_string(None), "-") def test_date_to_string_replacement_defined(self): - self.assertEqual(date_to_string(None, 'no date'), 'no date') + self.assertEqual(date_to_string(None, "no date"), "no date") def test_datetime_to_string_regular(self): - self.assertEqual(datetime_to_string(datetime.datetime(2020, 9, 19, 8, tzinfo=pytz.UTC)), '19.09.2020 08:00') + self.assertEqual(datetime_to_string(datetime.datetime(2020, 9, 19, 8, tzinfo=pytz.UTC)), "19.09.2020 08:00") def test_datetime_to_string_other_format(self): self.assertEqual( - datetime_to_string(datetime.datetime(2020, 9, 19, 8, tzinfo=pytz.UTC), str_format='%Y-%m-%d'), '2020-09-19' + datetime_to_string(datetime.datetime(2020, 9, 19, 8, tzinfo=pytz.UTC), str_format="%Y-%m-%d"), "2020-09-19" ) def test_datetime_to_string_replacement_undefined(self): - self.assertEqual(datetime_to_string(None), '-') + self.assertEqual(datetime_to_string(None), "-") def test_datetime_to_string_replacement_defined(self): - self.assertEqual(datetime_to_string(None, 'no date'), 'no date') + self.assertEqual(datetime_to_string(None, "no date"), "no date") def test_number_to_string_regular(self): - self.assertEqual(number_to_string(5.61, decimal_digits=2), '5.61') + self.assertEqual(number_to_string(5.61, decimal_digits=2), "5.61") def test_number_to_string_value_replacement_not_used(self): - self.assertEqual(number_to_string(4.41, decimal_digits=2, replacement='-'), '4.41') + self.assertEqual(number_to_string(4.41, decimal_digits=2, replacement="-"), "4.41") def test_number_to_string_no_value_replacement_used(self): - self.assertEqual(number_to_string(None, replacement='Heureka'), 'Heureka') + self.assertEqual(number_to_string(None, replacement="Heureka"), "Heureka") def test_number_to_string_value_greater_thousand(self): - self.assertEqual(number_to_string(1234.56, decimal_digits=2), '1,234.56') + self.assertEqual(number_to_string(1234.56, decimal_digits=2), "1,234.56") def test_number_to_string_int_value_no_digits(self): - self.assertEqual(number_to_string(117), '117') + self.assertEqual(number_to_string(117), "117") def test_number_to_string_int_value_with_digits(self): - self.assertEqual(number_to_string(117, decimal_digits=2), '117.00') + self.assertEqual(number_to_string(117, decimal_digits=2), "117.00") def test_string_or_none_to_string_regular(self): - my_str = 'I am a string.' + my_str = "I am a string." self.assertEqual(string_or_none_to_string(my_str), my_str) def test_string_or_none_to_string_replacement_undefined(self): - self.assertEqual(string_or_none_to_string(None), '-') + self.assertEqual(string_or_none_to_string(None), "-") def test_string_or_none_to_string_replacement_defined(self): - self.assertEqual(string_or_none_to_string(None, 'no value'), 'no value') + self.assertEqual(string_or_none_to_string(None, "no value"), "no value") def test_encode_to_xml_regular(self): - xml_str = 'Something with an ampersand (&)' - self.assertEqual(encode_to_xml(xml_str), '<tag>Something with an ampersand (&)</tag>') + xml_str = "Something with an ampersand (&)" + self.assertEqual(encode_to_xml(xml_str), "<tag>Something with an ampersand (&)</tag>") diff --git a/tests/tests/mixins/test_django_message_framework.py b/tests/tests/mixins/test_django_message_framework.py index ec15338..410ce29 100644 --- a/tests/tests/mixins/test_django_message_framework.py +++ b/tests/tests/mixins/test_django_message_framework.py @@ -12,9 +12,9 @@ def setUpTestData(cls): cls.request = cls.get_request() def test_full_message_found(self): - messages.add_message(self.request, messages.INFO, 'My message') - self.assert_full_message_in_request(request=self.request, message='My message') + messages.add_message(self.request, messages.INFO, "My message") + self.assert_full_message_in_request(request=self.request, message="My message") def test_partial_message_found(self): - messages.add_message(self.request, messages.INFO, 'My message') - self.assert_partial_message_in_request(request=self.request, message='My') + messages.add_message(self.request, messages.INFO, "My message") + self.assert_partial_message_in_request(request=self.request, message="My") diff --git a/tests/tests/mixins/test_request_provider_mixin.py b/tests/tests/mixins/test_request_provider_mixin.py index 6daa6cc..0d6a772 100644 --- a/tests/tests/mixins/test_request_provider_mixin.py +++ b/tests/tests/mixins/test_request_provider_mixin.py @@ -14,7 +14,7 @@ def test_request_is_request(self): self.assertIsInstance(request, HttpRequest) def test_request_user_set(self): - user = User.objects.create(username='albertus_magnus') + user = User.objects.create(username="albertus_magnus") request = self.get_request(user) self.assertEqual(request.user, user) @@ -26,23 +26,23 @@ def test_django_messages_set_up_correctly(self): request = self.get_request(None) # This would fail if the django messages were not set up correctly - messages.add_message(request, messages.SUCCESS, 'I am a great message!') + messages.add_message(request, messages.SUCCESS, "I am a great message!") self.assertIsInstance(request.session, SessionBase) def test_django_session_set_up_correctly(self): request = self.get_request(None) - request.session['my_val'] = 27 + request.session["my_val"] = 27 request.session.modified = True - self.assertEqual(request.session['my_val'], 27) + self.assertEqual(request.session["my_val"], 27) def test_passed_user_is_none(self): request = self.get_request(None) self.assertIsNone(request.user) def test_passed_user_is_regular_user(self): - user = User.objects.create(username='albertus_magnus') + user = User.objects.create(username="albertus_magnus") request = self.get_request(user) self.assertEqual(request.user, user) @@ -58,8 +58,8 @@ def test_passed_user_is_other_type(self): def test_default_url_used(self): request = self.get_request() - self.assertEqual(request.build_absolute_uri(), 'http://testserver/') + self.assertEqual(request.build_absolute_uri(), "http://testserver/") def test_passed_url_used(self): - request = self.get_request(url='my-url') - self.assertEqual(request.build_absolute_uri(), 'http://testserver/my-url') + request = self.get_request(url="my-url") + self.assertEqual(request.build_absolute_uri(), "http://testserver/my-url") diff --git a/tests/tests/test_mail_backends.py b/tests/tests/test_mail_backends.py index 96b27cb..10f60b3 100644 --- a/tests/tests/test_mail_backends.py +++ b/tests/tests/test_mail_backends.py @@ -8,43 +8,43 @@ @override_settings( - EMAIL_BACKEND='ambient_toolbox.mail.backends.whitelist_smtp.WhitelistEmailBackend', - EMAIL_BACKEND_DOMAIN_WHITELIST=['valid.domain'], - EMAIL_BACKEND_REDIRECT_ADDRESS='%s@testuser.valid.domain', + EMAIL_BACKEND="ambient_toolbox.mail.backends.whitelist_smtp.WhitelistEmailBackend", + EMAIL_BACKEND_DOMAIN_WHITELIST=["valid.domain"], + EMAIL_BACKEND_REDIRECT_ADDRESS="%s@testuser.valid.domain", ) class MailBackendWhitelistBackendTest(TestCase): def test_whitify_mail_addresses_replace(self): - email_1 = 'albertus.magnus@example.com' - email_2 = 'thomas_von_aquin@example.com' + email_1 = "albertus.magnus@example.com" + email_2 = "thomas_von_aquin@example.com" processed_list = WhitelistEmailBackend.whitify_mail_addresses(mail_address_list=[email_1, email_2]) self.assertEqual(len(processed_list), 2) - self.assertEqual(processed_list[0], 'albertus.magnus_example.com@testuser.valid.domain') - self.assertEqual(processed_list[1], 'thomas_von_aquin_example.com@testuser.valid.domain') + self.assertEqual(processed_list[0], "albertus.magnus_example.com@testuser.valid.domain") + self.assertEqual(processed_list[1], "thomas_von_aquin_example.com@testuser.valid.domain") def test_whitify_mail_addresses_whitelisted_domain(self): - email = 'platon@valid.domain' + email = "platon@valid.domain" processed_list = WhitelistEmailBackend.whitify_mail_addresses(mail_address_list=[email]) self.assertEqual(len(processed_list), 1) self.assertEqual(processed_list[0], email) - @override_settings(EMAIL_BACKEND_REDIRECT_ADDRESS='') + @override_settings(EMAIL_BACKEND_REDIRECT_ADDRESS="") def test_whitify_mail_addresses_no_redirect_configured(self): - email = 'sokrates@example.com' + email = "sokrates@example.com" processed_list = WhitelistEmailBackend.whitify_mail_addresses(mail_address_list=[email]) self.assertEqual(len(processed_list), 0) def test_process_recipients_regular(self): mail = EmailMultiAlternatives( - 'Test subject', 'Here is the message.', 'from@example.com', ['to@example.com'], connection=None + "Test subject", "Here is the message.", "from@example.com", ["to@example.com"], connection=None ) backend = WhitelistEmailBackend() message_list = backend._process_recipients([mail]) self.assertEqual(len(message_list), 1) - self.assertEqual(message_list[0].to, ['to_example.com@testuser.valid.domain']) + self.assertEqual(message_list[0].to, ["to_example.com@testuser.valid.domain"]) @mock.patch.object(EmailBackend, "send_messages") @mock.patch.object(WhitelistEmailBackend, "_process_recipients") diff --git a/tests/view_layer/test_formset_mixins.py b/tests/view_layer/test_formset_mixins.py index f6d41ff..9e2792b 100644 --- a/tests/view_layer/test_formset_mixins.py +++ b/tests/view_layer/test_formset_mixins.py @@ -9,7 +9,7 @@ class ForeignKeyRelatedModelForm(forms.ModelForm): class Meta: model = ForeignKeyRelatedModel - fields = ('single_signal',) + fields = ("single_signal",) class MySingleSignalModelFormset(CountChildrenFormsetMixin, BaseInlineFormSet): @@ -47,10 +47,10 @@ def test_regular_with_data(self): ) formset = formset_class( - {'fkrm-INITIAL_FORMS': '2', 'fkrm-MIN_NUM_FORMS': '2', 'fkrm-MAX_NUM_FORMS': '3', 'fkrm-TOTAL_FORMS': '2'}, + {"fkrm-INITIAL_FORMS": "2", "fkrm-MIN_NUM_FORMS": "2", "fkrm-MAX_NUM_FORMS": "3", "fkrm-TOTAL_FORMS": "2"}, None, instance=mssm, - prefix='fkrm', + prefix="fkrm", ) formset.is_valid() diff --git a/tests/view_layer/test_htmx_response_mixin.py b/tests/view_layer/test_htmx_response_mixin.py index b4389bf..49c26c4 100644 --- a/tests/view_layer/test_htmx_response_mixin.py +++ b/tests/view_layer/test_htmx_response_mixin.py @@ -8,37 +8,37 @@ class HtmxResponseMixinTest(RequestProviderMixin, TestCase): class TestView(HtmxResponseMixin, generic.View): - hx_redirect_url = 'https://my-url.com' - hx_trigger = 'myEvent' + hx_redirect_url = "https://my-url.com" + hx_trigger = "myEvent" class TestViewWithTriggerDict(HtmxResponseMixin, generic.View): - hx_trigger = {'myEvent': None} + hx_trigger = {"myEvent": None} def test_dispatch_functional(self): view = self.TestView() response = view.dispatch(request=self.get_request(user=AnonymousUser())) - self.assertIn('HX-Redirect', response) - self.assertEqual(response['HX-Redirect'], 'https://my-url.com') + self.assertIn("HX-Redirect", response) + self.assertEqual(response["HX-Redirect"], "https://my-url.com") - self.assertIn('HX-Trigger', response) - self.assertEqual(response['HX-Trigger'], 'myEvent') + self.assertIn("HX-Trigger", response) + self.assertEqual(response["HX-Trigger"], "myEvent") def test_dispatch_trigger_with_dict(self): view = self.TestViewWithTriggerDict() response = view.dispatch(request=self.get_request(user=AnonymousUser())) - self.assertIn('HX-Trigger', response) - self.assertEqual(response['HX-Trigger'], "{\"myEvent\": null}") + self.assertIn("HX-Trigger", response) + self.assertEqual(response["HX-Trigger"], '{"myEvent": null}') def test_get_hx_redirect_url_regular(self): view = self.TestView() - self.assertEqual(view.get_hx_redirect_url(), 'https://my-url.com') + self.assertEqual(view.get_hx_redirect_url(), "https://my-url.com") def test_get_hx_trigger_regular(self): view = self.TestView() - self.assertEqual(view.get_hx_trigger(), 'myEvent') + self.assertEqual(view.get_hx_trigger(), "myEvent") diff --git a/tests/view_layer/test_meta_mixins.py b/tests/view_layer/test_meta_mixins.py index 08f44b3..50656c2 100644 --- a/tests/view_layer/test_meta_mixins.py +++ b/tests/view_layer/test_meta_mixins.py @@ -14,37 +14,37 @@ class TestViewNoPerms(DjangoPermissionRequiredMixin, generic.View): pass class TestViewSinglePerm(DjangoPermissionRequiredMixin, generic.View): - permission_list = ['auth.change_user'] + permission_list = ["auth.change_user"] login_view_name = "other-login-view" def get(self, *args, **kwargs): return HttpResponse(status=200) class TestViewMultiplePerms(DjangoPermissionRequiredMixin, generic.View): - permission_list = ['auth.change_user', 'auth.add_user'] + permission_list = ["auth.change_user", "auth.add_user"] def get_login_url(self): - return 'login/' + return "login/" class TestDifferentLoginNameView(DjangoPermissionRequiredMixin, generic.View): - permission_list = ['auth.change_user'] - login_view_name = 'other-login-view' + permission_list = ["auth.change_user"] + login_view_name = "other-login-view" @classmethod def setUpTestData(cls): super().setUpTestData() - cls.permission = Permission.objects.get_by_natural_key(app_label='auth', codename='change_user', model='user') + cls.permission = Permission.objects.get_by_natural_key(app_label="auth", codename="change_user", model="user") def setUp(self) -> None: super().setUp() - self.user = User.objects.create(username='test_user', email='test.user@ambient-toolbox.com') + self.user = User.objects.create(username="test_user", email="test.user@ambient-toolbox.com") def test_get_login_url(self): - self.assertEqual(self.TestViewMultiplePerms().get_login_url(), 'login/') + self.assertEqual(self.TestViewMultiplePerms().get_login_url(), "login/") def test_get_custom_login_url(self): - self.assertEqual(self.TestDifferentLoginNameView().get_login_url(), '/other/login/') + self.assertEqual(self.TestDifferentLoginNameView().get_login_url(), "/other/login/") def test_permissions_are_set_validation(self): with self.assertRaises(RuntimeError): diff --git a/tests/view_layer/test_views.py b/tests/view_layer/test_views.py index 0f44b8e..faa4dba 100644 --- a/tests/view_layer/test_views.py +++ b/tests/view_layer/test_views.py @@ -10,19 +10,19 @@ class UserInFormKwargsMixinTest(RequestProviderMixin, TestCase): def test_get_form_kwargs_regular(self): - user = User(username='my-user') + user = User(username="my-user") view = UserInFormKwargsMixinView() view.request = self.get_request(user=user) form_kwargs = view.get_form_kwargs() - self.assertIn('user', form_kwargs) - self.assertEqual(form_kwargs['user'], user) + self.assertIn("user", form_kwargs) + self.assertEqual(form_kwargs["user"], user) class ToggleViewTest(RequestProviderMixin, TestCase): def test_http_method_set_correctly(self): - self.assertEqual(ToggleView.http_method_names, ('post',)) + self.assertEqual(ToggleView.http_method_names, ("post",)) def test_post_raises_not_implemented_error(self): with self.assertRaises(NotImplementedError):