From faa12880a9814155eac55acf0701d70d0f455f30 Mon Sep 17 00:00:00 2001 From: Jeff Bradberry Date: Mon, 31 Jan 2022 18:12:20 -0500 Subject: [PATCH] Squash a few deprecation warnings - inspect.getargspec() -> inspect.getfullargspec() - register pytest.mark.fixture_args - replace use of DRF's deprecated NullBooleanField - fix some usage of naive datetimes in the tests - fix some strings with backslashes that ought to be raw strings --- awx/api/fields.py | 12 ++++++++---- awx/api/filters.py | 4 +--- awx/api/serializers.py | 2 +- awx/conf/fields.py | 14 +++++++------- awx/conf/migrations/_ldap_group_type.py | 2 +- awx/main/tasks/__init__.py | 1 + .../functional/api/test_unified_jobs_stdout.py | 13 +++++++------ awx/main/tests/unit/test_tasks.py | 18 +++++++++--------- awx/main/validators.py | 2 +- awx/settings/defaults.py | 3 ++- awx/sso/fields.py | 16 ++++++++-------- awx/ui/fields.py | 2 +- pytest.ini | 1 + 13 files changed, 48 insertions(+), 42 deletions(-) diff --git a/awx/api/fields.py b/awx/api/fields.py index 98c1bd8eac..c84b6327f9 100644 --- a/awx/api/fields.py +++ b/awx/api/fields.py @@ -28,13 +28,17 @@ class NullFieldMixin(object): return (is_empty_value, data) -class BooleanNullField(NullFieldMixin, serializers.NullBooleanField): +class BooleanNullField(NullFieldMixin, serializers.BooleanField): """ Custom boolean field that allows null and empty string as False values. """ + def __init__(self, **kwargs): + kwargs['allow_null'] = True + super().__init__(**kwargs) + def to_internal_value(self, data): - return bool(super(BooleanNullField, self).to_internal_value(data)) + return bool(super().to_internal_value(data)) class CharNullField(NullFieldMixin, serializers.CharField): @@ -47,7 +51,7 @@ class CharNullField(NullFieldMixin, serializers.CharField): super(CharNullField, self).__init__(**kwargs) def to_internal_value(self, data): - return super(CharNullField, self).to_internal_value(data or u'') + return super(CharNullField, self).to_internal_value(data or '') class ChoiceNullField(NullFieldMixin, serializers.ChoiceField): @@ -60,7 +64,7 @@ class ChoiceNullField(NullFieldMixin, serializers.ChoiceField): super(ChoiceNullField, self).__init__(**kwargs) def to_internal_value(self, data): - return super(ChoiceNullField, self).to_internal_value(data or u'') + return super(ChoiceNullField, self).to_internal_value(data or '') class VerbatimField(serializers.Field): diff --git a/awx/api/filters.py b/awx/api/filters.py index 2856e58f76..5d2af58f72 100644 --- a/awx/api/filters.py +++ b/awx/api/filters.py @@ -192,9 +192,7 @@ class FieldLookupBackend(BaseFilterBackend): return int(value) def value_to_python_for_field(self, field, value): - if isinstance(field, models.NullBooleanField): - return to_python_boolean(value, allow_none=True) - elif isinstance(field, models.BooleanField): + if isinstance(field, models.BooleanField): return to_python_boolean(value) elif isinstance(field, (ForeignObjectRel, ManyToManyField, GenericForeignKey, ForeignKey)): try: diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 4cd4f01fb6..a63e651840 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -3628,7 +3628,7 @@ class LaunchConfigurationBaseSerializer(BaseSerializer): job_tags = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None) limit = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None) skip_tags = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None) - diff_mode = serializers.NullBooleanField(required=False, default=None) + diff_mode = serializers.BooleanField(required=False, allow_null=True, default=None) verbosity = serializers.ChoiceField(allow_null=True, required=False, default=None, choices=VERBOSITY_CHOICES) exclude_errors = () diff --git a/awx/conf/fields.py b/awx/conf/fields.py index 889f71ca23..7802b2a085 100644 --- a/awx/conf/fields.py +++ b/awx/conf/fields.py @@ -10,7 +10,7 @@ from django.core.validators import URLValidator, _lazy_re_compile from django.utils.translation import gettext_lazy as _ # Django REST Framework -from rest_framework.fields import BooleanField, CharField, ChoiceField, DictField, DateTimeField, EmailField, IntegerField, ListField, NullBooleanField # noqa +from rest_framework.fields import BooleanField, CharField, ChoiceField, DictField, DateTimeField, EmailField, IntegerField, ListField # noqa from rest_framework.serializers import PrimaryKeyRelatedField # noqa # AWX @@ -65,11 +65,11 @@ class StringListBooleanField(ListField): try: if isinstance(value, (list, tuple)): return super(StringListBooleanField, self).to_representation(value) - elif value in NullBooleanField.TRUE_VALUES: + elif value in BooleanField.TRUE_VALUES: return True - elif value in NullBooleanField.FALSE_VALUES: + elif value in BooleanField.FALSE_VALUES: return False - elif value in NullBooleanField.NULL_VALUES: + elif value in BooleanField.NULL_VALUES: return None elif isinstance(value, str): return self.child.to_representation(value) @@ -82,11 +82,11 @@ class StringListBooleanField(ListField): try: if isinstance(data, (list, tuple)): return super(StringListBooleanField, self).to_internal_value(data) - elif data in NullBooleanField.TRUE_VALUES: + elif data in BooleanField.TRUE_VALUES: return True - elif data in NullBooleanField.FALSE_VALUES: + elif data in BooleanField.FALSE_VALUES: return False - elif data in NullBooleanField.NULL_VALUES: + elif data in BooleanField.NULL_VALUES: return None elif isinstance(data, str): return self.child.run_validation(data) diff --git a/awx/conf/migrations/_ldap_group_type.py b/awx/conf/migrations/_ldap_group_type.py index e8de5ca4aa..09caa2d28b 100644 --- a/awx/conf/migrations/_ldap_group_type.py +++ b/awx/conf/migrations/_ldap_group_type.py @@ -17,7 +17,7 @@ def fill_ldap_group_type_params(apps, schema_editor): else: entry = Setting(key='AUTH_LDAP_GROUP_TYPE_PARAMS', value=group_type_params, created=now(), modified=now()) - init_attrs = set(inspect.getargspec(group_type.__init__).args[1:]) + init_attrs = set(inspect.getfullargspec(group_type.__init__).args[1:]) for k in list(group_type_params.keys()): if k not in init_attrs: del group_type_params[k] diff --git a/awx/main/tasks/__init__.py b/awx/main/tasks/__init__.py index e69de29bb2..517df4a285 100644 --- a/awx/main/tasks/__init__.py +++ b/awx/main/tasks/__init__.py @@ -0,0 +1 @@ +from . import jobs, receptor, system # noqa diff --git a/awx/main/tests/functional/api/test_unified_jobs_stdout.py b/awx/main/tests/functional/api/test_unified_jobs_stdout.py index acfc7a0459..dad55c5ba0 100644 --- a/awx/main/tests/functional/api/test_unified_jobs_stdout.py +++ b/awx/main/tests/functional/api/test_unified_jobs_stdout.py @@ -3,11 +3,12 @@ import base64 import json import re -from datetime import datetime +from unittest import mock from django.conf import settings from django.utils.encoding import smart_str -from unittest import mock +from django.utils.timezone import now as tz_now + import pytest from awx.api.versioning import reverse @@ -146,7 +147,7 @@ def test_stdout_line_range(sqlite_copy_expert, Parent, Child, relation, view, ge @pytest.mark.django_db def test_text_stdout_from_system_job_events(sqlite_copy_expert, get, admin): - created = datetime.utcnow() + created = tz_now() job = SystemJob(created=created) job.save() for i in range(3): @@ -158,7 +159,7 @@ def test_text_stdout_from_system_job_events(sqlite_copy_expert, get, admin): @pytest.mark.django_db def test_text_stdout_with_max_stdout(sqlite_copy_expert, get, admin): - created = datetime.utcnow() + created = tz_now() job = SystemJob(created=created) job.save() total_bytes = settings.STDOUT_MAX_BYTES_DISPLAY + 1 @@ -185,7 +186,7 @@ def test_text_stdout_with_max_stdout(sqlite_copy_expert, get, admin): @pytest.mark.parametrize('fmt', ['txt', 'ansi']) @mock.patch('awx.main.redact.UriCleaner.SENSITIVE_URI_PATTERN', mock.Mock(**{'search.return_value': None})) # really slow for large strings def test_max_bytes_display(sqlite_copy_expert, Parent, Child, relation, view, fmt, get, admin): - created = datetime.utcnow() + created = tz_now() job = Parent(created=created) job.save() total_bytes = settings.STDOUT_MAX_BYTES_DISPLAY + 1 @@ -267,7 +268,7 @@ def test_text_with_unicode_stdout(sqlite_copy_expert, Parent, Child, relation, v @pytest.mark.django_db def test_unicode_with_base64_ansi(sqlite_copy_expert, get, admin): - created = datetime.utcnow() + created = tz_now() job = Job(created=created) job.save() for i in range(3): diff --git a/awx/main/tests/unit/test_tasks.py b/awx/main/tests/unit/test_tasks.py index 200a027e36..69a7f03c33 100644 --- a/awx/main/tests/unit/test_tasks.py +++ b/awx/main/tests/unit/test_tasks.py @@ -788,7 +788,7 @@ class TestJobCredentials(TestJobExecution): password_prompts = task.get_password_prompts(passwords) expect_passwords = task.create_expect_passwords_data_struct(password_prompts, passwords) - assert expect_passwords['Vault password:\s*?$'] == 'vault-me' # noqa + assert expect_passwords[r'Vault password:\s*?$'] == 'vault-me' # noqa assert '--ask-vault-pass' in ' '.join(args) def test_vault_password_ask(self, private_data_dir, job, mock_me): @@ -803,7 +803,7 @@ class TestJobCredentials(TestJobExecution): password_prompts = task.get_password_prompts(passwords) expect_passwords = task.create_expect_passwords_data_struct(password_prompts, passwords) - assert expect_passwords['Vault password:\s*?$'] == 'provided-at-launch' # noqa + assert expect_passwords[r'Vault password:\s*?$'] == 'provided-at-launch' # noqa assert '--ask-vault-pass' in ' '.join(args) def test_multi_vault_password(self, private_data_dir, job, mock_me): @@ -820,10 +820,10 @@ class TestJobCredentials(TestJobExecution): expect_passwords = task.create_expect_passwords_data_struct(password_prompts, passwords) vault_passwords = dict((k, v) for k, v in expect_passwords.items() if 'Vault' in k) - assert vault_passwords['Vault password \(prod\):\\s*?$'] == 'pass@prod' # noqa - assert vault_passwords['Vault password \(dev\):\\s*?$'] == 'pass@dev' # noqa - assert vault_passwords['Vault password \(dotted.name\):\\s*?$'] == 'pass@dotted.name' # noqa - assert vault_passwords['Vault password:\\s*?$'] == '' # noqa + assert vault_passwords[r'Vault password \(prod\):\s*?$'] == 'pass@prod' # noqa + assert vault_passwords[r'Vault password \(dev\):\s*?$'] == 'pass@dev' # noqa + assert vault_passwords[r'Vault password \(dotted.name\):\s*?$'] == 'pass@dotted.name' # noqa + assert vault_passwords[r'Vault password:\s*?$'] == '' # noqa assert '--ask-vault-pass' not in ' '.join(args) assert '--vault-id dev@prompt' in ' '.join(args) assert '--vault-id prod@prompt' in ' '.join(args) @@ -855,9 +855,9 @@ class TestJobCredentials(TestJobExecution): expect_passwords = task.create_expect_passwords_data_struct(password_prompts, passwords) vault_passwords = dict((k, v) for k, v in expect_passwords.items() if 'Vault' in k) - assert vault_passwords['Vault password \(prod\):\\s*?$'] == 'provided-at-launch@prod' # noqa - assert vault_passwords['Vault password \(dev\):\\s*?$'] == 'provided-at-launch@dev' # noqa - assert vault_passwords['Vault password:\\s*?$'] == '' # noqa + assert vault_passwords[r'Vault password \(prod\):\s*?$'] == 'provided-at-launch@prod' # noqa + assert vault_passwords[r'Vault password \(dev\):\s*?$'] == 'provided-at-launch@dev' # noqa + assert vault_passwords[r'Vault password:\s*?$'] == '' # noqa assert '--ask-vault-pass' not in ' '.join(args) assert '--vault-id dev@prompt' in ' '.join(args) assert '--vault-id prod@prompt' in ' '.join(args) diff --git a/awx/main/validators.py b/awx/main/validators.py index 4cd0e25459..751d38060b 100644 --- a/awx/main/validators.py +++ b/awx/main/validators.py @@ -198,7 +198,7 @@ def vars_validate_or_raise(vars_str): def validate_container_image_name(value): - """ + r""" from https://github.com/distribution/distribution/blob/af8ac809336c2316c81b08605d92d94f8670ad15/reference/reference.go#L4 Grammar diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py index fcd422a3dd..75a49862a1 100644 --- a/awx/settings/defaults.py +++ b/awx/settings/defaults.py @@ -152,7 +152,8 @@ SITE_ID = 1 # Make this unique, and don't share it with anybody. if os.path.exists('/etc/tower/SECRET_KEY'): - SECRET_KEY = open('/etc/tower/SECRET_KEY', 'rb').read().strip() + with open('/etc/tower/SECRET_KEY', 'rb') as f: + SECRET_KEY = f.read().strip() else: SECRET_KEY = base64.encodebytes(os.urandom(32)).decode().rstrip() diff --git a/awx/sso/fields.py b/awx/sso/fields.py index e2c87d97f2..9ad016f594 100644 --- a/awx/sso/fields.py +++ b/awx/sso/fields.py @@ -457,7 +457,7 @@ class LDAPGroupTypeField(fields.ChoiceField, DependsOnMixin): params = self.get_depends_on() or {} params_sanitized = dict() - cls_args = inspect.getargspec(cls.__init__).args[1:] + cls_args = inspect.getfullargspec(cls.__init__).args[1:] if cls_args: if not isinstance(params, dict): @@ -488,7 +488,7 @@ class LDAPGroupTypeParamsField(fields.DictField, DependsOnMixin): # Fail safe return {} - invalid_keys = set(value.keys()) - set(inspect.getargspec(group_type_cls.__init__).args[1:]) + invalid_keys = set(value.keys()) - set(inspect.getfullargspec(group_type_cls.__init__).args[1:]) if invalid_keys: invalid_keys = sorted(list(invalid_keys)) keys_display = json.dumps(invalid_keys).lstrip('[').rstrip(']') @@ -583,11 +583,11 @@ class SocialMapField(fields.ListField): def to_representation(self, value): if isinstance(value, (list, tuple)): return super(SocialMapField, self).to_representation(value) - elif value in fields.NullBooleanField.TRUE_VALUES: + elif value in fields.BooleanField.TRUE_VALUES: return True - elif value in fields.NullBooleanField.FALSE_VALUES: + elif value in fields.BooleanField.FALSE_VALUES: return False - elif value in fields.NullBooleanField.NULL_VALUES: + elif value in fields.BooleanField.NULL_VALUES: return None elif isinstance(value, (str, type(re.compile('')))): return self.child.to_representation(value) @@ -597,11 +597,11 @@ class SocialMapField(fields.ListField): def to_internal_value(self, data): if isinstance(data, (list, tuple)): return super(SocialMapField, self).to_internal_value(data) - elif data in fields.NullBooleanField.TRUE_VALUES: + elif data in fields.BooleanField.TRUE_VALUES: return True - elif data in fields.NullBooleanField.FALSE_VALUES: + elif data in fields.BooleanField.FALSE_VALUES: return False - elif data in fields.NullBooleanField.NULL_VALUES: + elif data in fields.BooleanField.NULL_VALUES: return None elif isinstance(data, str): return self.child.run_validation(data) diff --git a/awx/ui/fields.py b/awx/ui/fields.py index 2200de3417..37089c0265 100644 --- a/awx/ui/fields.py +++ b/awx/ui/fields.py @@ -16,7 +16,7 @@ from awx.conf import fields class PendoTrackingStateField(fields.ChoiceField): def to_internal_value(self, data): # Any false/null values get converted to 'off'. - if data in fields.NullBooleanField.FALSE_VALUES or data in fields.NullBooleanField.NULL_VALUES: + if data in fields.BooleanField.FALSE_VALUES or data in fields.BooleanField.NULL_VALUES: return 'off' return super(PendoTrackingStateField, self).to_internal_value(data) diff --git a/pytest.ini b/pytest.ini index d5d7273433..d4ffd2db9b 100644 --- a/pytest.ini +++ b/pytest.ini @@ -12,4 +12,5 @@ markers = job_permissions: activity_stream_access: job_runtime_vars: + fixture_args: junit_family=xunit2