diff --git a/awx/api/authentication.py b/awx/api/authentication.py index 430c8098fd..bc3aaa15ed 100644 --- a/awx/api/authentication.py +++ b/awx/api/authentication.py @@ -21,7 +21,7 @@ class LoggedBasicAuthentication(authentication.BasicAuthentication): ret = super(LoggedBasicAuthentication, self).authenticate(request) if ret: username = ret[0].username if ret[0] else '' - logger.info(smart_str(u"User {} performed a {} to {} through the API".format(username, request.method, request.path))) + logger.info(smart_str("User {} performed a {} to {} through the API".format(username, request.method, request.path))) return ret def authenticate_header(self, request): diff --git a/awx/api/generics.py b/awx/api/generics.py index 67b0d46dd8..5e92842b39 100644 --- a/awx/api/generics.py +++ b/awx/api/generics.py @@ -81,7 +81,6 @@ analytics_logger = logging.getLogger('awx.analytics.performance') class LoggedLoginView(auth_views.LoginView): - def get(self, request, *args, **kwargs): if is_proxied_request(): next = request.GET.get('next', "") @@ -116,7 +115,7 @@ class LoggedLoginView(auth_views.LoginView): ret = super(LoggedLoginView, self).post(request, *args, **kwargs) ip = get_remote_host(request) # request.META.get('REMOTE_ADDR', None) if request.user.is_authenticated: - logger.info(smart_str(u"User {} logged in from {}".format(self.request.user.username, ip))) + logger.info(smart_str("User {} logged in from {}".format(self.request.user.username, ip))) ret.set_cookie( 'userLoggedIn', 'true', secure=getattr(settings, 'SESSION_COOKIE_SECURE', False), samesite=getattr(settings, 'USER_COOKIE_SAMESITE', 'Lax') ) @@ -125,7 +124,7 @@ class LoggedLoginView(auth_views.LoginView): return ret else: if 'username' in self.request.POST: - logger.warning(smart_str(u"Login failed for user {} from {}".format(self.request.POST.get('username'), ip))) + logger.warning(smart_str("Login failed for user {} from {}".format(self.request.POST.get('username'), ip))) ret.status_code = 401 return ret diff --git a/awx/api/metadata.py b/awx/api/metadata.py index 22eab14545..53999574a8 100644 --- a/awx/api/metadata.py +++ b/awx/api/metadata.py @@ -171,8 +171,7 @@ class Metadata(metadata.SimpleMetadata): ): field_info['type'] = 'json' elif ( - isinstance(field, ManyRelatedField) - and field.field_name == 'credentials' + isinstance(field, ManyRelatedField) and field.field_name == 'credentials' # launch-time credentials ): field_info['type'] = 'list_of_ids' diff --git a/awx/api/schema.py b/awx/api/schema.py index 0383111443..efab2a6a47 100644 --- a/awx/api/schema.py +++ b/awx/api/schema.py @@ -99,9 +99,9 @@ class CustomAutoSchema(AutoSchema): except Exception: serializer = None warnings.warn( - '{}.get_serializer() raised an exception during ' - 'schema generation. Serializer fields will not be ' - 'generated for this view.'.format(self.view.__class__.__name__) + '{}.get_serializer() raised an exception during schema generation. Serializer fields will not be generated for this view.'.format( + self.view.__class__.__name__ + ) ) if hasattr(self.view, 'swagger_topic'): diff --git a/awx/api/serializers.py b/awx/api/serializers.py index d87ff574cb..d52b9ca8c1 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -1292,9 +1292,9 @@ class ProjectOptionsSerializer(BaseSerializer): # Don't allow assigning a local_path when scm_type is set. valid_local_paths = Project.get_local_path_choices() if self.instance: - scm_type = attrs.get('scm_type', self.instance.scm_type) or u'' + scm_type = attrs.get('scm_type', self.instance.scm_type) or '' else: - scm_type = attrs.get('scm_type', u'') or u'' + scm_type = attrs.get('scm_type', '') or '' if self.instance and not scm_type: valid_local_paths.append(self.instance.local_path) if self.instance and scm_type and "local_path" in attrs and self.instance.local_path != attrs['local_path']: @@ -1914,7 +1914,7 @@ class HostSerializer(BaseSerializerWithVariables): if port < 1 or port > 65535: raise ValueError except ValueError: - raise serializers.ValidationError(_(u'Invalid port specification: %s') % force_str(port)) + raise serializers.ValidationError(_('Invalid port specification: %s') % force_str(port)) return name, port def validate_name(self, value): @@ -3595,7 +3595,7 @@ class JobRelaunchSerializer(BaseSerializer): res = super(JobRelaunchSerializer, self).to_representation(obj) view = self.context.get('view', None) if hasattr(view, '_raw_data_form_marker'): - password_keys = dict([(p, u'') for p in self.get_passwords_needed_to_start(obj)]) + password_keys = dict([(p, '') for p in self.get_passwords_needed_to_start(obj)]) res.update(password_keys) return res @@ -3765,7 +3765,7 @@ class AdHocCommandRelaunchSerializer(AdHocCommandSerializer): def to_representation(self, obj): if obj: - return dict([(p, u'') for p in obj.passwords_needed_to_start]) + return dict([(p, '') for p in obj.passwords_needed_to_start]) else: return {} diff --git a/awx/api/views/__init__.py b/awx/api/views/__init__.py index 1344a0bdd7..f68f52decf 100644 --- a/awx/api/views/__init__.py +++ b/awx/api/views/__init__.py @@ -1768,11 +1768,15 @@ class CredentialExternalTest(OIDCCredentialTestMixin, SubDetailAPIView): obj_permission_type = 'use' resource_purpose = 'test external credential' - @extend_schema_if_available(extensions={"x-ai-description": """Test update the input values and metadata of an external credential. + @extend_schema_if_available( + extensions={ + "x-ai-description": """Test update the input values and metadata of an external credential. This endpoint supports testing credentials that connect to external secret management systems such as CyberArk AIM, CyberArk Conjur, HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, Centrify Vault, Thycotic DevOps Secrets Vault, and GitHub App Installation Access Token Lookup. - It does not support standard credential types such as Machine, SCM, and Cloud."""}) + It does not support standard credential types such as Machine, SCM, and Cloud.""" + } + ) def post(self, request, *args, **kwargs): obj = self.get_object() if obj.credential_type.kind != 'external': @@ -2692,11 +2696,11 @@ class JobTemplateLaunch(RetrieveAPIView): if needed_passwords: data['credential_passwords'] = {} for p in needed_passwords: - data['credential_passwords'][p] = u'' + data['credential_passwords'][p] = '' else: data.pop('credential_passwords') for v in obj.variables_needed_to_start: - extra_vars.setdefault(v, u'') + extra_vars.setdefault(v, '') if extra_vars: data['extra_vars'] = extra_vars modified_ask_mapping = models.JobTemplate.get_ask_mapping() @@ -3347,7 +3351,7 @@ class WorkflowJobTemplateNodeChildrenBaseList(EnforceParentRelationshipMixin, Su ''' relationships = ['success_nodes', 'failure_nodes', 'always_nodes'] relationships.remove(self.relationship) - qs = functools.reduce(lambda x, y: (x | y), (Q(**{'{}__in'.format(r): [sub.id]}) for r in relationships)) + qs = functools.reduce(lambda x, y: x | y, (Q(**{'{}__in'.format(r): [sub.id]}) for r in relationships)) if models.WorkflowJobTemplateNode.objects.filter(Q(pk=parent.id) & qs).exists(): return {"Error": _("Relationship not allowed.")} @@ -3548,7 +3552,7 @@ class WorkflowJobTemplateLaunch(RetrieveAPIView): extra_vars = data.pop('extra_vars', None) or {} if obj: for v in obj.variables_needed_to_start: - extra_vars.setdefault(v, u'') + extra_vars.setdefault(v, '') if extra_vars: data['extra_vars'] = extra_vars modified_ask_mapping = models.WorkflowJobTemplate.get_ask_mapping() @@ -3958,7 +3962,7 @@ class JobRelaunch(RetrieveAPIView): if needed_passwords: data['credential_passwords'] = {} for p in needed_passwords: - data['credential_passwords'][p] = u'' + data['credential_passwords'][p] = '' else: data.pop('credential_passwords', None) return data diff --git a/awx/api/views/root.py b/awx/api/views/root.py index 4f01bf2d23..777a5fc5e3 100644 --- a/awx/api/views/root.py +++ b/awx/api/views/root.py @@ -246,7 +246,7 @@ class ApiV2SubscriptionView(APIView): elif isinstance(exc, (ValueError, OSError)) and exc.args: msg = exc.args[0] else: - logger.exception(smart_str(u"Invalid subscription submitted."), extra=dict(actor=request.user.username)) + logger.exception(smart_str("Invalid subscription submitted."), extra=dict(actor=request.user.username)) return Response({"error": msg}, status=status.HTTP_400_BAD_REQUEST) return Response(validated) @@ -298,7 +298,7 @@ class ApiV2AttachView(APIView): elif isinstance(exc, (ValueError, OSError)) and exc.args: msg = exc.args[0] else: - logger.exception(smart_str(u"Invalid subscription submitted."), extra=dict(actor=request.user.username)) + logger.exception(smart_str("Invalid subscription submitted."), extra=dict(actor=request.user.username)) return Response({"error": msg}, status=status.HTTP_400_BAD_REQUEST) for sub in validated: @@ -381,7 +381,7 @@ class ApiV2ConfigView(APIView): try: data_actual = json.dumps(request.data) except Exception: - logger.info(smart_str(u"Invalid JSON submitted for license."), extra=dict(actor=request.user.username)) + logger.info(smart_str("Invalid JSON submitted for license."), extra=dict(actor=request.user.username)) return Response({"error": _("Invalid JSON")}, status=status.HTTP_400_BAD_REQUEST) license_data = json.loads(data_actual) @@ -406,7 +406,7 @@ class ApiV2ConfigView(APIView): license_data_validated = get_licenser().license_from_manifest(license_data) connection.on_commit(lambda: clear_setting_cache.delay(['LICENSE'])) except Exception: - logger.warning(smart_str(u"Invalid subscription submitted."), extra=dict(actor=request.user.username)) + logger.warning(smart_str("Invalid subscription submitted."), extra=dict(actor=request.user.username)) return Response({"error": _("Invalid License")}, status=status.HTTP_400_BAD_REQUEST) else: license_data_validated = get_licenser().validate() @@ -417,7 +417,7 @@ class ApiV2ConfigView(APIView): settings.TOWER_URL_BASE = "{}://{}".format(request.scheme, request.get_host()) return Response(license_data_validated) - logger.warning(smart_str(u"Invalid subscription submitted."), extra=dict(actor=request.user.username)) + logger.warning(smart_str("Invalid subscription submitted."), extra=dict(actor=request.user.username)) return Response({"error": _("Invalid subscription")}, status=status.HTTP_400_BAD_REQUEST) @extend_schema_if_available( diff --git a/awx/conf/models.py b/awx/conf/models.py index e4442fcecf..788f130e46 100644 --- a/awx/conf/models.py +++ b/awx/conf/models.py @@ -27,11 +27,11 @@ class Setting(CreatedModifiedModel): json_value = json.dumps(self.value) except ValueError: # In the rare case the DB value is invalid JSON. - json_value = u'' + json_value = '' if self.user: - return u'{} ({}) = {}'.format(self.key, self.user, json_value) + return '{} ({}) = {}'.format(self.key, self.user, json_value) else: - return u'{} = {}'.format(self.key, json_value) + return '{} = {}'.format(self.key, json_value) def save(self, *args, **kwargs): encrypted = settings_registry.is_setting_encrypted(self.key) diff --git a/awx/conf/tests/functional/test_api.py b/awx/conf/tests/functional/test_api.py index 183fd7b8b6..9a398d5742 100644 --- a/awx/conf/tests/functional/test_api.py +++ b/awx/conf/tests/functional/test_api.py @@ -53,8 +53,9 @@ def test_non_admin_user_does_not_see_categories(api_request, dummy_setting, norm @pytest.mark.django_db def test_setting_singleton_detail_retrieve(api_request, dummy_setting): - with dummy_setting('FOO_BAR_1', field_class=fields.IntegerField, category='FooBar', category_slug='foobar'), dummy_setting( - 'FOO_BAR_2', field_class=fields.IntegerField, category='FooBar', category_slug='foobar' + with ( + dummy_setting('FOO_BAR_1', field_class=fields.IntegerField, category='FooBar', category_slug='foobar'), + dummy_setting('FOO_BAR_2', field_class=fields.IntegerField, category='FooBar', category_slug='foobar'), ): response = api_request('get', reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'})) assert response.status_code == 200 @@ -64,8 +65,9 @@ def test_setting_singleton_detail_retrieve(api_request, dummy_setting): @pytest.mark.django_db def test_setting_singleton_detail_invalid_retrieve(api_request, dummy_setting, normal_user): - with dummy_setting('FOO_BAR_1', field_class=fields.IntegerField, category='FooBar', category_slug='foobar'), dummy_setting( - 'FOO_BAR_2', field_class=fields.IntegerField, category='FooBar', category_slug='foobar' + with ( + dummy_setting('FOO_BAR_1', field_class=fields.IntegerField, category='FooBar', category_slug='foobar'), + dummy_setting('FOO_BAR_2', field_class=fields.IntegerField, category='FooBar', category_slug='foobar'), ): response = api_request('get', reverse('api:setting_singleton_detail', kwargs={'category_slug': 'barfoo'})) assert response.status_code == 404 @@ -104,8 +106,9 @@ def test_setting_singleton_update(api_request, dummy_setting): @pytest.mark.django_db def test_setting_singleton_update_dont_change_readonly_fields(api_request, dummy_setting): - with dummy_setting('FOO_BAR', field_class=fields.IntegerField, read_only=True, default=4, category='FooBar', category_slug='foobar'), mock.patch( - 'awx.conf.views.clear_setting_cache' + with ( + dummy_setting('FOO_BAR', field_class=fields.IntegerField, read_only=True, default=4, category='FooBar', category_slug='foobar'), + mock.patch('awx.conf.views.clear_setting_cache'), ): api_request('patch', reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'}), data={'FOO_BAR': 5}) response = api_request('get', reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'})) @@ -114,8 +117,9 @@ def test_setting_singleton_update_dont_change_readonly_fields(api_request, dummy @pytest.mark.django_db def test_setting_singleton_update_dont_change_encrypted_mark(api_request, dummy_setting): - with dummy_setting('FOO_BAR', field_class=fields.CharField, encrypted=True, category='FooBar', category_slug='foobar'), mock.patch( - 'awx.conf.views.clear_setting_cache' + with ( + dummy_setting('FOO_BAR', field_class=fields.CharField, encrypted=True, category='FooBar', category_slug='foobar'), + mock.patch('awx.conf.views.clear_setting_cache'), ): api_request('patch', reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'}), data={'FOO_BAR': 'password'}) assert Setting.objects.get(key='FOO_BAR').value.startswith('$encrypted$') @@ -132,9 +136,11 @@ def test_setting_singleton_update_runs_custom_validate(api_request, dummy_settin def func_raising_exception(serializer, attrs): raise serializers.ValidationError('Error') - with dummy_setting('FOO_BAR', field_class=fields.IntegerField, category='FooBar', category_slug='foobar'), dummy_validate( - 'foobar', func_raising_exception - ), mock.patch('awx.conf.views.clear_setting_cache'): + with ( + dummy_setting('FOO_BAR', field_class=fields.IntegerField, category='FooBar', category_slug='foobar'), + dummy_validate('foobar', func_raising_exception), + mock.patch('awx.conf.views.clear_setting_cache'), + ): response = api_request('patch', reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'}), data={'FOO_BAR': 23}) assert response.status_code == 400 @@ -149,8 +155,9 @@ def test_setting_singleton_delete(api_request, dummy_setting): @pytest.mark.django_db def test_setting_singleton_delete_no_read_only_fields(api_request, dummy_setting): - with dummy_setting('FOO_BAR', field_class=fields.IntegerField, read_only=True, default=23, category='FooBar', category_slug='foobar'), mock.patch( - 'awx.conf.views.clear_setting_cache' + with ( + dummy_setting('FOO_BAR', field_class=fields.IntegerField, read_only=True, default=23, category='FooBar', category_slug='foobar'), + mock.patch('awx.conf.views.clear_setting_cache'), ): api_request('delete', reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'})) response = api_request('get', reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'})) diff --git a/awx/main/analytics/collectors.py b/awx/main/analytics/collectors.py index 8e5c1f9cf0..2939d415da 100644 --- a/awx/main/analytics/collectors.py +++ b/awx/main/analytics/collectors.py @@ -227,7 +227,7 @@ def counts(since, **kwargs): counts['pending_jobs'] = models.UnifiedJob.objects.exclude(launch_type='sync').filter(status__in=('pending',)).count() if connection.vendor == 'postgresql': with connection.cursor() as cursor: - cursor.execute(f"select count(*) from pg_stat_activity where datname=\'{connection.settings_dict['NAME']}\'") + cursor.execute(f"select count(*) from pg_stat_activity where datname='{connection.settings_dict['NAME']}'") counts['database_connections'] = cursor.fetchone()[0] else: # We should be using postgresql, but if we do that change that ever we should change the below value @@ -441,7 +441,7 @@ def _events_table(since, full_path, until, tbl, where_column, project_job_create WHERE ({tbl}.{where_column} > '{since.isoformat()}' AND {tbl}.{where_column} <= '{until.isoformat()}')) TO STDOUT WITH CSV HEADER''' return query - return _copy_table(table='events', query=query(fr"replace({tbl}.event_data, '\u', '\u005cu')::jsonb"), path=full_path) + return _copy_table(table='events', query=query(rf"replace({tbl}.event_data, '\u', '\u005cu')::jsonb"), path=full_path) @register('events_table', '1.5', format='csv', description=_('Automation task records'), expensive=four_hour_slicing) diff --git a/awx/main/analytics/subsystem_metrics.py b/awx/main/analytics/subsystem_metrics.py index 07f141d266..db0295351f 100644 --- a/awx/main/analytics/subsystem_metrics.py +++ b/awx/main/analytics/subsystem_metrics.py @@ -181,7 +181,9 @@ class HistogramM(BaseM): node_label = f'node="{instance}"' subsystem_label = f',subsystem="{namespace}"' if namespace else '' for i, b in enumerate(self.buckets): - output_text += f'{self.field}_bucket{{le="{b}",{node_label}{subsystem_label}}} {sum(instance_data[instance][self.field]["counts"][0:i+1])}\n' + output_text += ( + f'{self.field}_bucket{{le="{b}",{node_label}{subsystem_label}}} {sum(instance_data[instance][self.field]["counts"][0 : i + 1])}\n' + ) output_text += f'{self.field}_bucket{{le="+Inf",{node_label}{subsystem_label}}} {instance_data[instance][self.field]["inf"]}\n' output_text += f'{self.field}_count{{{node_label}{subsystem_label}}} {instance_data[instance][self.field]["inf"]}\n' output_text += f'{self.field}_sum{{{node_label}{subsystem_label}}} {instance_data[instance][self.field]["sum"]}\n' diff --git a/awx/main/apps.py b/awx/main/apps.py index c39c882ec7..3793781cfb 100644 --- a/awx/main/apps.py +++ b/awx/main/apps.py @@ -39,8 +39,7 @@ class MainConfig(AppConfig): read_only=True, label=_('List of all named url graph nodes.'), help_text=_( - 'Read-only list of key-value pairs that exposes named URL graph topology.' - ' Use this list to programmatically generate named URLs for resources' + 'Read-only list of key-value pairs that exposes named URL graph topology. Use this list to programmatically generate named URLs for resources' ), category=_('Named URL'), category_slug='named-url', diff --git a/awx/main/conf.py b/awx/main/conf.py index 39bd206b09..85b640c83f 100644 --- a/awx/main/conf.py +++ b/awx/main/conf.py @@ -488,7 +488,7 @@ register( min_value=0, label=_('Job Event Standard Output Maximum Display Size'), help_text=_( - u'Maximum Size of Standard Output in bytes to display for a single job or ad hoc command event. `stdout` will end with `\u2026` when truncated.' + 'Maximum Size of Standard Output in bytes to display for a single job or ad hoc command event. `stdout` will end with `\u2026` when truncated.' ), category=_('Jobs'), category_slug='jobs', @@ -722,9 +722,7 @@ register( default='https', label=_('Logging Aggregator Protocol'), help_text=_( - 'Protocol used to communicate with log aggregator. ' - 'HTTPS/HTTP assumes HTTPS unless http:// is explicitly used in ' - 'the Logging Aggregator hostname.' + 'Protocol used to communicate with log aggregator. HTTPS/HTTP assumes HTTPS unless http:// is explicitly used in the Logging Aggregator hostname.' ), category=_('Logging'), category_slug='logging', diff --git a/awx/main/dispatch/worker/base.py b/awx/main/dispatch/worker/base.py index 8860238f13..28fc219b7b 100644 --- a/awx/main/dispatch/worker/base.py +++ b/awx/main/dispatch/worker/base.py @@ -20,7 +20,6 @@ def signame(sig): class AWXConsumerRedis(object): - def __init__(self, name, worker): self.name = name self.pool = WorkerPool() diff --git a/awx/main/dispatch/worker/dispatcherd.py b/awx/main/dispatch/worker/dispatcherd.py index 72cfadf799..a03bccf818 100644 --- a/awx/main/dispatch/worker/dispatcherd.py +++ b/awx/main/dispatch/worker/dispatcherd.py @@ -4,7 +4,6 @@ from django.db import connection class AWXTaskWorker(TaskWorker): - def on_start(self) -> None: """Get worker connected so that first task it gets will be worked quickly""" connection.ensure_connection() diff --git a/awx/main/management/commands/create_host_summary_index.py b/awx/main/management/commands/create_host_summary_index.py index ba39fbdd1b..b477cc7fe3 100644 --- a/awx/main/management/commands/create_host_summary_index.py +++ b/awx/main/management/commands/create_host_summary_index.py @@ -20,7 +20,7 @@ class Command(BaseCommand): """ with connection.cursor() as cursor: cursor.execute( - "SELECT pg_index.indisvalid " "FROM pg_class JOIN pg_index ON pg_class.oid = pg_index.indexrelid " "WHERE pg_class.relname = %s", + "SELECT pg_index.indisvalid FROM pg_class JOIN pg_index ON pg_class.oid = pg_index.indexrelid WHERE pg_class.relname = %s", [self.INDEX_NAME], ) row = cursor.fetchone() @@ -52,7 +52,7 @@ class Command(BaseCommand): # have set ALTER ROLE ... SET statement_timeout which would kill # the index build on large tables. cursor.execute("SET statement_timeout = 0") - cursor.execute(f"CREATE INDEX CONCURRENTLY {self.INDEX_NAME} " f"ON {self.TABLE_NAME} (host_id, id DESC)") + cursor.execute(f"CREATE INDEX CONCURRENTLY {self.INDEX_NAME} ON {self.TABLE_NAME} (host_id, id DESC)") finally: connection.connection.autocommit = old_autocommit diff --git a/awx/main/management/commands/export_custom_scripts.py b/awx/main/management/commands/export_custom_scripts.py index c0cc46c5a7..8b2aa007ed 100644 --- a/awx/main/management/commands/export_custom_scripts.py +++ b/awx/main/management/commands/export_custom_scripts.py @@ -22,8 +22,8 @@ class Command(BaseCommand): with tarfile.open(tar_filename, "w") as tar: for cis in CustomInventoryScript.objects.all(): # naming convention similar to project paths - slug_name = slugify(str(cis.name)).replace(u'-', u'_') - script_filename = u'_%d__%s' % (int(cis.pk), slug_name) + slug_name = slugify(str(cis.name)).replace('-', '_') + script_filename = '_%d__%s' % (int(cis.pk), slug_name) script_path = os.path.join(tmpdirname, script_filename) with open(script_path, 'w') as f: diff --git a/awx/main/management/commands/host_metric.py b/awx/main/management/commands/host_metric.py index c0862ea1a3..bd3cf4d7f6 100644 --- a/awx/main/management/commands/host_metric.py +++ b/awx/main/management/commands/host_metric.py @@ -43,9 +43,7 @@ class Command(BaseCommand): 'hosts_added', 'hosts_deleted', 'indirectly_managed_hosts', - ).order_by( - 'date' - )[offset : offset + limit] + ).order_by('date')[offset : offset + limit] ) return list_of_queryset @@ -90,8 +88,8 @@ class Command(BaseCommand): def csv_for_tar(self, temp_dir, type, filter_kwargs, rows_per_file, always_header=True): for index, list_of_queryset in enumerate(self.paginated_db_retrieval(type, filter_kwargs, rows_per_file)): - csv_file = f'{temp_dir}/{type}{index+1}.csv' - arcname_file = f'{type}{index+1}.csv' + csv_file = f'{temp_dir}/{type}{index + 1}.csv' + arcname_file = f'{type}{index + 1}.csv' first_write = True if index == 0 else False diff --git a/awx/main/management/commands/register_queue.py b/awx/main/management/commands/register_queue.py index e6dfd18a8b..357f0776bb 100644 --- a/awx/main/management/commands/register_queue.py +++ b/awx/main/management/commands/register_queue.py @@ -114,9 +114,15 @@ class Command(BaseCommand): parser.add_argument( '--hostnames', dest='hostnames', type=str, help='Comma-Delimited Hosts to add to the Queue (will not remove already assigned instances)' ) - parser.add_argument( - '--instance_percent', dest='instance_percent', type=int, default=0, help='The percentage of active instances that will be assigned to this group' - ), + ( + parser.add_argument( + '--instance_percent', + dest='instance_percent', + type=int, + default=0, + help='The percentage of active instances that will be assigned to this group', + ), + ) parser.add_argument( '--instance_minimum', dest='instance_minimum', diff --git a/awx/main/migrations/0144_event_partitions.py b/awx/main/migrations/0144_event_partitions.py index 0408384e54..17124a766a 100644 --- a/awx/main/migrations/0144_event_partitions.py +++ b/awx/main/migrations/0144_event_partitions.py @@ -42,9 +42,7 @@ def migrate_event_data(apps, schema_editor): # create parent table cursor.execute( - f'CREATE TABLE {tblname} ' - f'(LIKE tmp_{tblname} INCLUDING ALL, job_created TIMESTAMP WITH TIME ZONE NOT NULL) ' - f'PARTITION BY RANGE(job_created);' + f'CREATE TABLE {tblname} (LIKE tmp_{tblname} INCLUDING ALL, job_created TIMESTAMP WITH TIME ZONE NOT NULL) PARTITION BY RANGE(job_created);' ) cursor.execute(f'DROP TABLE tmp_{tblname}') diff --git a/awx/main/migrations/0196_indirect_managed_node_audit.py b/awx/main/migrations/0196_indirect_managed_node_audit.py index be9c5498a6..0df139a1d0 100644 --- a/awx/main/migrations/0196_indirect_managed_node_audit.py +++ b/awx/main/migrations/0196_indirect_managed_node_audit.py @@ -5,7 +5,6 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ ('main', '0195_EE_permissions'), ] diff --git a/awx/main/migrations/0197_add_opa_query_path.py b/awx/main/migrations/0197_add_opa_query_path.py index fdab27fdc1..d4cd35dab3 100644 --- a/awx/main/migrations/0197_add_opa_query_path.py +++ b/awx/main/migrations/0197_add_opa_query_path.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('main', '0196_indirect_managed_node_audit'), ] diff --git a/awx/main/migrations/0198_alter_inventorysource_source_and_more.py b/awx/main/migrations/0198_alter_inventorysource_source_and_more.py index 2f7f4dbedf..325636cdb4 100644 --- a/awx/main/migrations/0198_alter_inventorysource_source_and_more.py +++ b/awx/main/migrations/0198_alter_inventorysource_source_and_more.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [('main', '0197_add_opa_query_path')] operations = [ diff --git a/awx/main/migrations/0199_inventorygroupvariableswithhistory_and_more.py b/awx/main/migrations/0199_inventorygroupvariableswithhistory_and_more.py index 98e00925b6..1b74fcf7a8 100644 --- a/awx/main/migrations/0199_inventorygroupvariableswithhistory_and_more.py +++ b/awx/main/migrations/0199_inventorygroupvariableswithhistory_and_more.py @@ -5,7 +5,6 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ ('main', '0198_alter_inventorysource_source_and_more'), ] diff --git a/awx/main/migrations/0200_template_name_constraint.py b/awx/main/migrations/0200_template_name_constraint.py index 1b01dc57a7..7e96162ef6 100644 --- a/awx/main/migrations/0200_template_name_constraint.py +++ b/awx/main/migrations/0200_template_name_constraint.py @@ -31,7 +31,6 @@ def rename_wfjt(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ('main', '0199_inventorygroupvariableswithhistory_and_more'), ] diff --git a/awx/main/migrations/0203_remove_team_of_teams.py b/awx/main/migrations/0203_remove_team_of_teams.py index 905f5a40c4..50eff2f3b6 100644 --- a/awx/main/migrations/0203_remove_team_of_teams.py +++ b/awx/main/migrations/0203_remove_team_of_teams.py @@ -8,7 +8,6 @@ logger = logging.getLogger('awx.main.migrations') class Migration(migrations.Migration): - dependencies = [ ('main', '0202_convert_controller_role_definitions'), ] diff --git a/awx/main/migrations/0204_squashed_deletions.py b/awx/main/migrations/0204_squashed_deletions.py index 3e7bb38749..99075b7e1b 100644 --- a/awx/main/migrations/0204_squashed_deletions.py +++ b/awx/main/migrations/0204_squashed_deletions.py @@ -37,7 +37,7 @@ class Migration(migrations.Migration): # delete all sso application content permissions # Added reverse_sql=migrations.RunSQL.noop to make this reversible for tests migrations.RunSQL( - "DELETE FROM auth_permission " "WHERE content_type_id IN (SELECT id FROM django_content_type WHERE app_label = 'sso');", + "DELETE FROM auth_permission WHERE content_type_id IN (SELECT id FROM django_content_type WHERE app_label = 'sso');", reverse_sql=migrations.RunSQL.noop, ), # delete sso application content type diff --git a/awx/main/migrations/0205_add_ordering_to_instancegroup_and_workflow_nodes.py b/awx/main/migrations/0205_add_ordering_to_instancegroup_and_workflow_nodes.py index ea6670a88f..012d70d9ca 100644 --- a/awx/main/migrations/0205_add_ordering_to_instancegroup_and_workflow_nodes.py +++ b/awx/main/migrations/0205_add_ordering_to_instancegroup_and_workflow_nodes.py @@ -4,7 +4,6 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ ('main', '0204_squashed_deletions'), ] diff --git a/awx/main/migrations/0207_alter_skip_tags_to_textfield.py b/awx/main/migrations/0207_alter_skip_tags_to_textfield.py index 9a6457cc07..9624b29d8f 100644 --- a/awx/main/migrations/0207_alter_skip_tags_to_textfield.py +++ b/awx/main/migrations/0207_alter_skip_tags_to_textfield.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('main', '0206_jobhostsummary_host_id_idx'), ] diff --git a/awx/main/models/activity_stream.py b/awx/main/models/activity_stream.py index 62b1970b5a..e4427e4a51 100644 --- a/awx/main/models/activity_stream.py +++ b/awx/main/models/activity_stream.py @@ -93,7 +93,7 @@ class ActivityStream(models.Model): timestamp = self.timestamp else: timestamp = '_delayed_' - return u'%s-%s-pk=%s' % (operation, timestamp, self.pk) + return '%s-%s-pk=%s' % (operation, timestamp, self.pk) def get_absolute_url(self, request=None): return reverse('api:activity_stream_detail', kwargs={'pk': self.pk}, request=request) diff --git a/awx/main/models/ad_hoc_commands.py b/awx/main/models/ad_hoc_commands.py index 4a7ade5fdf..a0d871182b 100644 --- a/awx/main/models/ad_hoc_commands.py +++ b/awx/main/models/ad_hoc_commands.py @@ -221,7 +221,7 @@ class AdHocCommand(UnifiedJob, JobNotificationMixin): self.preferred_instance_groups_cache = self._get_preferred_instance_group_cache() add_to_update_fields("preferred_instance_groups_cache") if not self.name: - self.name = Truncator(u': '.join(filter(None, (self.module_name, self.module_args)))).chars(512) + self.name = Truncator(': '.join(filter(None, (self.module_name, self.module_args)))).chars(512) add_to_update_fields("name") if self.task_impact == 0: self.task_impact = self._get_task_impact() diff --git a/awx/main/models/base.py b/awx/main/models/base.py index d3bbdf4e02..434ef82459 100644 --- a/awx/main/models/base.py +++ b/awx/main/models/base.py @@ -102,9 +102,9 @@ class BaseModel(models.Model): def __str__(self): if 'name' in self.__dict__: - return u'%s-%s' % (self.name, self.pk) + return '%s-%s' % (self.name, self.pk) else: - return u'%s-%s' % (self._meta.verbose_name, self.pk) + return '%s-%s' % (self._meta.verbose_name, self.pk) def clean_fields(self, exclude=None): """ diff --git a/awx/main/models/events.py b/awx/main/models/events.py index 15f4bc7c46..17436f5ec2 100644 --- a/awx/main/models/events.py +++ b/awx/main/models/events.py @@ -525,7 +525,7 @@ class JobEvent(BasePlaybookEvent): return reverse('api:job_event_detail', kwargs={'pk': self.pk}, request=request) def __str__(self): - return u'%s @ %s' % (self.get_event_display2(), self.created.isoformat()) + return '%s @ %s' % (self.get_event_display2(), self.created.isoformat()) def _hostnames(self): hostnames = set() @@ -717,7 +717,7 @@ class BaseCommandEvent(CreatedModifiedModel): ) def __str__(self): - return u'%s @ %s' % (self.get_event_display(), self.created.isoformat()) + return '%s @ %s' % (self.get_event_display(), self.created.isoformat()) @classmethod def create_from_data(cls, **kwargs): diff --git a/awx/main/models/mixins.py b/awx/main/models/mixins.py index 184b4c7899..69a0fbba5d 100644 --- a/awx/main/models/mixins.py +++ b/awx/main/models/mixins.py @@ -701,7 +701,7 @@ class WebhookMixin(models.Model): if response.status_code < 400: logger.debug("Webhook status update sent.") else: - logger.error("Posting webhook status failed, code: {}\n" "{}\nPayload sent: {}".format(response.status_code, response.text, json.dumps(data))) + logger.error("Posting webhook status failed, code: {}\n{}\nPayload sent: {}".format(response.status_code, response.text, json.dumps(data))) class OpaQueryPathMixin(models.Model): diff --git a/awx/main/models/projects.py b/awx/main/models/projects.py index 86f00f842a..83d024045d 100644 --- a/awx/main/models/projects.py +++ b/awx/main/models/projects.py @@ -371,8 +371,8 @@ class Project(UnifiedJobTemplate, ProjectOptions, ResourceMixin, CustomVirtualEn self._skip_update = bool(kwargs.pop('skip_update', False)) # Create auto-generated local path if project uses SCM. if self.pk and self.scm_type and not self.local_path.startswith('_'): - slug_name = slugify(str(self.name)).replace(u'-', u'_') - self.local_path = u'_%d__%s' % (int(self.pk), slug_name) + slug_name = slugify(str(self.name)).replace('-', '_') + self.local_path = '_%d__%s' % (int(self.pk), slug_name) if 'local_path' not in update_fields: update_fields.append('local_path') # Do the actual save. diff --git a/awx/main/models/rbac.py b/awx/main/models/rbac.py index 8d7a51cb2d..3b88c7794f 100644 --- a/awx/main/models/rbac.py +++ b/awx/main/models/rbac.py @@ -180,9 +180,9 @@ class Role(models.Model): def __str__(self): if 'role_field' in self.__dict__: - return u'%s-%s' % (self.name, self.pk) + return '%s-%s' % (self.name, self.pk) else: - return u'%s-%s' % (self._meta.verbose_name, self.pk) + return '%s-%s' % (self._meta.verbose_name, self.pk) def save(self, *args, **kwargs): super(Role, self).save(*args, **kwargs) @@ -365,7 +365,8 @@ class Role(models.Model): if len(removals) > 0: for ids in split_ids_for_sqlite(removals): sql_params['ids'] = ','.join(str(x) for x in ids) - cursor.execute(''' + cursor.execute( + ''' DELETE FROM %(ancestors_table)s WHERE descendent_id IN (%(ids)s) AND descendent_id != ancestor_id @@ -377,7 +378,9 @@ class Role(models.Model): WHERE parents.from_role_id = %(ancestors_table)s.descendent_id AND %(ancestors_table)s.ancestor_id = inner_ancestors.ancestor_id ) - ''' % sql_params) + ''' + % sql_params + ) delete_ct += cursor.rowcount @@ -385,7 +388,8 @@ class Role(models.Model): if len(additions) > 0: for ids in split_ids_for_sqlite(additions): sql_params['ids'] = ','.join(str(x) for x in ids) - cursor.execute(''' + cursor.execute( + ''' INSERT INTO %(ancestors_table)s (descendent_id, ancestor_id, role_field, content_type_id, object_id) SELECT from_id, to_id, new_ancestry_list.role_field, new_ancestry_list.content_type_id, new_ancestry_list.object_id FROM ( SELECT roles.id from_id, @@ -415,7 +419,9 @@ class Role(models.Model): AND %(ancestors_table)s.ancestor_id = new_ancestry_list.to_id ) - ''' % sql_params) + ''' + % sql_params + ) insert_ct += cursor.rowcount if insert_ct == 0 and delete_ct == 0: diff --git a/awx/main/models/schedules.py b/awx/main/models/schedules.py index 5ab57e1746..ee6332a077 100644 --- a/awx/main/models/schedules.py +++ b/awx/main/models/schedules.py @@ -276,7 +276,7 @@ class Schedule(PrimordialModel, LaunchTimeConfig): return rruleset def __str__(self): - return u'%s_t%s_%s_%s' % (self.name, self.unified_job_template.id, self.id, self.next_run) + return '%s_t%s_%s_%s' % (self.name, self.unified_job_template.id, self.id, self.next_run) def get_absolute_url(self, request=None): return reverse('api:schedule_detail', kwargs={'pk': self.pk}, request=request) diff --git a/awx/main/models/unified_jobs.py b/awx/main/models/unified_jobs.py index 7b5b74d632..1a8abd47f1 100644 --- a/awx/main/models/unified_jobs.py +++ b/awx/main/models/unified_jobs.py @@ -836,7 +836,7 @@ class UnifiedJob( return True def __str__(self): - return u'%s-%s-%s' % (self.created, self.id, self.status) + return '%s-%s-%s' % (self.created, self.id, self.status) @property def log_format(self): @@ -1416,14 +1416,14 @@ class UnifiedJob( if not all(opts.values()): missing_fields = ', '.join([k for k, v in opts.items() if not v]) - self.job_explanation = u'Missing needed fields: %s.' % missing_fields + self.job_explanation = 'Missing needed fields: %s.' % missing_fields self.save(update_fields=['job_explanation']) return opts def pre_start(self): if not self.can_start: - self.job_explanation = u'%s is not in a startable state: %s, expecting one of %s' % (self._meta.verbose_name, self.status, str(('new', 'waiting'))) + self.job_explanation = '%s is not in a startable state: %s, expecting one of %s' % (self._meta.verbose_name, self.status, str(('new', 'waiting'))) self.save(update_fields=['job_explanation']) return (False, None) diff --git a/awx/main/notifications/webhook_backend.py b/awx/main/notifications/webhook_backend.py index 17fae5fe31..dc4adbcb81 100644 --- a/awx/main/notifications/webhook_backend.py +++ b/awx/main/notifications/webhook_backend.py @@ -93,7 +93,7 @@ class WebhookBackend(AWXBaseEmailBackend, CustomNotificationBase): url_next_log_safe = base64.b64encode(url_next.encode('UTF-8')) if url_next else b'None' # we've hit a redirect. extract the redirect URL out of the first response header and try again - logger.warning(f"Received a {resp.status_code} from {url_log_safe}, trying to reach redirect url {url_next_log_safe}; attempt #{retries+1}") + logger.warning(f"Received a {resp.status_code} from {url_log_safe}, trying to reach redirect url {url_next_log_safe}; attempt #{retries + 1}") # take the first redirect URL in the response header and try that url = url_next diff --git a/awx/main/scheduler/task_manager.py b/awx/main/scheduler/task_manager.py index c93b5c69a1..ad9d69c795 100644 --- a/awx/main/scheduler/task_manager.py +++ b/awx/main/scheduler/task_manager.py @@ -256,8 +256,7 @@ class WorkflowManager(TaskBase): ) display_list = [spawn_node.unified_job_template] + workflow_ancestors job.job_explanation = gettext_noop( - "Workflow Job spawned from workflow could not start because it " - "would result in recursion (spawn order, most recent first: {})" + "Workflow Job spawned from workflow could not start because it would result in recursion (spawn order, most recent first: {})" ).format(', '.join('<{}>'.format(tmp) for tmp in display_list)) else: logger.debug( @@ -344,7 +343,7 @@ class DependencyManager(TaskBase): if update.status in ['waiting', 'pending', 'running']: return False - return bool(((update.finished + timedelta(seconds=cache_timeout))) < tz_now()) + return bool((update.finished + timedelta(seconds=cache_timeout)) < tz_now()) def get_or_create_project_update(self, project_id): project = self.all_projects.get(project_id, None) diff --git a/awx/main/tasks/jobs.py b/awx/main/tasks/jobs.py index 5fb06bf87a..3a6b5a3064 100644 --- a/awx/main/tasks/jobs.py +++ b/awx/main/tasks/jobs.py @@ -563,7 +563,7 @@ class BaseTask(object): project.save() lock_path = project.get_lock_file() if lock_path is None: - raise RuntimeError(u'Invalid lock file path') + raise RuntimeError('Invalid lock file path') try: self.lock_fd = os.open(lock_path, os.O_RDWR | os.O_CREAT) diff --git a/awx/main/tasks/receptor.py b/awx/main/tasks/receptor.py index e1ccf4d7c4..dae7e49bc7 100644 --- a/awx/main/tasks/receptor.py +++ b/awx/main/tasks/receptor.py @@ -180,7 +180,7 @@ def find_node_in_mesh(node_name, receptor_ctl): if node.get('NodeID') == node_name: return node else: - logger.warning(f"Instance {node_name} is not in the receptor mesh. {attempts-attempt} attempts left.") + logger.warning(f"Instance {node_name} is not in the receptor mesh. {attempts - attempt} attempts left.") time.sleep(backoff) backoff += 1 else: @@ -848,7 +848,7 @@ def reload_receptor(): receptor_ctl.simple_command("reload") break except ValueError: - logger.warning(f"Unable to reload Receptor configuration. {attempts-backoff} attempts left.") + logger.warning(f"Unable to reload Receptor configuration. {attempts - backoff} attempts left.") time.sleep(backoff) else: raise RuntimeError("Receptor reload failed") diff --git a/awx/main/tasks/system.py b/awx/main/tasks/system.py index 3d669c9699..be418daa0e 100644 --- a/awx/main/tasks/system.py +++ b/awx/main/tasks/system.py @@ -79,7 +79,7 @@ from awx.main.utils.reload import stop_local_services logger = logging.getLogger('awx.main.tasks.system') -OPENSSH_KEY_ERROR = u'''\ +OPENSSH_KEY_ERROR = '''\ It looks like you're trying to use a private key in OpenSSH format, which \ isn't supported by the installed version of OpenSSH on this instance. \ Try upgrading OpenSSH or providing your private key in an different format. \ @@ -690,7 +690,6 @@ def _get_active_task_ids_from_dispatcherd(binder): """ active_task_ids = [] try: - logger.debug("Querying dispatcherd API for running tasks") data = binder.control('running') @@ -934,8 +933,10 @@ def awx_periodic_scheduler(): continue if not can_start: new_unified_job.status = 'failed' - new_unified_job.job_explanation = gettext_noop("Scheduled job could not start because it \ - was not in the right state or required manual credentials") + new_unified_job.job_explanation = gettext_noop( + "Scheduled job could not start because it \ + was not in the right state or required manual credentials" + ) new_unified_job.save(update_fields=['status', 'job_explanation']) new_unified_job.websocket_emit_status("failed") emit_channel_notification('schedules-changed', dict(id=schedule.id, group_name="schedules")) diff --git a/awx/main/templatetags/swagger.py b/awx/main/templatetags/swagger.py index d9f9ceb4dc..f80f04bd11 100644 --- a/awx/main/templatetags/swagger.py +++ b/awx/main/templatetags/swagger.py @@ -4,9 +4,7 @@ from django import template register = template.Library() CONSONANT_SOUND = re.compile(r'''one(![ir])''', re.IGNORECASE | re.VERBOSE) # noqa -VOWEL_SOUND = re.compile( - r'''[aeio]|u([aeiou]|[^n][^aeiou]|ni[^dmnl]|nil[^l])|h(ier|onest|onou?r|ors\b|our(!i))|[fhlmnrsx]\b''', re.IGNORECASE | re.VERBOSE -) # noqa +VOWEL_SOUND = re.compile(r'''[aeio]|u([aeiou]|[^n][^aeiou]|ni[^dmnl]|nil[^l])|h(ier|onest|onou?r|ors\b|our(!i))|[fhlmnrsx]\b''', re.IGNORECASE | re.VERBOSE) # noqa @register.filter diff --git a/awx/main/tests/functional/analytics/test_collectors.py b/awx/main/tests/functional/analytics/test_collectors.py index 4dcb9cd3c3..c7e5858cfe 100644 --- a/awx/main/tests/functional/analytics/test_collectors.py +++ b/awx/main/tests/functional/analytics/test_collectors.py @@ -166,6 +166,6 @@ def test_copy_tables_workflow_job_node_query(sqlite_copy, workflow_job): for index, relationship in zip([7, 8, 9], ["success_nodes", "failure_nodes", "always_nodes"]): for i, l in enumerate(lines): related_nodes = [int(e) for e in l[index].split(",")] if l[index] else [] - assert related_nodes == list( - getattr(workflow_job.workflow_nodes.all()[i], relationship).all().values_list("id", flat=True) - ), f"(right side) workflow_nodes.all()[{i}].{relationship}.all()" + assert related_nodes == list(getattr(workflow_job.workflow_nodes.all()[i], relationship).all().values_list("id", flat=True)), ( + f"(right side) workflow_nodes.all()[{i}].{relationship}.all()" + ) diff --git a/awx/main/tests/functional/api/test_analytics.py b/awx/main/tests/functional/api/test_analytics.py index 52fdba74e3..08b9842904 100644 --- a/awx/main/tests/functional/api/test_analytics.py +++ b/awx/main/tests/functional/api/test_analytics.py @@ -233,9 +233,10 @@ class TestAnalyticsGenericView: request = RequestFactory().post('/some/path') view = AnalyticsGenericView() - with mock.patch('awx.api.views.analytics.OIDCClient') as mock_oidc_client, mock.patch( - 'awx.api.views.analytics.AnalyticsGenericView._base_auth_request' - ) as mock_base_auth_request: + with ( + mock.patch('awx.api.views.analytics.OIDCClient') as mock_oidc_client, + mock.patch('awx.api.views.analytics.AnalyticsGenericView._base_auth_request') as mock_base_auth_request, + ): # Configure the mock OIDCClient instance and its make_request method mock_client_instance = mock.Mock() mock_oidc_client.return_value = mock_client_instance diff --git a/awx/main/tests/functional/api/test_credential.py b/awx/main/tests/functional/api/test_credential.py index 8d2f6dc0bb..f948e7fac3 100644 --- a/awx/main/tests/functional/api/test_credential.py +++ b/awx/main/tests/functional/api/test_credential.py @@ -930,7 +930,7 @@ def test_field_removal(put, organization, admin, credentialtype_ssh): }, } cred = Credential( - credential_type=credentialtype_ssh, name='Best credential ever', organization=organization, inputs={'username': u'jim', 'password': u'secret'} + credential_type=credentialtype_ssh, name='Best credential ever', organization=organization, inputs={'username': 'jim', 'password': 'secret'} ) cred.save() @@ -957,7 +957,7 @@ def test_field_removal(put, organization, admin, credentialtype_ssh): ) def test_credential_type_mutability(patch, organization, admin, credentialtype_ssh, credentialtype_aws, relation, related_obj): cred = Credential( - credential_type=credentialtype_ssh, name='Best credential ever', organization=organization, inputs={'username': u'jim', 'password': u'pass'} + credential_type=credentialtype_ssh, name='Best credential ever', organization=organization, inputs={'username': 'jim', 'password': 'pass'} ) cred.save() @@ -967,7 +967,7 @@ def test_credential_type_mutability(patch, organization, admin, credentialtype_s def _change_credential_type(): return patch( reverse('api:credential_detail', kwargs={'pk': cred.pk}), - {'credential_type': credentialtype_aws.pk, 'inputs': {'username': u'jim', 'password': u'pass'}}, + {'credential_type': credentialtype_aws.pk, 'inputs': {'username': 'jim', 'password': 'pass'}}, admin, ) @@ -992,7 +992,7 @@ def test_vault_credential_type_mutability(patch, organization, admin, credential name='Best credential ever', organization=organization, inputs={ - 'vault_password': u'some-vault', + 'vault_password': 'some-vault', }, ) cred.save() @@ -1004,7 +1004,7 @@ def test_vault_credential_type_mutability(patch, organization, admin, credential def _change_credential_type(): return patch( reverse('api:credential_detail', kwargs={'pk': cred.pk}), - {'credential_type': credentialtype_ssh.pk, 'inputs': {'username': u'jim', 'password': u'pass'}}, + {'credential_type': credentialtype_ssh.pk, 'inputs': {'username': 'jim', 'password': 'pass'}}, admin, ) @@ -1025,7 +1025,7 @@ def test_vault_credential_type_mutability(patch, organization, admin, credential @pytest.mark.django_db def test_cloud_credential_type_mutability(patch, organization, admin, credentialtype_ssh, credentialtype_aws): cred = Credential( - credential_type=credentialtype_aws, name='Best credential ever', organization=organization, inputs={'username': u'jim', 'password': u'pass'} + credential_type=credentialtype_aws, name='Best credential ever', organization=organization, inputs={'username': 'jim', 'password': 'pass'} ) cred.save() @@ -1036,7 +1036,7 @@ def test_cloud_credential_type_mutability(patch, organization, admin, credential def _change_credential_type(): return patch( reverse('api:credential_detail', kwargs={'pk': cred.pk}), - {'credential_type': credentialtype_ssh.pk, 'inputs': {'username': u'jim', 'password': u'pass'}}, + {'credential_type': credentialtype_ssh.pk, 'inputs': {'username': 'jim', 'password': 'pass'}}, admin, ) @@ -1084,7 +1084,7 @@ def test_ssh_unlock_needed(put, organization, admin, credentialtype_ssh): credential_type=credentialtype_ssh, name='Best credential ever', organization=organization, - inputs={'username': u'joe', 'ssh_key_data': EXAMPLE_ENCRYPTED_PRIVATE_KEY, 'ssh_key_unlock': 'unlock'}, + inputs={'username': 'joe', 'ssh_key_data': EXAMPLE_ENCRYPTED_PRIVATE_KEY, 'ssh_key_unlock': 'unlock'}, ) cred.save() @@ -1110,7 +1110,7 @@ def test_ssh_unlock_not_needed(put, organization, admin, credentialtype_ssh): name='Best credential ever', organization=organization, inputs={ - 'username': u'joe', + 'username': 'joe', 'ssh_key_data': EXAMPLE_PRIVATE_KEY, }, ) @@ -1137,7 +1137,7 @@ def test_ssh_unlock_with_prior_value(put, organization, admin, credentialtype_ss credential_type=credentialtype_ssh, name='Best credential ever', organization=organization, - inputs={'username': u'joe', 'ssh_key_data': EXAMPLE_ENCRYPTED_PRIVATE_KEY, 'ssh_key_unlock': 'old-unlock'}, + inputs={'username': 'joe', 'ssh_key_data': EXAMPLE_ENCRYPTED_PRIVATE_KEY, 'ssh_key_unlock': 'old-unlock'}, ) cred.save() @@ -1165,7 +1165,7 @@ def test_ssh_bad_key_unlock_not_checked(put, organization, admin, credentialtype name='Best credential ever', organization=organization, inputs={ - 'username': u'oscar', + 'username': 'oscar', 'ssh_key_data': 'invalid-key', 'ssh_key_unlock': 'unchecked-unlock', }, @@ -1251,7 +1251,7 @@ def test_secret_encryption_previous_value(patch, organization, admin, credential } } cred = Credential( - credential_type=credentialtype_ssh, name='Best credential ever', organization=organization, inputs={'username': u'jim', 'password': u'secret'} + credential_type=credentialtype_ssh, name='Best credential ever', organization=organization, inputs={'username': 'jim', 'password': 'secret'} ) cred.save() diff --git a/awx/main/tests/functional/api/test_instance_group.py b/awx/main/tests/functional/api/test_instance_group.py index 5bc56940c9..298437f631 100644 --- a/awx/main/tests/functional/api/test_instance_group.py +++ b/awx/main/tests/functional/api/test_instance_group.py @@ -102,7 +102,7 @@ def test_delete_instance_group_jobs_running(delete, instance_group_jobs_running, response_sorted = sorted(response.data['active_jobs'], key=sort_keys) expect_sorted = sorted(expect_transformed, key=sort_keys) - assert response.data['error'] == u"Resource is being used by running jobs." + assert response.data['error'] == "Resource is being used by running jobs." assert response_sorted == expect_sorted diff --git a/awx/main/tests/functional/api/test_inventory.py b/awx/main/tests/functional/api/test_inventory.py index e257b3e983..6d6481db29 100644 --- a/awx/main/tests/functional/api/test_inventory.py +++ b/awx/main/tests/functional/api/test_inventory.py @@ -285,12 +285,12 @@ def test_urlencode_host_filter(post, admin_user, organization): def test_host_filter_unicode(post, admin_user, organization): post( reverse('api:inventory_list'), - data={'name': 'smart inventory', 'kind': 'smart', 'organization': organization.pk, 'host_filter': u'ansible_facts__ansible_distribution=レッドハット'}, + data={'name': 'smart inventory', 'kind': 'smart', 'organization': organization.pk, 'host_filter': 'ansible_facts__ansible_distribution=レッドハット'}, user=admin_user, expect=201, ) si = Inventory.objects.get(name='smart inventory') - assert si.host_filter == u'ansible_facts__ansible_distribution=レッドハット' + assert si.host_filter == 'ansible_facts__ansible_distribution=レッドハット' @pytest.mark.django_db @@ -302,7 +302,7 @@ def test_host_filter_invalid_ansible_facts_lookup(post, admin_user, organization 'name': 'smart inventory', 'kind': 'smart', 'organization': organization.pk, - 'host_filter': u'ansible_facts__ansible_distribution__{}=cent'.format(lookup), + 'host_filter': 'ansible_facts__ansible_distribution__{}=cent'.format(lookup), }, user=admin_user, expect=400, @@ -417,7 +417,7 @@ def test_inventory_source_vars_prohibition(post, inventory, admin_user): mock_settings.INV_ENV_VARIABLE_BLOCKED = ('FOOBAR',) r = post( reverse('api:inventory_source_list'), - {'name': 'new inv src', 'source_vars': '{\"FOOBAR\": \"val\"}', 'inventory': inventory.pk}, + {'name': 'new inv src', 'source_vars': '{"FOOBAR": "val"}', 'inventory': inventory.pk}, admin_user, expect=400, ) @@ -729,7 +729,6 @@ class TestConstructedInventory: @pytest.mark.django_db class TestInventoryAllVariables: - @staticmethod def simulate_update_from_source(inv_src, variables_dict, overwrite_vars=True): """ diff --git a/awx/main/tests/functional/api/test_job_runtime_params.py b/awx/main/tests/functional/api/test_job_runtime_params.py index 1220a0c8db..707a0fb187 100644 --- a/awx/main/tests/functional/api/test_job_runtime_params.py +++ b/awx/main/tests/functional/api/test_job_runtime_params.py @@ -278,9 +278,9 @@ def test_job_reject_invalid_prompted_vars(runtime_data, job_template_prompts, po expect=400, ) - assert response.data['job_type'] == [u'"foobicate" is not a valid choice.'] - assert response.data['inventory'] == [u'Invalid pk "87865" - object does not exist.'] - assert response.data['credentials'] == [u'Invalid pk "48474" - object does not exist.'] + assert response.data['job_type'] == ['"foobicate" is not a valid choice.'] + assert response.data['inventory'] == ['Invalid pk "87865" - object does not exist.'] + assert response.data['credentials'] == ['Invalid pk "48474" - object does not exist.'] @pytest.mark.django_db @@ -314,7 +314,7 @@ def test_job_launch_fails_without_inventory_access(job_template_prompts, runtime # Assure that giving an inventory without access to the inventory blocks the launch response = post(reverse('api:job_template_launch', kwargs={'pk': job_template.pk}), dict(inventory=runtime_data['inventory']), rando, expect=403) - assert response.data['detail'] == u'You do not have permission to perform this action.' + assert response.data['detail'] == 'You do not have permission to perform this action.' @pytest.mark.django_db @@ -540,15 +540,15 @@ def test_job_launch_fails_with_missing_multivault_password(machine_credential, v assert { 'credential_type': vault_cred_first.credential_type_id, 'passwords_needed': ['vault_password.abc'], - 'vault_id': u'abc', - 'name': u'Vault #1', + 'vault_id': 'abc', + 'name': 'Vault #1', 'id': vault_cred_first.id, } in resp.data['defaults']['credentials'] assert { 'credential_type': vault_cred_second.credential_type_id, 'passwords_needed': ['vault_password.xyz'], - 'vault_id': u'xyz', - 'name': u'Vault #2', + 'vault_id': 'xyz', + 'name': 'Vault #2', 'id': vault_cred_second.id, } in resp.data['defaults']['credentials'] diff --git a/awx/main/tests/functional/api/test_license_cache_clearing.py b/awx/main/tests/functional/api/test_license_cache_clearing.py index 08b8e35138..d8893e4d36 100644 --- a/awx/main/tests/functional/api/test_license_cache_clearing.py +++ b/awx/main/tests/functional/api/test_license_cache_clearing.py @@ -13,10 +13,12 @@ class TestLicenseCacheClearing: """Test that posting a manifest to /api/v2/config/ clears the LICENSE cache""" # Mock the licenser and clear_setting_cache - with patch('awx.api.views.root.get_licenser') as mock_get_licenser, patch('awx.api.views.root.validate_entitlement_manifest') as mock_validate, patch( - 'awx.api.views.root.clear_setting_cache' - ) as mock_clear_cache, patch('django.db.connection.on_commit') as mock_on_commit: - + with ( + patch('awx.api.views.root.get_licenser') as mock_get_licenser, + patch('awx.api.views.root.validate_entitlement_manifest') as mock_validate, + patch('awx.api.views.root.clear_setting_cache') as mock_clear_cache, + patch('django.db.connection.on_commit') as mock_on_commit, + ): # Set up mock license data mock_license_data = {'valid_key': True, 'license_type': 'enterprise', 'instance_count': 100, 'subscription_name': 'Test Enterprise License'} @@ -54,7 +56,6 @@ class TestLicenseCacheClearing: """Test that DELETE /api/v2/config/ clears the LICENSE cache""" with patch('awx.api.views.root.clear_setting_cache') as mock_clear_cache, patch('django.db.connection.on_commit') as mock_on_commit: - # Make the DELETE request url = reverse('api:api_v2_config_view') delete(url, admin_user, expect=204) @@ -72,10 +73,12 @@ class TestLicenseCacheClearing: def test_attach_view_clears_cache(self, admin_user, post): """Test that posting to /api/v2/config/attach/ clears the LICENSE cache""" - with patch('awx.api.views.root.get_licenser') as mock_get_licenser, patch('awx.api.views.root.clear_setting_cache') as mock_clear_cache, patch( - 'django.db.connection.on_commit' - ) as mock_on_commit, patch('awx.api.views.root.settings') as mock_settings: - + with ( + patch('awx.api.views.root.get_licenser') as mock_get_licenser, + patch('awx.api.views.root.clear_setting_cache') as mock_clear_cache, + patch('django.db.connection.on_commit') as mock_on_commit, + patch('awx.api.views.root.settings') as mock_settings, + ): # Set up subscription credentials in settings mock_settings.SUBSCRIPTIONS_CLIENT_ID = 'test-client-id' mock_settings.SUBSCRIPTIONS_CLIENT_SECRET = 'test-client-secret' @@ -113,10 +116,11 @@ class TestLicenseCacheClearing: def test_attach_view_subscription_not_found_no_cache_clear(self, admin_user, post): """Test that attach view doesn't clear cache when subscription is not found""" - with patch('awx.api.views.root.get_licenser') as mock_get_licenser, patch('awx.api.views.root.clear_setting_cache') as mock_clear_cache, patch( - 'django.db.connection.on_commit' - ) as mock_on_commit: - + with ( + patch('awx.api.views.root.get_licenser') as mock_get_licenser, + patch('awx.api.views.root.clear_setting_cache') as mock_clear_cache, + patch('django.db.connection.on_commit') as mock_on_commit, + ): # Set up mock licenser with different subscription mock_licenser = MagicMock() subscription_data = {'subscription_id': 'different-subscription-456', 'valid_key': False, 'license_type': 'enterprise'} # Different ID @@ -142,10 +146,11 @@ class TestLicenseCacheClearing: def test_manifest_validation_error_no_cache_clear(self, admin_user, post): """Test that config view doesn't clear cache when manifest validation fails""" - with patch('awx.api.views.root.validate_entitlement_manifest') as mock_validate, patch( - 'awx.api.views.root.clear_setting_cache' - ) as mock_clear_cache, patch('django.db.connection.on_commit') as mock_on_commit: - + with ( + patch('awx.api.views.root.validate_entitlement_manifest') as mock_validate, + patch('awx.api.views.root.clear_setting_cache') as mock_clear_cache, + patch('django.db.connection.on_commit') as mock_on_commit, + ): # Mock validation to raise ValueError mock_validate.side_effect = ValueError("Invalid manifest") @@ -166,10 +171,12 @@ class TestLicenseCacheClearing: def test_license_processing_error_no_cache_clear(self, admin_user, post): """Test that config view doesn't clear cache when license processing fails""" - with patch('awx.api.views.root.get_licenser') as mock_get_licenser, patch('awx.api.views.root.validate_entitlement_manifest') as mock_validate, patch( - 'awx.api.views.root.clear_setting_cache' - ) as mock_clear_cache, patch('django.db.connection.on_commit') as mock_on_commit: - + with ( + patch('awx.api.views.root.get_licenser') as mock_get_licenser, + patch('awx.api.views.root.validate_entitlement_manifest') as mock_validate, + patch('awx.api.views.root.clear_setting_cache') as mock_clear_cache, + patch('django.db.connection.on_commit') as mock_on_commit, + ): # Mock validation to succeed but license processing to fail mock_validate.return_value = [{'some': 'manifest_data'}] mock_licenser = MagicMock() diff --git a/awx/main/tests/functional/api/test_oidc_credential_test.py b/awx/main/tests/functional/api/test_oidc_credential_test.py index 29ed9aa094..af2f13bbfa 100644 --- a/awx/main/tests/functional/api/test_oidc_credential_test.py +++ b/awx/main/tests/functional/api/test_oidc_credential_test.py @@ -62,10 +62,11 @@ def oidc_credential(oidc_credentialtype): @pytest.fixture def mock_oidc_backend(): """Fixture that mocks OIDC JWT generation and credential backend.""" - with mock.patch('awx.api.views.retrieve_workload_identity_jwt_with_claims') as mock_jwt, mock.patch('awx.api.views._jwt_decode') as mock_decode, mock.patch( - 'awx.main.models.credential.CredentialType.plugin', new_callable=mock.PropertyMock - ) as mock_plugin: - + with ( + mock.patch('awx.api.views.retrieve_workload_identity_jwt_with_claims') as mock_jwt, + mock.patch('awx.api.views._jwt_decode') as mock_decode, + mock.patch('awx.main.models.credential.CredentialType.plugin', new_callable=mock.PropertyMock) as mock_plugin, + ): # Set default return values mock_jwt.return_value = 'fake.jwt.token' mock_decode.return_value = {'iss': 'http://gateway/o', 'aud': 'vault'} diff --git a/awx/main/tests/functional/api/test_organizations.py b/awx/main/tests/functional/api/test_organizations.py index 6a234c09f5..2f39d81d3a 100644 --- a/awx/main/tests/functional/api/test_organizations.py +++ b/awx/main/tests/functional/api/test_organizations.py @@ -272,7 +272,7 @@ def test_organization_delete_with_active_jobs(delete, admin, organization, organ resp_sorted = sorted(resp.data['active_jobs'], key=sort_keys) expect_sorted = sorted(expect_transformed, key=sort_keys) - assert resp.data['error'] == u"Resource is being used by running jobs." + assert resp.data['error'] == "Resource is being used by running jobs." assert resp_sorted == expect_sorted diff --git a/awx/main/tests/functional/api/test_smart_inventory.py b/awx/main/tests/functional/api/test_smart_inventory.py index b60b73064f..b541d84d97 100644 --- a/awx/main/tests/functional/api/test_smart_inventory.py +++ b/awx/main/tests/functional/api/test_smart_inventory.py @@ -150,13 +150,13 @@ def test_host_filter_unicode(post, admin_user, smart_inv_org): 'name': 'unicode-smart', 'kind': 'smart', 'organization': smart_inv_org.pk, - 'host_filter': u'ansible_facts__ansible_distribution=レッドハット', + 'host_filter': 'ansible_facts__ansible_distribution=レッドハット', }, user=admin_user, expect=201, ) si = Inventory.objects.get(name='unicode-smart') - assert si.host_filter == u'ansible_facts__ansible_distribution=レッドハット' + assert si.host_filter == 'ansible_facts__ansible_distribution=レッドハット' @pytest.mark.django_db @@ -168,7 +168,7 @@ def test_host_filter_invalid_ansible_facts_lookup(post, admin_user, smart_inv_or 'name': 'invalid-lookup-smart', 'kind': 'smart', 'organization': smart_inv_org.pk, - 'host_filter': u'ansible_facts__ansible_distribution__{}=cent'.format(lookup), + 'host_filter': 'ansible_facts__ansible_distribution__{}=cent'.format(lookup), }, user=admin_user, expect=400, 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 3565a73d77..cfe4a1acf3 100644 --- a/awx/main/tests/functional/api/test_unified_jobs_stdout.py +++ b/awx/main/tests/functional/api/test_unified_jobs_stdout.py @@ -168,8 +168,9 @@ def test_text_stdout_with_max_stdout(sqlite_copy, get, admin): url = reverse('api:system_job_detail', kwargs={'pk': job.pk}) response = get(url, user=admin, expect=200) assert response.data['result_stdout'] == ( - 'Standard Output too large to display ({actual} bytes), only download ' - 'supported for sizes over {max} bytes.'.format(actual=total_bytes, max=settings.STDOUT_MAX_BYTES_DISPLAY) + 'Standard Output too large to display ({actual} bytes), only download supported for sizes over {max} bytes.'.format( + actual=total_bytes, max=settings.STDOUT_MAX_BYTES_DISPLAY + ) ) @@ -196,8 +197,9 @@ def test_max_bytes_display(sqlite_copy, Parent, Child, relation, view, fmt, get, response = get(url + '?format={}'.format(fmt), user=admin, expect=200) assert smart_str(response.content) == ( - 'Standard Output too large to display ({actual} bytes), only download ' - 'supported for sizes over {max} bytes.'.format(actual=total_bytes, max=settings.STDOUT_MAX_BYTES_DISPLAY) + 'Standard Output too large to display ({actual} bytes), only download supported for sizes over {max} bytes.'.format( + actual=total_bytes, max=settings.STDOUT_MAX_BYTES_DISPLAY + ) ) response = get(url + '?format={}_download'.format(fmt), user=admin, expect=200) @@ -236,8 +238,9 @@ def test_legacy_result_stdout_with_max_bytes(Cls, view, fmt, get, admin): response = get(url + '?format={}'.format(fmt), user=admin, expect=200) assert smart_str(response.content) == ( - 'Standard Output too large to display ({actual} bytes), only download ' - 'supported for sizes over {max} bytes.'.format(actual=total_bytes, max=settings.STDOUT_MAX_BYTES_DISPLAY) + 'Standard Output too large to display ({actual} bytes), only download supported for sizes over {max} bytes.'.format( + actual=total_bytes, max=settings.STDOUT_MAX_BYTES_DISPLAY + ) ) response = get(url + '?format={}'.format(fmt + '_download'), user=admin, expect=200) @@ -259,7 +262,7 @@ def test_text_with_unicode_stdout(sqlite_copy, Parent, Child, relation, view, ge job = Parent() job.save() for i in range(3): - Child(**{relation: job, 'stdout': u'オ{}\n'.format(i), 'start_line': i}).save() + Child(**{relation: job, 'stdout': 'オ{}\n'.format(i), 'start_line': i}).save() url = reverse(view, kwargs={'pk': job.pk}) + '?format=' + fmt response = get(url, user=admin, expect=200) diff --git a/awx/main/tests/functional/commands/test_secret_key_regeneration.py b/awx/main/tests/functional/commands/test_secret_key_regeneration.py index 05584e5101..303a72d9bf 100644 --- a/awx/main/tests/functional/commands/test_secret_key_regeneration.py +++ b/awx/main/tests/functional/commands/test_secret_key_regeneration.py @@ -126,7 +126,7 @@ class TestKeyRegeneration: name='Example Template', survey_spec=survey_spec_factory([{'variable': 'secret_key', 'default': encrypt_value('donttell', pk=None), 'type': 'password'}]), survey_enabled=True, - **params + **params, ) job = jt.create_unified_job() assert jt.survey_spec['spec'][0]['default'].startswith(PREFIX) diff --git a/awx/main/tests/functional/dab_rbac/test_claims_old_rbac_sync.py b/awx/main/tests/functional/dab_rbac/test_claims_old_rbac_sync.py index 965f8f8aae..28c04b6a49 100644 --- a/awx/main/tests/functional/dab_rbac/test_claims_old_rbac_sync.py +++ b/awx/main/tests/functional/dab_rbac/test_claims_old_rbac_sync.py @@ -15,7 +15,6 @@ from awx.main.models import Organization, Team @pytest.mark.django_db class TestClaimsOldRbacSync: - def _build_claims(self, orgs, teams): """Build a claims dict from org/team model instances.""" objects = {"organization": [], "team": []} diff --git a/awx/main/tests/functional/dab_rbac/test_consolidate_teams.py b/awx/main/tests/functional/dab_rbac/test_consolidate_teams.py index 1e42059e56..f1ff591cb8 100644 --- a/awx/main/tests/functional/dab_rbac/test_consolidate_teams.py +++ b/awx/main/tests/functional/dab_rbac/test_consolidate_teams.py @@ -85,12 +85,12 @@ def test_consolidate_indirect_user_roles_with_nested_teams(setup_managed_roles, assert team_g_users_after == set(team_g.member_role.members.all().values_list('id', flat=True)) # Verify team-to-team relationships are removed after consolidation - assert not RoleTeamAssignment.objects.filter( - role_definition=team_member_role, team=team_f, object_id=team_e.id - ).exists(), "Team-to-team relationship F→E should be removed" - assert not RoleTeamAssignment.objects.filter( - role_definition=team_member_role, team=team_g, object_id=team_f.id - ).exists(), "Team-to-team relationship G→F should be removed" + assert not RoleTeamAssignment.objects.filter(role_definition=team_member_role, team=team_f, object_id=team_e.id).exists(), ( + "Team-to-team relationship F→E should be removed" + ) + assert not RoleTeamAssignment.objects.filter(role_definition=team_member_role, team=team_g, object_id=team_f.id).exists(), ( + "Team-to-team relationship G→F should be removed" + ) @pytest.mark.django_db diff --git a/awx/main/tests/functional/dab_rbac/test_filtered_queryset_optimization.py b/awx/main/tests/functional/dab_rbac/test_filtered_queryset_optimization.py index 966094e920..6d05694a0c 100644 --- a/awx/main/tests/functional/dab_rbac/test_filtered_queryset_optimization.py +++ b/awx/main/tests/functional/dab_rbac/test_filtered_queryset_optimization.py @@ -28,7 +28,7 @@ class TestHostManagerDeferral: """ansible_facts should be in the deferred set for default Host queries.""" qs = Host.objects.all() deferred = qs.query.deferred_loading[0] - assert 'ansible_facts' in deferred, f'ansible_facts should be deferred by the HostManager. ' f'Deferred fields: {deferred}' + assert 'ansible_facts' in deferred, f'ansible_facts should be deferred by the HostManager. Deferred fields: {deferred}' def test_ansible_facts_accessible_when_needed(self, inventory): """Deferred fields are still accessible — Django fetches on access.""" diff --git a/awx/main/tests/functional/dab_rbac/test_translation_layer.py b/awx/main/tests/functional/dab_rbac/test_translation_layer.py index 4f269a3b47..cf061196a1 100644 --- a/awx/main/tests/functional/dab_rbac/test_translation_layer.py +++ b/awx/main/tests/functional/dab_rbac/test_translation_layer.py @@ -62,9 +62,9 @@ def test_role_migration_matches(request, model, setup_managed_roles): rd_data = {} for rd in model_rds: rd_data[rd.name] = list(rd.permissions.values_list('codename', flat=True)) - assert ( - 'Compat' not in rd.name - ), f'Permissions for old vs new roles did not match.\nold {field.name}: {old_codenames}\nnew:\n{json.dumps(rd_data, indent=2)}' + assert 'Compat' not in rd.name, ( + f'Permissions for old vs new roles did not match.\nold {field.name}: {old_codenames}\nnew:\n{json.dumps(rd_data, indent=2)}' + ) assert new_codenames == set(old_codenames) # In the old system these models did not have object-level roles, all others expect some model roles diff --git a/awx/main/tests/functional/dab_rbac/test_unified_job_access.py b/awx/main/tests/functional/dab_rbac/test_unified_job_access.py index 69022934c1..0146c7b22d 100644 --- a/awx/main/tests/functional/dab_rbac/test_unified_job_access.py +++ b/awx/main/tests/functional/dab_rbac/test_unified_job_access.py @@ -135,7 +135,7 @@ def test_unified_job_list_team_member_sees_team_granted_jobs(user, setup_managed response = get(reverse('api:unified_job_list'), team_user) assert response.status_code == 200 result_ids = [r['id'] for r in response.data['results']] - assert job.pk in result_ids, f"Team member should see job {job.pk} via team-granted JT execute permission, " f"but got result IDs: {result_ids}" + assert job.pk in result_ids, f"Team member should see job {job.pk} via team-granted JT execute permission, but got result IDs: {result_ids}" @pytest.mark.django_db diff --git a/awx/main/tests/functional/tasks/test_fact_cache.py b/awx/main/tests/functional/tasks/test_fact_cache.py index 07e6a325ec..616bf67d65 100644 --- a/awx/main/tests/functional/tasks/test_fact_cache.py +++ b/awx/main/tests/functional/tasks/test_fact_cache.py @@ -171,7 +171,7 @@ class TestFinishFactCacheConcurrentProtection: ) host.refresh_from_db() - assert host.ansible_facts == {}, 'Stale facts should have been cleared when the fact file is missing ' 'and ansible_facts_modified predates job_created' + assert host.ansible_facts == {}, 'Stale facts should have been cleared when the fact file is missing and ansible_facts_modified predates job_created' @pytest.mark.django_db diff --git a/awx/main/tests/functional/test_inventory_source_injectors.py b/awx/main/tests/functional/test_inventory_source_injectors.py index 8f740db72f..c51202b0e4 100644 --- a/awx/main/tests/functional/test_inventory_source_injectors.py +++ b/awx/main/tests/functional/test_inventory_source_injectors.py @@ -230,9 +230,9 @@ def test_inventory_update_injected_content(product_name, this_kind, inventory, f # Assert inventory plugin inventory file is in private_data_dir inventory_filename = InventorySource.injectors[inventory_update.source]().filename - assert ( - len([True for k in content.keys() if k.endswith(inventory_filename)]) > 0 - ), f"'{inventory_filename}' file not found in inventory update runtime files {content.keys()}" + assert len([True for k in content.keys() if k.endswith(inventory_filename)]) > 0, ( + f"'{inventory_filename}' file not found in inventory update runtime files {content.keys()}" + ) env.pop('ANSIBLE_COLLECTIONS_PATH', None) base_dir = os.path.join(DATA, 'plugins') diff --git a/awx/main/tests/functional/test_migrations.py b/awx/main/tests/functional/test_migrations.py index 2081c32f56..e6a09ae3a5 100644 --- a/awx/main/tests/functional/test_migrations.py +++ b/awx/main/tests/functional/test_migrations.py @@ -164,15 +164,15 @@ class TestMigrationSmoke: CredentialType = new_state.apps.get_model('main', 'CredentialType') for expected_name in validate_exists: - assert CredentialType.objects.filter( - name=expected_name - ).exists(), f'Could not find {expected_name} credential type name, all names: {list(CredentialType.objects.values_list("name", flat=True))}' + assert CredentialType.objects.filter(name=expected_name).exists(), ( + f'Could not find {expected_name} credential type name, all names: {list(CredentialType.objects.values_list("name", flat=True))}' + ) # Verify the system_administrator role exists Role = new_state.apps.get_model('main', 'Role') - assert Role.objects.filter( - singleton_name='system_administrator', role_field='system_administrator' - ).exists(), "expected to find a system_administrator singleton role" + assert Role.objects.filter(singleton_name='system_administrator', role_field='system_administrator').exists(), ( + "expected to find a system_administrator singleton role" + ) @pytest.mark.django_db @@ -215,15 +215,15 @@ class TestGithubAppBug: CredentialType = new_state.apps.get_model('main', 'CredentialType') # Get CredentialType model from the new state # Assertion 1: The CredentialType with the old 'github_app' kind should no longer exist. - assert not CredentialType.objects.filter( - namespace='github_app' - ).exists(), "CredentialType with old 'github_app' kind should no longer exist after migration." + assert not CredentialType.objects.filter(namespace='github_app').exists(), ( + "CredentialType with old 'github_app' kind should no longer exist after migration." + ) # Assertion 2: The CredentialType should now exist with the new 'github_app_lookup' kind # and retain its original name. - assert CredentialType.objects.filter( - namespace='github_app_lookup', name='Legacy GitHub App Credential' - ).exists(), "CredentialType should be updated to 'github_app_lookup' and retain its name." + assert CredentialType.objects.filter(namespace='github_app_lookup', name='Legacy GitHub App Credential').exists(), ( + "CredentialType should be updated to 'github_app_lookup' and retain its name." + ) @pytest.mark.django_db @@ -245,9 +245,9 @@ class TestSystemAuditorMigration: new_state = migrator.apply_tested_migration(('main', '0192_custom_roles')) RoleUserAssignment = new_state.apps.get_model('dab_rbac', 'RoleUserAssignment') - assert RoleUserAssignment.objects.filter( - user=user.id, role_definition__name='Platform Auditor' - ).exists(), "system_auditor member should have been granted Platform Auditor" + assert RoleUserAssignment.objects.filter(user=user.id, role_definition__name='Platform Auditor').exists(), ( + "system_auditor member should have been granted Platform Auditor" + ) def test_fix_system_auditor_migration_backfills_missing(self, migrator): """ @@ -269,16 +269,16 @@ class TestSystemAuditorMigration: # Simulate the pre-fix state: remove the Platform Auditor assignment platform_auditor = RoleDefinition.objects.get(name='Platform Auditor') RoleUserAssignment.objects.filter(user=user.id, role_definition=platform_auditor).delete() - assert not RoleUserAssignment.objects.filter( - user=user.id, role_definition=platform_auditor - ).exists(), "Setup: user should not have Platform Auditor before corrective migration" + assert not RoleUserAssignment.objects.filter(user=user.id, role_definition=platform_auditor).exists(), ( + "Setup: user should not have Platform Auditor before corrective migration" + ) state = migrator.apply_tested_migration(('main', '0208_fix_system_auditor_migration')) RoleUserAssignment = state.apps.get_model('dab_rbac', 'RoleUserAssignment') - assert RoleUserAssignment.objects.filter( - user=user.id, role_definition__name='Platform Auditor' - ).exists(), "Corrective migration should have backfilled Platform Auditor" + assert RoleUserAssignment.objects.filter(user=user.id, role_definition__name='Platform Auditor').exists(), ( + "Corrective migration should have backfilled Platform Auditor" + ) def test_fix_system_auditor_migration_no_duplicates(self, migrator): """ @@ -302,6 +302,6 @@ class TestSystemAuditorMigration: state = migrator.apply_tested_migration(('main', '0208_fix_system_auditor_migration')) RoleUserAssignment = state.apps.get_model('dab_rbac', 'RoleUserAssignment') - assert ( - RoleUserAssignment.objects.filter(user=user.id, role_definition__name='Platform Auditor').count() == 1 - ), "Should have exactly one Platform Auditor assignment, not duplicates" + assert RoleUserAssignment.objects.filter(user=user.id, role_definition__name='Platform Auditor').count() == 1, ( + "Should have exactly one Platform Auditor assignment, not duplicates" + ) diff --git a/awx/main/tests/functional/test_notifications.py b/awx/main/tests/functional/test_notifications.py index cf93030ac6..b66ddc319d 100644 --- a/awx/main/tests/functional/test_notifications.py +++ b/awx/main/tests/functional/test_notifications.py @@ -163,9 +163,11 @@ def test_custom_environment_injection(post, user, organization): expect=201, ) template = NotificationTemplate.objects.get(pk=response.data['id']) - with pytest.raises(ConnectionError), override_settings(AWX_TASK_ENV={'HTTPS_PROXY': '192.168.50.100:1234'}), mock.patch.object( - HTTPAdapter, 'send' - ) as fake_send: + with ( + pytest.raises(ConnectionError), + override_settings(AWX_TASK_ENV={'HTTPS_PROXY': '192.168.50.100:1234'}), + mock.patch.object(HTTPAdapter, 'send') as fake_send, + ): def _send_side_effect(request, **kw): assert select_proxy(request.url, kw['proxies']) == '192.168.50.100:1234' diff --git a/awx/main/tests/live/tests/test_indirect_counting_external_queries.py b/awx/main/tests/live/tests/test_indirect_counting_external_queries.py index 6dd445cab2..003b7d7da2 100644 --- a/awx/main/tests/live/tests/test_indirect_counting_external_queries.py +++ b/awx/main/tests/live/tests/test_indirect_counting_external_queries.py @@ -218,7 +218,7 @@ def test_embedded_query_takes_precedence(live_tmp_folder, run_job_from_playbook, # Verify the embedded query was used (includes device_type in facts) host_audit = IndirectManagedNodeAudit.objects.filter(job=job).first() assert host_audit.facts == {'device_type': 'Fake Host'}, ( - 'Expected embedded query output (with device_type). ' 'If facts is {}, the external query was incorrectly used instead.' + 'Expected embedded query output (with device_type). If facts is {}, the external query was incorrectly used instead.' ) @@ -288,7 +288,7 @@ def test_fallback_does_not_overcount(live_tmp_folder, run_job_from_playbook, ena # Critical safety check: fallback must never count MORE than exact assert fallback_count <= exact_count, ( - f'Overcounting detected! Fallback produced {fallback_count} records ' f'but exact match produced only {exact_count} records.' + f'Overcounting detected! Fallback produced {fallback_count} records but exact match produced only {exact_count} records.' ) # Both use the same jq expression and same module, so counts should be equal @@ -343,5 +343,5 @@ def test_no_counting_without_compatible_fallback(live_tmp_folder, run_job_from_p # No audit records should exist for this job assert IndirectManagedNodeAudit.objects.filter(job=job).count() == 0, ( - 'IndirectManagedNodeAudit records were created despite no compatible ' 'fallback existing for demo.external v3.0.0 (only v1.x queries available).' + 'IndirectManagedNodeAudit records were created despite no compatible fallback existing for demo.external v3.0.0 (only v1.x queries available).' ) diff --git a/awx/main/tests/live/tests/test_nested_workflow_artifacts.py b/awx/main/tests/live/tests/test_nested_workflow_artifacts.py index e6fb0a8f60..f0bd35576a 100644 --- a/awx/main/tests/live/tests/test_nested_workflow_artifacts.py +++ b/awx/main/tests/live/tests/test_nested_workflow_artifacts.py @@ -120,7 +120,7 @@ def test_nested_workflow_set_stats_precedence(live_tmp_folder, demo_inv, project reader_extra_vars = json.loads(reader_node.job.extra_vars) # var1: only set by outer job_first, no conflict — should propagate through - assert reader_extra_vars.get('var1') == 'outer-only', f'var1: expected "outer-only" (uncontested outer artifact), ' f'got "{reader_extra_vars.get("var1")}"' + assert reader_extra_vars.get('var1') == 'outer-only', f'var1: expected "outer-only" (uncontested outer artifact), got "{reader_extra_vars.get("var1")}"' # var2: set by outer as "should-be-overridden", then by inner as "from-inner" # Inner workflow's own ancestor artifacts should take precedence @@ -132,7 +132,7 @@ def test_nested_workflow_set_stats_precedence(live_tmp_folder, demo_inv, project ) # var3: only set by inner job_second — should propagate normally - assert reader_extra_vars.get('var3') == 'inner-only', f'var3: expected "inner-only" (inner-only artifact), ' f'got "{reader_extra_vars.get("var3")}"' + assert reader_extra_vars.get('var3') == 'inner-only', f'var3: expected "inner-only" (inner-only artifact), got "{reader_extra_vars.get("var3")}"' @pytest.mark.django_db(transaction=True) diff --git a/awx/main/tests/unit/api/serializers/test_job_serializers.py b/awx/main/tests/unit/api/serializers/test_job_serializers.py index e6a27afd05..5bd849821d 100644 --- a/awx/main/tests/unit/api/serializers/test_job_serializers.py +++ b/awx/main/tests/unit/api/serializers/test_job_serializers.py @@ -76,7 +76,7 @@ class TestJobSerializerGetRelated: class TestJobSerializerSubstitution: def test_survey_password_hide(self, mocker): job = mocker.MagicMock( - **{'display_extra_vars.return_value': '{\"secret_key\": \"$encrypted$\"}', 'extra_vars.return_value': '{\"secret_key\": \"my_password\"}'} + **{'display_extra_vars.return_value': '{"secret_key": "$encrypted$"}', 'extra_vars.return_value': '{"secret_key": "my_password"}'} ) serializer = JobSerializer(job) rep = serializer.to_representation(job) diff --git a/awx/main/tests/unit/api/serializers/test_notification_template_serializers.py b/awx/main/tests/unit/api/serializers/test_notification_template_serializers.py index c9cfad00b2..22376c5d72 100644 --- a/awx/main/tests/unit/api/serializers/test_notification_template_serializers.py +++ b/awx/main/tests/unit/api/serializers/test_notification_template_serializers.py @@ -29,7 +29,7 @@ class TestNotificationTemplateSerializer: }, {'started': {'body': '{{ job_metadata }}'}}, {'started': {'body': '{{ job.summary_fields.inventory.total_hosts }}'}}, - {'started': {'body': u'Iñtërnâtiônàlizætiøn'}}, + {'started': {'body': 'Iñtërnâtiônàlizætiøn'}}, ], ) def test_valid_messages(self, valid_messages): diff --git a/awx/main/tests/unit/api/serializers/test_unified_serializers.py b/awx/main/tests/unit/api/serializers/test_unified_serializers.py index 36558f92cb..5e90e539d1 100644 --- a/awx/main/tests/unit/api/serializers/test_unified_serializers.py +++ b/awx/main/tests/unit/api/serializers/test_unified_serializers.py @@ -29,9 +29,9 @@ def test_unified_job_list_field_consistency(): for cls in UnifiedJob.__subclasses__(): list_serializer = getattr(serializers, '{}ListSerializer'.format(cls.__name__)) unified_serializer = serializers.UnifiedJobListSerializer().get_sub_serializer(cls()) - assert set(list_serializer().fields.keys()) == set( - unified_serializer().fields.keys() - ), 'Mismatch between {} list serializer & unified list serializer'.format(cls) + assert set(list_serializer().fields.keys()) == set(unified_serializer().fields.keys()), ( + 'Mismatch between {} list serializer & unified list serializer'.format(cls) + ) def test_unified_job_detail_exclusive_fields(): diff --git a/awx/main/tests/unit/api/test_views.py b/awx/main/tests/unit/api/test_views.py index 503ad6e854..f9dcea2aed 100644 --- a/awx/main/tests/unit/api/test_views.py +++ b/awx/main/tests/unit/api/test_views.py @@ -278,9 +278,9 @@ class TestSurveySpecValidation: ({'type': 'password', 'default': ['some', 'invalid', 'list']}, 'expected to be string'), ({'type': 'password', 'default': False}, 'expected to be string'), ({'type': 'integer', 'default': 'foo'}, 'expected to be int'), - ({'type': 'integer', 'default': u'🐉'}, 'expected to be int'), + ({'type': 'integer', 'default': '🐉'}, 'expected to be int'), ({'type': 'foo'}, 'allowed question types'), - ({'type': u'🐉'}, 'allowed question types'), + ({'type': '🐉'}, 'allowed question types'), ({'type': 'multiplechoice'}, 'multiplechoice must specify choices'), ({'type': 'integer', 'min': 'foo'}, 'min limit in survey question 0 expected to be integer'), ({'question_name': 42}, "'question_name' in survey question 0 expected to be string."), diff --git a/awx/main/tests/unit/models/test_jobs.py b/awx/main/tests/unit/models/test_jobs.py index 763dc0b4e0..46a95bf1ca 100644 --- a/awx/main/tests/unit/models/test_jobs.py +++ b/awx/main/tests/unit/models/test_jobs.py @@ -29,7 +29,7 @@ def hosts(ref_time): Host(name='host1', ansible_facts={"a": 1, "b": 2}, ansible_facts_modified=ref_time, inventory=inventory), Host(name='host2', ansible_facts={"a": 1, "b": 2}, ansible_facts_modified=ref_time, inventory=inventory), Host(name='host3', ansible_facts={"a": 1, "b": 2}, ansible_facts_modified=ref_time, inventory=inventory), - Host(name=u'Iñtërnâtiônàlizætiøn', ansible_facts={"a": 1, "b": 2}, ansible_facts_modified=ref_time, inventory=inventory), + Host(name='Iñtërnâtiônàlizætiøn', ansible_facts={"a": 1, "b": 2}, ansible_facts_modified=ref_time, inventory=inventory), ] diff --git a/awx/main/tests/unit/models/test_project.py b/awx/main/tests/unit/models/test_project.py index ee4e86c08b..9c559d1098 100644 --- a/awx/main/tests/unit/models/test_project.py +++ b/awx/main/tests/unit/models/test_project.py @@ -11,4 +11,4 @@ def test_clean_credential_insights(): with pytest.raises(ValidationError) as e: proj.clean_credential() - assert json.dumps(str(e.value)) == json.dumps(str([u'Insights Credential is required for an Insights Project.'])) + assert json.dumps(str(e.value)) == json.dumps(str(['Insights Credential is required for an Insights Project.'])) diff --git a/awx/main/tests/unit/models/test_survey_models.py b/awx/main/tests/unit/models/test_survey_models.py index 6d9eb5dec9..8e591ac514 100644 --- a/awx/main/tests/unit/models/test_survey_models.py +++ b/awx/main/tests/unit/models/test_survey_models.py @@ -96,8 +96,8 @@ class TestSurveyVariableValidation: def job(mocker): ret = mocker.MagicMock( **{ - 'decrypted_extra_vars.return_value': '{\"secret_key\": \"my_password\"}', - 'display_extra_vars.return_value': '{\"secret_key\": \"$encrypted$\"}', + 'decrypted_extra_vars.return_value': '{"secret_key": "my_password"}', + 'display_extra_vars.return_value': '{"secret_key": "$encrypted$"}', 'extra_vars_dict': {"secret_key": "my_password"}, 'pk': 1, 'job_template.pk': 1, @@ -313,7 +313,7 @@ class TestWorkflowSurveys: ({'tmpl_var': 'bar2'}, False), # different value from template, not okay ({'tmpl_var': 'bar', 'a': 2}, False), # extra key, not okay ({'tmpl_var': 'bar', False: 2}, False), # Falsy key - ({'tmpl_var': 'bar', u'🐉': u'🐉'}, False), # dragons + ({'tmpl_var': 'bar', '🐉': '🐉'}, False), # dragons ], ) class TestExtraVarsNoPrompt: diff --git a/awx/main/tests/unit/models/test_system_jobs.py b/awx/main/tests/unit/models/test_system_jobs.py index 5e2936d161..1181de4609 100644 --- a/awx/main/tests/unit/models/test_system_jobs.py +++ b/awx/main/tests/unit/models/test_system_jobs.py @@ -39,7 +39,7 @@ def test_valid__clean_extra_data_system_jobs(extra_data): ) def test_invalid__extra_data_system_jobs(extra_data): accepted, rejected, errors = SystemJobTemplate(job_type='cleanup_jobs').accept_or_ignore_variables(extra_data) - assert str(errors['extra_vars'][0]) == u'days must be a positive integer.' + assert str(errors['extra_vars'][0]) == 'days must be a positive integer.' def test_unallowed_system_job_data(): diff --git a/awx/main/tests/unit/notifications/test_rocketchat.py b/awx/main/tests/unit/notifications/test_rocketchat.py index 9f087ba98f..98d2bd2cf6 100644 --- a/awx/main/tests/unit/notifications/test_rocketchat.py +++ b/awx/main/tests/unit/notifications/test_rocketchat.py @@ -7,9 +7,10 @@ import awx.main.notifications.rocketchat_backend as rocketchat_backend def test_send_messages(): - with mock.patch('awx.main.notifications.rocketchat_backend.requests') as requests_mock, mock.patch( - 'awx.main.notifications.rocketchat_backend.get_awx_http_client_headers' - ) as version_mock: + with ( + mock.patch('awx.main.notifications.rocketchat_backend.requests') as requests_mock, + mock.patch('awx.main.notifications.rocketchat_backend.get_awx_http_client_headers') as version_mock, + ): requests_mock.post.return_value.status_code = 201 version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'} backend = rocketchat_backend.RocketChatBackend() @@ -92,9 +93,10 @@ def test_send_messages_with_icon_url(): def test_send_messages_with_no_verify_ssl(): - with mock.patch('awx.main.notifications.rocketchat_backend.requests') as requests_mock, mock.patch( - 'awx.main.notifications.rocketchat_backend.get_awx_http_client_headers' - ) as version_mock: + with ( + mock.patch('awx.main.notifications.rocketchat_backend.requests') as requests_mock, + mock.patch('awx.main.notifications.rocketchat_backend.get_awx_http_client_headers') as version_mock, + ): requests_mock.post.return_value.status_code = 201 version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'} backend = rocketchat_backend.RocketChatBackend(rocketchat_no_verify_ssl=True) diff --git a/awx/main/tests/unit/notifications/test_webhook.py b/awx/main/tests/unit/notifications/test_webhook.py index 4abbf45b70..4d0c8937ce 100644 --- a/awx/main/tests/unit/notifications/test_webhook.py +++ b/awx/main/tests/unit/notifications/test_webhook.py @@ -7,9 +7,10 @@ import awx.main.notifications.webhook_backend as webhook_backend def test_send_messages_as_POST(): - with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch( - 'awx.main.notifications.webhook_backend.get_awx_http_client_headers' - ) as version_mock: + with ( + mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, + mock.patch('awx.main.notifications.webhook_backend.get_awx_http_client_headers') as version_mock, + ): requests_mock.post.return_value.status_code = 200 version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'} backend = webhook_backend.WebhookBackend('POST', None) @@ -38,9 +39,10 @@ def test_send_messages_as_POST(): def test_send_messages_as_PUT(): - with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch( - 'awx.main.notifications.webhook_backend.get_awx_http_client_headers' - ) as version_mock: + with ( + mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, + mock.patch('awx.main.notifications.webhook_backend.get_awx_http_client_headers') as version_mock, + ): requests_mock.put.return_value.status_code = 200 version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'} backend = webhook_backend.WebhookBackend('PUT', None) @@ -69,9 +71,10 @@ def test_send_messages_as_PUT(): def test_send_messages_with_username(): - with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch( - 'awx.main.notifications.webhook_backend.get_awx_http_client_headers' - ) as version_mock: + with ( + mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, + mock.patch('awx.main.notifications.webhook_backend.get_awx_http_client_headers') as version_mock, + ): requests_mock.post.return_value.status_code = 200 version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'} backend = webhook_backend.WebhookBackend('POST', None, username='userstring') @@ -100,9 +103,10 @@ def test_send_messages_with_username(): def test_send_messages_with_password(): - with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch( - 'awx.main.notifications.webhook_backend.get_awx_http_client_headers' - ) as version_mock: + with ( + mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, + mock.patch('awx.main.notifications.webhook_backend.get_awx_http_client_headers') as version_mock, + ): requests_mock.post.return_value.status_code = 200 version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'} backend = webhook_backend.WebhookBackend('POST', None, password='passwordstring') @@ -131,9 +135,10 @@ def test_send_messages_with_password(): def test_send_messages_with_username_and_password(): - with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch( - 'awx.main.notifications.webhook_backend.get_awx_http_client_headers' - ) as version_mock: + with ( + mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, + mock.patch('awx.main.notifications.webhook_backend.get_awx_http_client_headers') as version_mock, + ): requests_mock.post.return_value.status_code = 200 version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'} backend = webhook_backend.WebhookBackend('POST', None, username='userstring', password='passwordstring') @@ -162,9 +167,10 @@ def test_send_messages_with_username_and_password(): def test_send_messages_with_no_verify_ssl(): - with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch( - 'awx.main.notifications.webhook_backend.get_awx_http_client_headers' - ) as version_mock: + with ( + mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, + mock.patch('awx.main.notifications.webhook_backend.get_awx_http_client_headers') as version_mock, + ): requests_mock.post.return_value.status_code = 200 version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'} backend = webhook_backend.WebhookBackend('POST', None, disable_ssl_verification=True) @@ -193,9 +199,10 @@ def test_send_messages_with_no_verify_ssl(): def test_send_messages_with_additional_headers(): - with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch( - 'awx.main.notifications.webhook_backend.get_awx_http_client_headers' - ) as version_mock: + with ( + mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, + mock.patch('awx.main.notifications.webhook_backend.get_awx_http_client_headers') as version_mock, + ): requests_mock.post.return_value.status_code = 200 version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'} backend = webhook_backend.WebhookBackend('POST', {'X-Test-Header1': 'test-content-1', 'X-Test-Header2': 'test-content-2'}) @@ -229,9 +236,10 @@ def test_send_messages_with_additional_headers(): def test_send_messages_with_redirects_ok(): - with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch( - 'awx.main.notifications.webhook_backend.get_awx_http_client_headers' - ) as version_mock: + with ( + mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, + mock.patch('awx.main.notifications.webhook_backend.get_awx_http_client_headers') as version_mock, + ): # First two calls return redirects, third call returns 200 requests_mock.post.side_effect = [ mock.Mock(status_code=301, headers={"Location": "http://redirect1.com"}), @@ -266,9 +274,11 @@ def test_send_messages_with_redirects_ok(): def test_send_messages_with_redirects_blank(): - with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch( - 'awx.main.notifications.webhook_backend.get_awx_http_client_headers' - ) as version_mock, mock.patch('awx.main.notifications.webhook_backend.logger') as logger_mock: + with ( + mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, + mock.patch('awx.main.notifications.webhook_backend.get_awx_http_client_headers') as version_mock, + mock.patch('awx.main.notifications.webhook_backend.logger') as logger_mock, + ): # First call returns a redirect with Location header, second call returns 301 but NO Location header requests_mock.post.side_effect = [ mock.Mock(status_code=301, headers={"Location": "http://redirect1.com"}), @@ -299,9 +309,11 @@ def test_send_messages_with_redirects_blank(): def test_send_messages_with_redirects_max_retries_exceeded(): - with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch( - 'awx.main.notifications.webhook_backend.get_awx_http_client_headers' - ) as version_mock, mock.patch('awx.main.notifications.webhook_backend.logger') as logger_mock: + with ( + mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, + mock.patch('awx.main.notifications.webhook_backend.get_awx_http_client_headers') as version_mock, + mock.patch('awx.main.notifications.webhook_backend.logger') as logger_mock, + ): # Return MAX_RETRIES (5) redirect responses to exceed the retry limit requests_mock.post.side_effect = [ mock.Mock(status_code=301, headers={"Location": "http://redirect1.com"}), @@ -336,9 +348,11 @@ def test_send_messages_with_redirects_max_retries_exceeded(): def test_send_messages_with_error_status_code(): - with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch( - 'awx.main.notifications.webhook_backend.get_awx_http_client_headers' - ) as version_mock, mock.patch('awx.main.notifications.webhook_backend.logger') as logger_mock: + with ( + mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, + mock.patch('awx.main.notifications.webhook_backend.get_awx_http_client_headers') as version_mock, + mock.patch('awx.main.notifications.webhook_backend.logger') as logger_mock, + ): # Return a 404 error status code requests_mock.post.return_value = mock.Mock(status_code=404) version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'} diff --git a/awx/main/tests/unit/scheduler/test_dag_workflow.py b/awx/main/tests/unit/scheduler/test_dag_workflow.py index b4681e6b90..70dae15db9 100644 --- a/awx/main/tests/unit/scheduler/test_dag_workflow.py +++ b/awx/main/tests/unit/scheduler/test_dag_workflow.py @@ -470,8 +470,7 @@ class TestIsWorkflowDone: True, smart_str( _( - "No error handling path for workflow job node(s) [({},{})]. Workflow job node(s)" - " missing unified job template and error handling path []." + "No error handling path for workflow job node(s) [({},{})]. Workflow job node(s) missing unified job template and error handling path []." ).format(nodes[2].id, nodes[2].job.status) ), ) @@ -485,9 +484,9 @@ class TestIsWorkflowDone: assert g.has_workflow_failed() == ( True, smart_str( - _( - "No error handling path for workflow job node(s) []. Workflow job node(s) missing" " unified job template and error handling path [{}]." - ).format(nodes[2].id) + _("No error handling path for workflow job node(s) []. Workflow job node(s) missing unified job template and error handling path [{}].").format( + nodes[2].id + ) ), ) @@ -501,9 +500,9 @@ class TestIsWorkflowDone: assert g.has_workflow_failed() == ( True, smart_str( - _( - "No error handling path for workflow job node(s) []. Workflow job node(s) missing" " unified job template and error handling path [{}]." - ).format(nodes[0].id) + _("No error handling path for workflow job node(s) []. Workflow job node(s) missing unified job template and error handling path [{}].").format( + nodes[0].id + ) ), ) @@ -514,8 +513,7 @@ class TestIsWorkflowDone: True, smart_str( _( - "No error handling path for workflow job node(s) [({},{})]. Workflow job node(s)" - " missing unified job template and error handling path []." + "No error handling path for workflow job node(s) [({},{})]. Workflow job node(s) missing unified job template and error handling path []." ).format(nodes[0].id, nodes[0].job.status) ), ) @@ -527,8 +525,7 @@ class TestIsWorkflowDone: True, smart_str( _( - "No error handling path for workflow job node(s) [({},{})]. Workflow job node(s)" - " missing unified job template and error handling path []." + "No error handling path for workflow job node(s) [({},{})]. Workflow job node(s) missing unified job template and error handling path []." ).format(nodes[0].id, nodes[0].job.status) ), ) diff --git a/awx/main/tests/unit/test_fields.py b/awx/main/tests/unit/test_fields.py index 2250dbde70..53f79b116c 100644 --- a/awx/main/tests/unit/test_fields.py +++ b/awx/main/tests/unit/test_fields.py @@ -141,8 +141,8 @@ def test_cred_type_input_schema_validity(input_, valid): ({'env': {'99': '{{awx_secret}}'}}, False), ({'env': {'AWX_SECRET=': '{{awx_secret}}'}}, False), ({'env': {'ANSIBLE_SETTING': '{{awx_secret}}'}}, False), - ({'env': {'DRAGON': u'🐉'}}, False), - ({'env': {u'🐉': 'DRAGON'}}, False), + ({'env': {'DRAGON': '🐉'}}, False), + ({'env': {'🐉': 'DRAGON'}}, False), ({'extra_vars': 123}, False), ({'extra_vars': {}}, True), ({'extra_vars': {'hostname': '{{host}}'}}, True), @@ -306,7 +306,8 @@ def test_implicit_role_field_parents(): second_field_descriptor = getattr(cls, field_name) # all supported linkage types assert isinstance( - second_field_descriptor, (ReverseManyToOneDescriptor, ImplicitRoleDescriptor, ForwardManyToOneDescriptor) # not currently used + second_field_descriptor, + (ReverseManyToOneDescriptor, ImplicitRoleDescriptor, ForwardManyToOneDescriptor), # not currently used ) # only these links are supported if field_attr: diff --git a/awx/main/tests/unit/test_redact.py b/awx/main/tests/unit/test_redact.py index f175cbbf7a..c5585ff75c 100644 --- a/awx/main/tests/unit/test_redact.py +++ b/awx/main/tests/unit/test_redact.py @@ -36,7 +36,8 @@ uri = URI(scheme="https", username="myusername", password="mypasswordwith%40", h TEST_CLEARTEXT.append( { 'uri': uri, - 'text': textwrap.dedent("""\ + 'text': textwrap.dedent( + """\ PLAY [all] ******************************************************************** TASK: [delete project directory before update] ******************************** @@ -58,7 +59,9 @@ TEST_CLEARTEXT.append( localhost : ok=0 changed=0 unreachable=0 failed=1 - """ % (uri.username, uri.password, str(uri), str(uri))), + """ + % (uri.username, uri.password, str(uri), str(uri)) + ), 'host_occurrences': 2, } ) @@ -67,7 +70,8 @@ uri = URI(scheme="https", username="Dhh3U47nmC26xk9PKscV", password="PXPfWW8YzYr TEST_CLEARTEXT.append( { 'uri': uri, - 'text': textwrap.dedent("""\ + 'text': textwrap.dedent( + """\ TASK: [update project using git] ** failed: [localhost] => {"cmd": "/usr/bin/git ls-remote https://REDACTED:********", "failed": true, "rc": 128} stderr: error: Couldn't resolve host '@%s' while accessing %s @@ -77,7 +81,9 @@ TEST_CLEARTEXT.append( msg: error: Couldn't resolve host '@%s' while accessing %s fatal: HTTP request failed - """ % (uri.host, str(uri), uri.host, str(uri))), + """ + % (uri.host, str(uri), uri.host, str(uri)) + ), 'host_occurrences': 4, } ) diff --git a/awx/main/tests/unit/test_tasks.py b/awx/main/tests/unit/test_tasks.py index ba490e7252..35cf0b0d00 100644 --- a/awx/main/tests/unit/test_tasks.py +++ b/awx/main/tests/unit/test_tasks.py @@ -1303,10 +1303,10 @@ class TestInventoryUpdateCredentials(TestJobExecution): if credential: credential.credential_type.inject_credential(credential, env, safe_env, [], private_data_dir) - env["VMWARE_USER"] == "bob", - env["VMWARE_PASSWORD"] == "secret", - env["VMWARE_HOST"] == "https://example.org", - env["VMWARE_VALIDATE_CERTS"] == "False", + (env["VMWARE_USER"] == "bob",) + (env["VMWARE_PASSWORD"] == "secret",) + (env["VMWARE_HOST"] == "https://example.org",) + (env["VMWARE_VALIDATE_CERTS"] == "False",) def test_azure_rm_source_with_tenant(self, private_data_dir, inventory_update, mocker, mock_me): task = jobs.RunInventoryUpdate() diff --git a/awx/main/tests/unit/utils/test_common.py b/awx/main/tests/unit/utils/test_common.py index b5983497b2..9910164851 100644 --- a/awx/main/tests/unit/utils/test_common.py +++ b/awx/main/tests/unit/utils/test_common.py @@ -163,13 +163,13 @@ def memoized_function(mocker, mock_cache): def test_memoize_track_function(memoized_function, mock_cache): assert memoized_function('scott', 'scotterson') == 'scotterson' - assert mock_cache.get('myfunction') == {u'scott-scotterson': 'scotterson'} + assert mock_cache.get('myfunction') == {'scott-scotterson': 'scotterson'} assert memoized_function('scott', 'scotterson') == 'scotterson' assert memoized_function.calls['scott'] == 1 assert memoized_function('john', 'smith') == 'smith' - assert mock_cache.get('myfunction') == {u'scott-scotterson': 'scotterson', u'john-smith': 'smith'} + assert mock_cache.get('myfunction') == {'scott-scotterson': 'scotterson', 'john-smith': 'smith'} assert memoized_function('john', 'smith') == 'smith' assert memoized_function.calls['john'] == 1 @@ -180,7 +180,7 @@ def test_memoize_delete(memoized_function, mock_cache): assert memoized_function('john', 'smith') == 'smith' assert memoized_function.calls['john'] == 1 - assert mock_cache.get('myfunction') == {u'john-smith': 'smith'} + assert mock_cache.get('myfunction') == {'john-smith': 'smith'} with mock.patch('awx.main.utils.common.memoize_delete', side_effect=mock_cache.delete): common.memoize_delete('myfunction') diff --git a/awx/main/tests/unit/utils/test_encryption.py b/awx/main/tests/unit/utils/test_encryption.py index 58afad0ef2..8e5002e337 100644 --- a/awx/main/tests/unit/utils/test_encryption.py +++ b/awx/main/tests/unit/utils/test_encryption.py @@ -23,7 +23,7 @@ def test_encrypt_field_without_pk(): def test_encrypt_field_with_unicode_string(): - value = u'Iñtërnâtiônàlizætiøn' + value = 'Iñtërnâtiônàlizætiøn' field = Setting(value=value) encrypted = field.value = encryption.encrypt_field(field, 'value') assert encryption.decrypt_field(field, 'value') == value diff --git a/awx/main/tests/unit/utils/test_filters.py b/awx/main/tests/unit/utils/test_filters.py index c2b23de0ee..69b2a2e2ef 100644 --- a/awx/main/tests/unit/utils/test_filters.py +++ b/awx/main/tests/unit/utils/test_filters.py @@ -74,16 +74,16 @@ class TestSmartFilterQueryFromString: @pytest.mark.parametrize( "filter_string,q_expected", [ - ('facts__facts__blank=""', Q(**{u"facts__facts__blank": u""})), - ('"facts__facts__ space "="f"', Q(**{u"facts__facts__ space ": u"f"})), - ('"facts__facts__ e "=no_quotes_here', Q(**{u"facts__facts__ e ": u"no_quotes_here"})), - ('a__b__c=3', Q(**{u"a__b__c": 3})), - ('a__b__c=3.14', Q(**{u"a__b__c": 3.14})), - ('a__b__c=true', Q(**{u"a__b__c": True})), - ('a__b__c=false', Q(**{u"a__b__c": False})), - ('a__b__c=null', Q(**{u"a__b__c": None})), - ('ansible_facts__a="true"', Q(**{u"ansible_facts__contains": {u"a": u"true"}})), - ('ansible_facts__a__exact="true"', Q(**{u"ansible_facts__contains": {u"a": u"true"}})), + ('facts__facts__blank=""', Q(**{"facts__facts__blank": ""})), + ('"facts__facts__ space "="f"', Q(**{"facts__facts__ space ": "f"})), + ('"facts__facts__ e "=no_quotes_here', Q(**{"facts__facts__ e ": "no_quotes_here"})), + ('a__b__c=3', Q(**{"a__b__c": 3})), + ('a__b__c=3.14', Q(**{"a__b__c": 3.14})), + ('a__b__c=true', Q(**{"a__b__c": True})), + ('a__b__c=false', Q(**{"a__b__c": False})), + ('a__b__c=null', Q(**{"a__b__c": None})), + ('ansible_facts__a="true"', Q(**{"ansible_facts__contains": {"a": "true"}})), + ('ansible_facts__a__exact="true"', Q(**{"ansible_facts__contains": {"a": "true"}})), # ('"a__b\"__c"="true"', Q(**{u"a__b\"__c": "true"})), # ('a__b\"__c="true"', Q(**{u"a__b\"__c": "true"})), ], @@ -101,7 +101,7 @@ class TestSmartFilterQueryFromString: def test_invalid_filter_strings(self, mock_get_host_model, filter_string): with pytest.raises(RuntimeError) as e: SmartFilter.query_from_string(filter_string) - assert str(e.value) == u"Invalid query " + filter_string + assert str(e.value) == "Invalid query " + filter_string @pytest.mark.parametrize( "filter_string", @@ -118,8 +118,8 @@ class TestSmartFilterQueryFromString: @pytest.mark.parametrize( "filter_string,q_expected", [ - (u'(a=abc\u1f5e3def)', Q(**{u"a": u"abc\u1f5e3def"})), - (u'(ansible_facts__a=abc\u1f5e3def)', Q(**{u"ansible_facts__contains": {u"a": u"abc\u1f5e3def"}})), + ('(a=abc\u1f5e3def)', Q(**{"a": "abc\u1f5e3def"})), + ('(ansible_facts__a=abc\u1f5e3def)', Q(**{"ansible_facts__contains": {"a": "abc\u1f5e3def"}})), ], ) def test_unicode(self, mock_get_host_model, filter_string, q_expected): @@ -129,17 +129,14 @@ class TestSmartFilterQueryFromString: @pytest.mark.parametrize( "filter_string,q_expected", [ - ('(a=b)', Q(**{u"a": u"b"})), - ('a=b and c=d', Q(**{u"a": u"b"}) & Q(**{u"c": u"d"})), - ('(a=b and c=d)', Q(**{u"a": u"b"}) & Q(**{u"c": u"d"})), - ('a=b or c=d', Q(**{u"a": u"b"}) | Q(**{u"c": u"d"})), - ('(a=b and c=d) or (e=f)', (Q(**{u"a": u"b"}) & Q(**{u"c": u"d"})) | (Q(**{u"e": u"f"}))), + ('(a=b)', Q(**{"a": "b"})), + ('a=b and c=d', Q(**{"a": "b"}) & Q(**{"c": "d"})), + ('(a=b and c=d)', Q(**{"a": "b"}) & Q(**{"c": "d"})), + ('a=b or c=d', Q(**{"a": "b"}) | Q(**{"c": "d"})), + ('(a=b and c=d) or (e=f)', (Q(**{"a": "b"}) & Q(**{"c": "d"})) | (Q(**{"e": "f"}))), ( 'a=b or a=d or a=e or a=z and b=h and b=i and b=j and b=k', - Q(**{u"a": u"b"}) - | Q(**{u"a": u"d"}) - | Q(**{u"a": u"e"}) - | Q(**{u"a": u"z"}) & Q(**{u"b": u"h"}) & Q(**{u"b": u"i"}) & Q(**{u"b": u"j"}) & Q(**{u"b": u"k"}), + Q(**{"a": "b"}) | Q(**{"a": "d"}) | Q(**{"a": "e"}) | Q(**{"a": "z"}) & Q(**{"b": "h"}) & Q(**{"b": "i"}) & Q(**{"b": "j"}) & Q(**{"b": "k"}), ), ], ) @@ -150,21 +147,21 @@ class TestSmartFilterQueryFromString: @pytest.mark.parametrize( "filter_string,q_expected", [ - ('ansible_facts__a__b__c[]=3', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [3]}}}})), - ('ansible_facts__a__b__c[]=3.14', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [3.14]}}}})), - ('ansible_facts__a__b__c[]=true', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [True]}}}})), - ('ansible_facts__a__b__c[]=false', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [False]}}}})), - ('ansible_facts__a__b__c[]="true"', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [u"true"]}}}})), - ('ansible_facts__a__b__c[]="hello world"', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [u"hello world"]}}}})), - ('ansible_facts__a__b__c[]__d[]="foobar"', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [{u"d": [u"foobar"]}]}}}})), - ('ansible_facts__a__b__c[]__d="foobar"', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [{u"d": u"foobar"}]}}}})), - ('ansible_facts__a__b__c[]__d__e="foobar"', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [{u"d": {u"e": u"foobar"}}]}}}})), - ('ansible_facts__a__b__c[]__d__e[]="foobar"', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [{u"d": {u"e": [u"foobar"]}}]}}}})), - ('ansible_facts__a__b__c[]__d__e__f[]="foobar"', Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [{u"d": {u"e": {u"f": [u"foobar"]}}}]}}}})), + ('ansible_facts__a__b__c[]=3', Q(**{"ansible_facts__contains": {"a": {"b": {"c": [3]}}}})), + ('ansible_facts__a__b__c[]=3.14', Q(**{"ansible_facts__contains": {"a": {"b": {"c": [3.14]}}}})), + ('ansible_facts__a__b__c[]=true', Q(**{"ansible_facts__contains": {"a": {"b": {"c": [True]}}}})), + ('ansible_facts__a__b__c[]=false', Q(**{"ansible_facts__contains": {"a": {"b": {"c": [False]}}}})), + ('ansible_facts__a__b__c[]="true"', Q(**{"ansible_facts__contains": {"a": {"b": {"c": ["true"]}}}})), + ('ansible_facts__a__b__c[]="hello world"', Q(**{"ansible_facts__contains": {"a": {"b": {"c": ["hello world"]}}}})), + ('ansible_facts__a__b__c[]__d[]="foobar"', Q(**{"ansible_facts__contains": {"a": {"b": {"c": [{"d": ["foobar"]}]}}}})), + ('ansible_facts__a__b__c[]__d="foobar"', Q(**{"ansible_facts__contains": {"a": {"b": {"c": [{"d": "foobar"}]}}}})), + ('ansible_facts__a__b__c[]__d__e="foobar"', Q(**{"ansible_facts__contains": {"a": {"b": {"c": [{"d": {"e": "foobar"}}]}}}})), + ('ansible_facts__a__b__c[]__d__e[]="foobar"', Q(**{"ansible_facts__contains": {"a": {"b": {"c": [{"d": {"e": ["foobar"]}}]}}}})), + ('ansible_facts__a__b__c[]__d__e__f[]="foobar"', Q(**{"ansible_facts__contains": {"a": {"b": {"c": [{"d": {"e": {"f": ["foobar"]}}}]}}}})), ( '(ansible_facts__a__b__c[]__d__e__f[]="foobar") and (ansible_facts__a__b__c[]__d__e[]="foobar")', - Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [{u"d": {u"e": {u"f": [u"foobar"]}}}]}}}}) - & Q(**{u"ansible_facts__contains": {u"a": {u"b": {u"c": [{u"d": {u"e": [u"foobar"]}}]}}}}), + Q(**{"ansible_facts__contains": {"a": {"b": {"c": [{"d": {"e": {"f": ["foobar"]}}}]}}}}) + & Q(**{"ansible_facts__contains": {"a": {"b": {"c": [{"d": {"e": ["foobar"]}}]}}}}), ), # ('"a__b\"__c"="true"', Q(**{u"a__b\"__c": "true"})), # ('a__b\"__c="true"', Q(**{u"a__b\"__c": "true"})), @@ -178,7 +175,7 @@ class TestSmartFilterQueryFromString: "filter_string,q_expected", [ # ('a__b__c[]="true"', Q(**{u"a__b__c__contains": u"\"true\""})), - ('ansible_facts__a="true"', Q(**{u"ansible_facts__contains": {u"a": u"true"}})), + ('ansible_facts__a="true"', Q(**{"ansible_facts__contains": {"a": "true"}})), # ('"a__b\"__c"="true"', Q(**{u"a__b\"__c": "true"})), # ('a__b\"__c="true"', Q(**{u"a__b\"__c": "true"})), ], @@ -190,8 +187,8 @@ class TestSmartFilterQueryFromString: @pytest.mark.parametrize( "filter_string,q_expected", [ - ('ansible_facts__a=null', Q(**{u"ansible_facts__contains": {u"a": None}})), - ('ansible_facts__c="null"', Q(**{u"ansible_facts__contains": {u"c": u"\"null\""}})), + ('ansible_facts__a=null', Q(**{"ansible_facts__contains": {"a": None}})), + ('ansible_facts__c="null"', Q(**{"ansible_facts__contains": {"c": "\"null\""}})), ], ) def test_contains_query_generated_null(self, mock_get_host_model, filter_string, q_expected): @@ -201,17 +198,17 @@ class TestSmartFilterQueryFromString: @pytest.mark.parametrize( "filter_string,q_expected", [ - ('group__search=foo', Q(Q(**{u"group__name__icontains": u"foo"}) | Q(**{u"group__description__icontains": u"foo"}))), + ('group__search=foo', Q(Q(**{"group__name__icontains": "foo"}) | Q(**{"group__description__icontains": "foo"}))), ( 'search=foo and group__search=foo', Q( - Q(**{u"name__icontains": u"foo"}) | Q(**{u"description__icontains": u"foo"}), - Q(**{u"group__name__icontains": u"foo"}) | Q(**{u"group__description__icontains": u"foo"}), + Q(**{"name__icontains": "foo"}) | Q(**{"description__icontains": "foo"}), + Q(**{"group__name__icontains": "foo"}) | Q(**{"group__description__icontains": "foo"}), ), ), ( 'search=foo or ansible_facts__a=null', - Q(Q(**{u"name__icontains": u"foo"}) | Q(**{u"description__icontains": u"foo"})) | Q(**{u"ansible_facts__contains": {u"a": None}}), + Q(Q(**{"name__icontains": "foo"}) | Q(**{"description__icontains": "foo"})) | Q(**{"ansible_facts__contains": {"a": None}}), ), ], ) diff --git a/awx/main/tests/unit/utils/test_safe_yaml.py b/awx/main/tests/unit/utils/test_safe_yaml.py index 596cf708d7..6b663392d0 100644 --- a/awx/main/tests/unit/utils/test_safe_yaml.py +++ b/awx/main/tests/unit/utils/test_safe_yaml.py @@ -45,7 +45,7 @@ def test_kv_unsafe(): def test_kv_unsafe_unicode(): - assert safe_dump({'a': u'🐉'}) == '!unsafe \'a\': !unsafe "\\U0001F409"\n' + assert safe_dump({'a': '🐉'}) == '!unsafe \'a\': !unsafe "\\U0001F409"\n' def test_kv_unsafe_in_list(): diff --git a/awx/main/tests/unit/utils/test_validate_rh.py b/awx/main/tests/unit/utils/test_validate_rh.py index df4adbc44f..08b0f3edad 100644 --- a/awx/main/tests/unit/utils/test_validate_rh.py +++ b/awx/main/tests/unit/utils/test_validate_rh.py @@ -14,16 +14,14 @@ def test_validate_rh_basic_auth_rhsm(): """ licenser = Licenser() - with patch('awx.main.utils.licensing.settings') as mock_settings, patch.object( - licenser, 'get_host_from_rhsm_config', return_value='https://subscription.rhsm.redhat.com' - ) as mock_get_host, patch.object(licenser, 'get_rhsm_subs', return_value=[]) as mock_get_rhsm, patch.object( - licenser, 'get_satellite_subs' - ) as mock_get_satellite, patch.object( - licenser, 'get_crc_subs' - ) as mock_get_crc, patch.object( - licenser, 'generate_license_options_from_entitlements' - ) as mock_generate: - + with ( + patch('awx.main.utils.licensing.settings') as mock_settings, + patch.object(licenser, 'get_host_from_rhsm_config', return_value='https://subscription.rhsm.redhat.com') as mock_get_host, + patch.object(licenser, 'get_rhsm_subs', return_value=[]) as mock_get_rhsm, + patch.object(licenser, 'get_satellite_subs') as mock_get_satellite, + patch.object(licenser, 'get_crc_subs') as mock_get_crc, + patch.object(licenser, 'generate_license_options_from_entitlements') as mock_generate, + ): mock_settings.REDHAT_CANDLEPIN_HOST = None licenser.validate_rh('testuser', 'testpass', basic_auth=True) @@ -44,16 +42,14 @@ def test_validate_rh_basic_auth_satellite(): """ licenser = Licenser() - with patch('awx.main.utils.licensing.settings') as mock_settings, patch.object( - licenser, 'get_host_from_rhsm_config', return_value='https://satellite.example.com' - ) as mock_get_host, patch.object(licenser, 'get_rhsm_subs') as mock_get_rhsm, patch.object( - licenser, 'get_satellite_subs', return_value=[] - ) as mock_get_satellite, patch.object( - licenser, 'get_crc_subs' - ) as mock_get_crc, patch.object( - licenser, 'generate_license_options_from_entitlements' - ) as mock_generate: - + with ( + patch('awx.main.utils.licensing.settings') as mock_settings, + patch.object(licenser, 'get_host_from_rhsm_config', return_value='https://satellite.example.com') as mock_get_host, + patch.object(licenser, 'get_rhsm_subs') as mock_get_rhsm, + patch.object(licenser, 'get_satellite_subs', return_value=[]) as mock_get_satellite, + patch.object(licenser, 'get_crc_subs') as mock_get_crc, + patch.object(licenser, 'generate_license_options_from_entitlements') as mock_generate, + ): mock_settings.REDHAT_CANDLEPIN_HOST = None licenser.validate_rh('testuser', 'testpass', basic_auth=True) @@ -72,14 +68,14 @@ def test_validate_rh_service_account_crc(): """ licenser = Licenser() - with patch('awx.main.utils.licensing.settings') as mock_settings, patch.object(licenser, 'get_host_from_rhsm_config') as mock_get_host, patch.object( - licenser, 'get_rhsm_subs' - ) as mock_get_rhsm, patch.object(licenser, 'get_satellite_subs') as mock_get_satellite, patch.object( - licenser, 'get_crc_subs', return_value=[] - ) as mock_get_crc, patch.object( - licenser, 'generate_license_options_from_entitlements' - ) as mock_generate: - + with ( + patch('awx.main.utils.licensing.settings') as mock_settings, + patch.object(licenser, 'get_host_from_rhsm_config') as mock_get_host, + patch.object(licenser, 'get_rhsm_subs') as mock_get_rhsm, + patch.object(licenser, 'get_satellite_subs') as mock_get_satellite, + patch.object(licenser, 'get_crc_subs', return_value=[]) as mock_get_crc, + patch.object(licenser, 'generate_license_options_from_entitlements') as mock_generate, + ): mock_settings.SUBSCRIPTIONS_RHSM_URL = 'https://console.redhat.com/api/rhsm/v1/subscriptions' licenser.validate_rh('client_id', 'client_secret', basic_auth=False) @@ -99,14 +95,14 @@ def test_validate_rh_candlepin_host_prioritized_over_rhsm_config(): """ licenser = Licenser() - with patch('awx.main.utils.licensing.settings') as mock_settings, patch.object(licenser, 'get_host_from_rhsm_config') as mock_get_host, patch.object( - licenser, 'get_rhsm_subs' - ) as mock_get_rhsm, patch.object(licenser, 'get_satellite_subs', return_value=[]) as mock_get_satellite, patch.object( - licenser, 'get_crc_subs' - ) as mock_get_crc, patch.object( - licenser, 'generate_license_options_from_entitlements' - ) as mock_generate: - + with ( + patch('awx.main.utils.licensing.settings') as mock_settings, + patch.object(licenser, 'get_host_from_rhsm_config') as mock_get_host, + patch.object(licenser, 'get_rhsm_subs') as mock_get_rhsm, + patch.object(licenser, 'get_satellite_subs', return_value=[]) as mock_get_satellite, + patch.object(licenser, 'get_crc_subs') as mock_get_crc, + patch.object(licenser, 'generate_license_options_from_entitlements') as mock_generate, + ): mock_settings.REDHAT_CANDLEPIN_HOST = 'https://satellite.example.com' licenser.validate_rh('testuser', 'testpass', basic_auth=True) @@ -121,14 +117,14 @@ def test_validate_rh_prepends_scheme_when_missing(): """REDHAT_CANDLEPIN_HOST without a scheme gets https:// prepended""" licenser = Licenser() - with patch('awx.main.utils.licensing.settings') as mock_settings, patch.object(licenser, 'get_host_from_rhsm_config'), patch.object( - licenser, 'get_rhsm_subs' - ) as mock_get_rhsm, patch.object(licenser, 'get_satellite_subs', return_value=[]) as mock_get_satellite, patch.object( - licenser, 'get_crc_subs' - ), patch.object( - licenser, 'generate_license_options_from_entitlements' + with ( + patch('awx.main.utils.licensing.settings') as mock_settings, + patch.object(licenser, 'get_host_from_rhsm_config'), + patch.object(licenser, 'get_rhsm_subs') as mock_get_rhsm, + patch.object(licenser, 'get_satellite_subs', return_value=[]) as mock_get_satellite, + patch.object(licenser, 'get_crc_subs'), + patch.object(licenser, 'generate_license_options_from_entitlements'), ): - mock_settings.REDHAT_CANDLEPIN_HOST = 'satellite.example.com' licenser.validate_rh('testuser', 'testpass', basic_auth=True) @@ -140,8 +136,9 @@ def test_validate_rh_missing_user_raises_error(): """Test validate_rh raises ValueError when user is missing""" licenser = Licenser() - with patch('awx.main.utils.licensing.settings') as mock_settings, patch.object( - licenser, 'get_host_from_rhsm_config', return_value='https://subscription.rhsm.redhat.com' + with ( + patch('awx.main.utils.licensing.settings') as mock_settings, + patch.object(licenser, 'get_host_from_rhsm_config', return_value='https://subscription.rhsm.redhat.com'), ): mock_settings.REDHAT_CANDLEPIN_HOST = None with pytest.raises(ValueError, match='subscriptions_client_id or subscriptions_username is required'): @@ -152,8 +149,9 @@ def test_validate_rh_missing_password_raises_error(): """Test validate_rh raises ValueError when password is missing""" licenser = Licenser() - with patch('awx.main.utils.licensing.settings') as mock_settings, patch.object( - licenser, 'get_host_from_rhsm_config', return_value='https://subscription.rhsm.redhat.com' + with ( + patch('awx.main.utils.licensing.settings') as mock_settings, + patch.object(licenser, 'get_host_from_rhsm_config', return_value='https://subscription.rhsm.redhat.com'), ): mock_settings.REDHAT_CANDLEPIN_HOST = None with pytest.raises(ValueError, match='subscriptions_client_secret or subscriptions_password is required'): diff --git a/awx/main/utils/common.py b/awx/main/utils/common.py index 21a27980b2..831a7ab61c 100644 --- a/awx/main/utils/common.py +++ b/awx/main/utils/common.py @@ -333,16 +333,16 @@ def update_scm_url(scm_type, url, username=True, password=True, check_special_ca netloc_password = '' if netloc_username and parts.scheme != 'file' and scm_type not in ("insights", "archive"): - netloc = u':'.join([urllib.parse.quote(x, safe='') for x in (netloc_username, netloc_password) if x]) + netloc = ':'.join([urllib.parse.quote(x, safe='') for x in (netloc_username, netloc_password) if x]) else: - netloc = u'' + netloc = '' # urllib.parse strips brackets from IPv6 addresses, so we need to add them back in hostname = parts.hostname if hostname and ':' in hostname and '[' in url and ']' in url: hostname = f'[{hostname}]' - netloc = u'@'.join(filter(None, [netloc, hostname])) + netloc = '@'.join(filter(None, [netloc, hostname])) if parts.port: - netloc = u':'.join([netloc, str(parts.port)]) + netloc = ':'.join([netloc, str(parts.port)]) new_url = urllib.parse.urlunsplit([parts.scheme, netloc, parts.path, parts.query, parts.fragment]) if scp_format and parts.scheme == 'git+ssh': new_url = new_url.replace('git+ssh://', '', 1).replace('/', ':', 1) @@ -378,7 +378,7 @@ def _convert_model_field_for_display(obj, field_name, password_fields=None): if password_fields is None: password_fields = set(getattr(type(obj), 'PASSWORD_FIELDS', [])) | set(['password']) if field_name in password_fields or (isinstance(field_val, str) and field_val.startswith('$encrypted$')): - return u'hidden' + return 'hidden' if hasattr(obj, 'display_%s' % field_name): field_val = getattr(obj, 'display_%s' % field_name)() if isinstance(field_val, (list, dict)): @@ -1126,15 +1126,15 @@ def truncate_stdout(stdout, size): if size <= 0 or len(stdout) <= size: return stdout - stdout = stdout[: (size - 1)] + u'\u2026' + stdout = stdout[: (size - 1)] + '\u2026' set_count, reset_count = 0, 0 for m in ANSI_SGR_PATTERN.finditer(stdout): - if m.group() == u'\u001b[0m': + if m.group() == '\u001b[0m': reset_count += 1 else: set_count += 1 - return stdout + u'\u001b[0m' * (set_count - reset_count) + return stdout + '\u001b[0m' * (set_count - reset_count) def deepmerge(a, b): diff --git a/awx/main/utils/db.py b/awx/main/utils/db.py index 9b1b887ebe..2ce3619535 100644 --- a/awx/main/utils/db.py +++ b/awx/main/utils/db.py @@ -46,7 +46,6 @@ def db_requirement_violations() -> Optional[str]: if os.getenv('SKIP_PG_VERSION_CHECK', False): return None if connection.vendor == 'postgresql': - # enforce the postgres version is a minimum of 12 (we need this for partitioning); if not, then terminate program with exit code of 1 # In the future if we require a feature of a version of postgres > 12 this should be updated to reflect that. # The return of connection.pg_version is something like 12013 diff --git a/awx/main/utils/filters.py b/awx/main/utils/filters.py index 3b22f7e4ab..3fa87ede0a 100644 --- a/awx/main/utils/filters.py +++ b/awx/main/utils/filters.py @@ -118,11 +118,11 @@ class DynamicLevelFilter(Filter): def string_to_type(t): - if t == u'null': + if t == 'null': return None - if t == u'true': + if t == 'true': return True - elif t == u'false': + elif t == 'false': return False if re.search(r'^[-+]?[0-9]+$', t): @@ -151,7 +151,7 @@ class SmartFilter(object): search_kwargs = self._expand_search(k, v) if search_kwargs: kwargs.update(search_kwargs) - q = reduce(lambda x, y: x | y, [models.Q(**{u'%s__icontains' % _k: _v}) for _k, _v in kwargs.items()]) + q = reduce(lambda x, y: x | y, [models.Q(**{'%s__icontains' % _k: _v}) for _k, _v in kwargs.items()]) self.result = Host.objects.filter(q) else: # detect loops and restrict access to sensitive fields @@ -168,7 +168,7 @@ class SmartFilter(object): return v def strip_quotes_json_logic(self, v): - if type(v) is str and v.startswith('"') and v.endswith('"') and v != u'"null"': + if type(v) is str and v.startswith('"') and v.endswith('"') and v != '"null"': return v[1:-1] return v @@ -203,9 +203,9 @@ class SmartFilter(object): strip_len = len(SmartFilter.SEARCHABLE_RELATIONSHIP) k = k[strip_len:] - pieces = k.split(u'__') + pieces = k.split('__') - assembled_k = u'%s__contains' % (SmartFilter.SEARCHABLE_RELATIONSHIP) + assembled_k = '%s__contains' % (SmartFilter.SEARCHABLE_RELATIONSHIP) assembled_v = None last_v = None @@ -213,7 +213,7 @@ class SmartFilter(object): for i, piece in enumerate(pieces): new_kv = dict() - if piece.endswith(u'[]'): + if piece.endswith('[]'): new_v = [] new_kv[piece[0:-2]] = new_v else: @@ -241,7 +241,7 @@ class SmartFilter(object): def _extract_key_value(self, t): k = t[0] - v = t[1] if len(t) > 1 else u"" + v = t[1] if len(t) > 1 else "" # Strip quotes from key if isinstance(k, str) and k.startswith('"') and k.endswith('"'): @@ -333,7 +333,7 @@ class SmartFilter(object): try: res = bool_expr.parse_string(filter_string, parse_all=True) except (pp.ParseException, FieldDoesNotExist): - raise RuntimeError(u"Invalid query %s" % filter_string_raw) + raise RuntimeError("Invalid query %s" % filter_string_raw) if len(res) > 0: return res[0].result diff --git a/awx/main/utils/licensing.py b/awx/main/utils/licensing.py index b95dcdc32e..39f6863b2e 100644 --- a/awx/main/utils/licensing.py +++ b/awx/main/utils/licensing.py @@ -265,9 +265,7 @@ class Licenser(object): except requests.exceptions.ConnectionError as error: raise error except OSError as error: - raise OSError( - 'Unable to open certificate bundle {}. Check that the service is running on Red Hat Enterprise Linux.'.format(verify) - ) from error # noqa + raise OSError('Unable to open certificate bundle {}. Check that the service is running on Red Hat Enterprise Linux.'.format(verify)) from error # noqa subs.raise_for_status() for sub in subs.json(): @@ -328,9 +326,7 @@ class Licenser(object): except requests.exceptions.ConnectionError as error: raise error except OSError as error: - raise OSError( - 'Unable to open certificate bundle {}. Check that the service is running on Red Hat Enterprise Linux.'.format(verify) - ) from error # noqa + raise OSError('Unable to open certificate bundle {}. Check that the service is running on Red Hat Enterprise Linux.'.format(verify)) from error # noqa orgs.raise_for_status() for org in orgs.json()['results']: diff --git a/awx/main/utils/mem_inventory.py b/awx/main/utils/mem_inventory.py index 3167710d8c..52ac4d1ba7 100644 --- a/awx/main/utils/mem_inventory.py +++ b/awx/main/utils/mem_inventory.py @@ -134,7 +134,7 @@ class MemInventory(object): try: port = int(name.split(':')[1]) except (ValueError, UnicodeDecodeError): - logger.warning(u'Invalid port "%s" for host "%s"', name.split(':')[1], host_name) + logger.warning('Invalid port "%s" for host "%s"', name.split(':')[1], host_name) port = None else: host_name = name diff --git a/awx/main/utils/safe_yaml.py b/awx/main/utils/safe_yaml.py index 3dbfffc6a1..5ae5c333aa 100644 --- a/awx/main/utils/safe_yaml.py +++ b/awx/main/utils/safe_yaml.py @@ -20,7 +20,7 @@ class SafeLoader(yaml.Loader): return node -SafeLoader.add_constructor(u'!unsafe', SafeLoader.construct_yaml_unsafe) +SafeLoader.add_constructor('!unsafe', SafeLoader.construct_yaml_unsafe) def safe_dump(x, safe_dict=None): diff --git a/awxkit/awxkit/api/pages/ad_hoc_commands.py b/awxkit/awxkit/api/pages/ad_hoc_commands.py index 92dc34c523..afd466ef7b 100644 --- a/awxkit/awxkit/api/pages/ad_hoc_commands.py +++ b/awxkit/awxkit/api/pages/ad_hoc_commands.py @@ -39,7 +39,7 @@ class AdHocCommand(HasCreate, UnifiedJob): verbosity=verbosity, inventory=self.ds.inventory, credential=self.ds.credential, - **kwargs + **kwargs, ) payload.ds = DSAdapter(self.__class__.__name__, self._dependency_store) return payload @@ -53,7 +53,7 @@ class AdHocCommand(HasCreate, UnifiedJob): verbosity=verbosity, inventory=inventory, credential=credential, - **kwargs + **kwargs, ) return self.update_identity(AdHocCommands(self.connection).post(payload)) diff --git a/awxkit/awxkit/api/pages/execution_environments.py b/awxkit/awxkit/api/pages/execution_environments.py index 028aa51efd..6c9abc9412 100644 --- a/awxkit/awxkit/api/pages/execution_environments.py +++ b/awxkit/awxkit/api/pages/execution_environments.py @@ -42,7 +42,7 @@ class ExecutionEnvironment(HasCreate, HasCopy, base.Base): organization=organization.id if organization else None, credential=credential.id if credential else None, pull=pull, - **kwargs + **kwargs, ) return payload diff --git a/awxkit/awxkit/api/pages/projects.py b/awxkit/awxkit/api/pages/projects.py index 125f452637..f1b64effd8 100644 --- a/awxkit/awxkit/api/pages/projects.py +++ b/awxkit/awxkit/api/pages/projects.py @@ -70,7 +70,7 @@ class Project(HasCopy, HasCreate, HasNotifications, UnifiedJobTemplate): scm_url=scm_url, scm_branch=scm_branch, credential=credential, - **kwargs + **kwargs, ) payload.ds = DSAdapter(self.__class__.__name__, self._dependency_store) return payload @@ -84,7 +84,7 @@ class Project(HasCopy, HasCreate, HasNotifications, UnifiedJobTemplate): scm_branch=scm_branch, organization=organization, credential=credential, - **kwargs + **kwargs, ) self.update_identity(Projects(self.connection).post(payload)) diff --git a/awxkit/awxkit/cli/client.py b/awxkit/awxkit/cli/client.py index 1e15442ab8..e3e76118b0 100755 --- a/awxkit/awxkit/cli/client.py +++ b/awxkit/awxkit/cli/client.py @@ -156,7 +156,7 @@ class CLI(object): self.root.connection.login(username, password) self.root.get() except Exception as e: - raise RuntimeError(f"Basic authentication failed: {str(e)}. " "Verify credentials and network connectivity.") from e + raise RuntimeError(f"Basic authentication failed: {str(e)}. Verify credentials and network connectivity.") from e return # Use session-based authentication (default) diff --git a/awxkit/awxkit/cli/custom.py b/awxkit/awxkit/cli/custom.py index d0e52114df..61fbc55bc8 100644 --- a/awxkit/awxkit/cli/custom.py +++ b/awxkit/awxkit/cli/custom.py @@ -174,7 +174,7 @@ class ProjectCreate(CustomAction): resource = 'projects' def add_arguments(self, parser, resource_options_parser): - parser.choices[self.action].add_argument('--monitor', action='store_true', help=('If set, prints stdout of the project update until ' 'it finishes.')) + parser.choices[self.action].add_argument('--monitor', action='store_true', help=('If set, prints stdout of the project update until it finishes.')) parser.choices[self.action].add_argument('--wait', action='store_true', help='If set, waits until the new project has updated.') def post(self, kwargs): diff --git a/awxkit/awxkit/utils/toposort.py b/awxkit/awxkit/utils/toposort.py index 58eec59646..dc5b6ee1c1 100644 --- a/awxkit/awxkit/utils/toposort.py +++ b/awxkit/awxkit/utils/toposort.py @@ -42,9 +42,7 @@ class CircularDependencyError(ValueError): def __init__(self, data): # Sort the data just to make the output consistent, for use in # error messages. That's convenient for doctests. - s = 'Circular dependencies exist among these items: {{{}}}'.format( - ', '.join('{!r}:{!r}'.format(key, value) for key, value in sorted(data.items())) - ) # noqa + s = 'Circular dependencies exist among these items: {{{}}}'.format(', '.join('{!r}:{!r}'.format(key, value) for key, value in sorted(data.items()))) # noqa super(CircularDependencyError, self).__init__(s) self.data = data