qontract-reconcile 0.10.1rc975__py3-none-any.whl → 0.10.1rc977__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. {qontract_reconcile-0.10.1rc975.dist-info → qontract_reconcile-0.10.1rc977.dist-info}/METADATA +1 -1
  2. {qontract_reconcile-0.10.1rc975.dist-info → qontract_reconcile-0.10.1rc977.dist-info}/RECORD +110 -110
  3. reconcile/aus/healthchecks.py +1 -1
  4. reconcile/aws_account_manager/integration.py +23 -21
  5. reconcile/aws_account_manager/reconciler.py +1 -1
  6. reconcile/aws_saml_idp/integration.py +5 -5
  7. reconcile/aws_saml_roles/integration.py +5 -5
  8. reconcile/aws_version_sync/utils.py +3 -3
  9. reconcile/cna/state.py +2 -2
  10. reconcile/database_access_manager.py +2 -5
  11. reconcile/external_resources/manager.py +3 -3
  12. reconcile/external_resources/model.py +1 -1
  13. reconcile/external_resources/secrets_sync.py +2 -2
  14. reconcile/external_resources/state.py +1 -1
  15. reconcile/gcr_mirror.py +2 -6
  16. reconcile/jira_permissions_validator.py +4 -4
  17. reconcile/ldap_groups/integration.py +4 -7
  18. reconcile/ocm_internal_notifications/integration.py +2 -2
  19. reconcile/openshift_base.py +14 -14
  20. reconcile/openshift_cluster_bots.py +1 -1
  21. reconcile/openshift_clusterrolebindings.py +9 -10
  22. reconcile/openshift_namespace_labels.py +2 -2
  23. reconcile/openshift_namespaces.py +1 -1
  24. reconcile/openshift_resources_base.py +9 -9
  25. reconcile/openshift_rolebindings.py +8 -11
  26. reconcile/openshift_saas_deploy_trigger_base.py +8 -5
  27. reconcile/oum/base.py +1 -1
  28. reconcile/quay_mirror.py +3 -10
  29. reconcile/queries.py +1 -1
  30. reconcile/saas_auto_promotions_manager/merge_request_manager/mr_parser.py +2 -2
  31. reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +1 -1
  32. reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py +0 -1
  33. reconcile/skupper_network/integration.py +3 -1
  34. reconcile/skupper_network/site_controller.py +8 -8
  35. reconcile/slack_usergroups.py +10 -10
  36. reconcile/status_board.py +1 -1
  37. reconcile/statuspage/status.py +1 -3
  38. reconcile/terraform_cloudflare_dns.py +2 -3
  39. reconcile/terraform_cloudflare_users.py +2 -3
  40. reconcile/terraform_repo.py +5 -3
  41. reconcile/terraform_resources.py +16 -16
  42. reconcile/terraform_tgw_attachments.py +6 -6
  43. reconcile/terraform_vpc_peerings.py +8 -8
  44. reconcile/terraform_vpc_resources/integration.py +1 -1
  45. reconcile/test/test_aws_cloudwatch_log_retention.py +2 -5
  46. reconcile/test/test_github_org.py +18 -16
  47. reconcile/test/test_github_repo_invites.py +10 -10
  48. reconcile/test/test_integrations_manager.py +11 -11
  49. reconcile/test/test_ocm_additional_routers.py +6 -6
  50. reconcile/test/test_ocm_clusters.py +1 -0
  51. reconcile/test/test_ocm_update_recommended_version.py +2 -2
  52. reconcile/test/test_openshift_serviceaccount_tokens.py +5 -5
  53. reconcile/test/test_openshift_tekton_resources.py +3 -3
  54. reconcile/test/test_saasherder.py +48 -48
  55. reconcile/test/test_sql_query.py +1 -1
  56. reconcile/test/test_terraform_cloudflare_resources.py +14 -14
  57. reconcile/test/test_terraform_cloudflare_users.py +4 -4
  58. reconcile/test/test_terraform_resources.py +32 -32
  59. reconcile/test/test_terraform_tgw_attachments.py +5 -5
  60. reconcile/typed_queries/saas_files.py +1 -1
  61. reconcile/unleash_feature_toggles/integration.py +2 -2
  62. reconcile/utils/aggregated_list.py +1 -1
  63. reconcile/utils/aws_api.py +1 -1
  64. reconcile/utils/aws_api_typed/iam.py +4 -2
  65. reconcile/utils/aws_api_typed/service_quotas.py +2 -2
  66. reconcile/utils/binary.py +1 -1
  67. reconcile/utils/clusterhealth/telemeter.py +5 -3
  68. reconcile/utils/config.py +4 -2
  69. reconcile/utils/expiration.py +1 -1
  70. reconcile/utils/external_resources.py +4 -7
  71. reconcile/utils/git.py +1 -3
  72. reconcile/utils/gitlab_api.py +1 -4
  73. reconcile/utils/glitchtip/client.py +7 -2
  74. reconcile/utils/gql.py +9 -8
  75. reconcile/utils/helm.py +1 -1
  76. reconcile/utils/imap_client.py +3 -1
  77. reconcile/utils/internal_groups/client.py +1 -1
  78. reconcile/utils/jinja2/utils.py +4 -4
  79. reconcile/utils/jobcontroller/models.py +2 -2
  80. reconcile/utils/jump_host.py +1 -1
  81. reconcile/utils/ldap_client.py +1 -1
  82. reconcile/utils/merge_request_manager/merge_request_manager.py +1 -4
  83. reconcile/utils/models.py +2 -5
  84. reconcile/utils/oc.py +18 -28
  85. reconcile/utils/ocm/ocm.py +3 -1
  86. reconcile/utils/ocm/products.py +2 -2
  87. reconcile/utils/ocm/search_filters.py +4 -11
  88. reconcile/utils/ocm_base_client.py +1 -4
  89. reconcile/utils/openshift_resource.py +12 -19
  90. reconcile/utils/quay_api.py +1 -3
  91. reconcile/utils/repo_owners.py +2 -8
  92. reconcile/utils/runtime/runner.py +1 -1
  93. reconcile/utils/saasherder/saasherder.py +4 -4
  94. reconcile/utils/secret_reader.py +2 -2
  95. reconcile/utils/slack_api.py +1 -1
  96. reconcile/utils/sqs_gateway.py +1 -1
  97. reconcile/utils/state.py +4 -4
  98. reconcile/utils/terraform/config_client.py +1 -1
  99. reconcile/utils/terraform_client.py +2 -2
  100. reconcile/utils/terrascript_aws_client.py +13 -23
  101. reconcile/utils/three_way_diff_strategy.py +3 -9
  102. reconcile/utils/unleash/client.py +2 -2
  103. reconcile/utils/vault.py +11 -14
  104. reconcile/utils/vcs.py +1 -1
  105. reconcile/vault_replication.py +1 -1
  106. tools/app_interface_reporter.py +2 -3
  107. tools/qontract_cli.py +1 -1
  108. {qontract_reconcile-0.10.1rc975.dist-info → qontract_reconcile-0.10.1rc977.dist-info}/WHEEL +0 -0
  109. {qontract_reconcile-0.10.1rc975.dist-info → qontract_reconcile-0.10.1rc977.dist-info}/entry_points.txt +0 -0
  110. {qontract_reconcile-0.10.1rc975.dist-info → qontract_reconcile-0.10.1rc977.dist-info}/top_level.txt +0 -0
reconcile/utils/helm.py CHANGED
@@ -70,7 +70,7 @@ def do_template(
70
70
  msg += f" {e.stdout.decode()}"
71
71
  if e.stderr:
72
72
  msg += f" {e.stderr.decode()}"
73
- raise HelmTemplateError(msg)
73
+ raise HelmTemplateError(msg) from None
74
74
 
75
75
  return result.stdout.decode()
76
76
 
@@ -33,7 +33,9 @@ class ImapClient:
33
33
  try:
34
34
  config = {k: data[k] for k in required_keys}
35
35
  except KeyError as e:
36
- raise Exception(f"Missing expected IMAP config key in vault secret: {e}")
36
+ raise Exception(
37
+ f"Missing expected IMAP config key in vault secret: {e}"
38
+ ) from None
37
39
  return config
38
40
 
39
41
  def get_mails(
@@ -46,7 +46,7 @@ class InternalGroupsApi:
46
46
  resp.raise_for_status()
47
47
  except requests.exceptions.HTTPError as e:
48
48
  if e.response is not None and e.response.status_code == 404:
49
- raise NotFound
49
+ raise NotFound(e.response.text) from e
50
50
  raise
51
51
 
52
52
  def __enter__(self) -> Self:
@@ -175,9 +175,9 @@ def lookup_secret(
175
175
  except (SecretNotFound, SecretFieldNotFound) as e:
176
176
  if allow_not_found:
177
177
  return None
178
- raise FetchSecretError(e)
178
+ raise FetchSecretError(e) from None
179
179
  except Exception as e:
180
- raise FetchSecretError(e)
180
+ raise FetchSecretError(e) from e
181
181
 
182
182
 
183
183
  def process_jinja2_template(
@@ -221,12 +221,12 @@ def process_jinja2_template(
221
221
  })
222
222
  if "_template_mocks" in vars:
223
223
  for k, v in vars["_template_mocks"].items():
224
- vars[k] = lambda *args, **kwargs: v
224
+ vars[k] = lambda *args, **kwargs: v # noqa: B023
225
225
  try:
226
226
  template = compile_jinja2_template(body, extra_curly, template_render_options)
227
227
  r = template.render(vars)
228
228
  except Exception as e:
229
- raise Jinja2TemplateError(e)
229
+ raise Jinja2TemplateError(e) from None
230
230
  return r
231
231
 
232
232
 
@@ -160,7 +160,7 @@ class K8sJob(ABC):
160
160
  )
161
161
  ),
162
162
  )
163
- for secret_key_name in self.secret_data().keys()
163
+ for secret_key_name in self.secret_data()
164
164
  ]
165
165
 
166
166
  def scripts_volume_mount(self, directory: str) -> V1VolumeMount:
@@ -189,7 +189,7 @@ class K8sJob(ABC):
189
189
  key=script_name,
190
190
  path=script_name,
191
191
  )
192
- for script_name in self.scripts().keys()
192
+ for script_name in self.scripts()
193
193
  ],
194
194
  ),
195
195
  )
@@ -90,7 +90,7 @@ class JumpHostSSH(JumpHostBase):
90
90
  try:
91
91
  known_hosts = self._gql_api.get_resource(known_hosts_path)
92
92
  except gql.GqlGetResourceError as e:
93
- raise FetchResourceError(str(e))
93
+ raise FetchResourceError(str(e)) from None
94
94
  return known_hosts["content"]
95
95
 
96
96
  def _init_known_hosts_file(self) -> None:
@@ -33,7 +33,7 @@ class LdapClient:
33
33
  _, _, results, _ = self.connection.search(
34
34
  self.base_dn, f"(&(objectclass=person)(|{user_filter}))", attributes=["uid"]
35
35
  )
36
- return set(r["attributes"]["uid"][0] for r in results)
36
+ return {r["attributes"]["uid"][0] for r in results}
37
37
 
38
38
  def get_group_members(self, groups_dns: set[str]) -> dict[str, set[str]]:
39
39
  """
@@ -43,10 +43,7 @@ class MergeRequestManagerBase(Generic[T]):
43
43
  ) -> OpenMergeRequest | None:
44
44
  for mr in self._open_mrs:
45
45
  mr_info_dict = mr.mr_info.dict()
46
- if all(
47
- mr_info_dict.get(k) == expected_data.get(k)
48
- for k in expected_data.keys()
49
- ):
46
+ if all(mr_info_dict.get(k) == expected_data.get(k) for k in expected_data):
50
47
  return mr
51
48
 
52
49
  return None
reconcile/utils/models.py CHANGED
@@ -94,10 +94,7 @@ class CSV(list[str]):
94
94
 
95
95
  @classmethod
96
96
  def validate(cls, value: str) -> list[str]:
97
- if not value:
98
- items = []
99
- else:
100
- items = value.split(",")
97
+ items = [] if not value else value.split(",")
101
98
  return items
102
99
 
103
100
  @classmethod
@@ -123,4 +120,4 @@ def cron_validator(value: str) -> str:
123
120
  croniter(value)
124
121
  return value
125
122
  except ValueError as e:
126
- raise ValueError(f"Invalid cron expression: {e}")
123
+ raise ValueError(f"Invalid cron expression: {e}") from None
reconcile/utils/oc.py CHANGED
@@ -231,14 +231,10 @@ def equal_spec_template(t1: dict, t2: dict) -> bool:
231
231
  """Compare two spec.templates."""
232
232
  t1_copy = copy.deepcopy(t1)
233
233
  t2_copy = copy.deepcopy(t2)
234
- try:
234
+ with suppress(KeyError):
235
235
  del t1_copy["metadata"]["labels"]["pod-template-hash"]
236
- except KeyError:
237
- pass
238
- try:
236
+ with suppress(KeyError):
239
237
  del t2_copy["metadata"]["labels"]["pod-template-hash"]
240
- except KeyError:
241
- pass
242
238
  return t1_copy == t2_copy
243
239
 
244
240
 
@@ -740,11 +736,11 @@ class OCCli: # pylint: disable=too-many-public-methods
740
736
  cmd = ["logs", "--all-containers=true", "-n", namespace, f"job/{name}"]
741
737
  if follow:
742
738
  cmd.append("-f")
743
- # pylint: disable=consider-using-with
739
+
744
740
  if isinstance(output, TextIOWrapper):
745
741
  output_file = output
746
742
  else:
747
- output_file = open(os.path.join(output, name), "w", encoding="locale")
743
+ output_file = open(os.path.join(output, name), "w", encoding="locale") # noqa: SIM115
748
744
 
749
745
  if wait_for_logs_process:
750
746
  subprocess.run(self.oc_base_cmd + cmd, stdout=output_file, check=False)
@@ -1138,7 +1134,7 @@ class OCCli: # pylint: disable=too-many-public-methods
1138
1134
  try:
1139
1135
  out_json = json.loads(out)
1140
1136
  except ValueError as e:
1141
- raise JSONParsingError(out + "\n" + str(e))
1137
+ raise JSONParsingError(out + "\n" + str(e)) from e
1142
1138
 
1143
1139
  return out_json
1144
1140
 
@@ -1280,13 +1276,13 @@ class OCNative(OCCli):
1280
1276
 
1281
1277
  @retry(exceptions=(ServerTimeoutError, InternalServerError, ForbiddenError))
1282
1278
  def _get_client(self, server, token):
1283
- opts = dict(
1284
- api_key={"authorization": f"Bearer {token}"},
1285
- host=server,
1286
- verify_ssl=False,
1279
+ opts = {
1280
+ "api_key": {"authorization": f"Bearer {token}"},
1281
+ "host": server,
1282
+ "verify_ssl": False,
1287
1283
  # default timeout seems to be 1+ minutes
1288
- retries=5,
1289
- )
1284
+ "retries": 5,
1285
+ }
1290
1286
  if self.jump_host:
1291
1287
  # the ports could be parameterized, but at this point
1292
1288
  # we only have need of 1 tunnel for 1 service
@@ -1307,7 +1303,7 @@ class OCNative(OCCli):
1307
1303
  try:
1308
1304
  return DynamicClient(k8s_client, discoverer=OpenshiftLazyDiscoverer)
1309
1305
  except urllib3.exceptions.MaxRetryError as e:
1310
- raise StatusCodeError(f"[{self.server}]: {e}")
1306
+ raise StatusCodeError(f"[{self.server}]: {e}") from None
1311
1307
 
1312
1308
  def _get_obj_client(self, kind, group_version):
1313
1309
  key = f"{kind}.{group_version}"
@@ -1380,7 +1376,7 @@ class OCNative(OCCli):
1380
1376
  except NotFoundError as e:
1381
1377
  if allow_not_found:
1382
1378
  return {}
1383
- raise StatusCodeError(f"[{self.server}]: {e}")
1379
+ raise StatusCodeError(f"[{self.server}]: {e}") from None
1384
1380
 
1385
1381
  def get_all(self, kind, all_namespaces=False):
1386
1382
  k, group_version = self._parse_kind(kind)
@@ -1388,7 +1384,7 @@ class OCNative(OCCli):
1388
1384
  try:
1389
1385
  return obj_client.get(_request_timeout=REQUEST_TIMEOUT).to_dict()
1390
1386
  except NotFoundError as e:
1391
- raise StatusCodeError(f"[{self.server}]: {e}")
1387
+ raise StatusCodeError(f"[{self.server}]: {e}") from None
1392
1388
 
1393
1389
 
1394
1390
  OCClient = OCNative | OCCli
@@ -1640,10 +1636,7 @@ class OC_Map:
1640
1636
  )
1641
1637
  return
1642
1638
 
1643
- if self.use_jump_host:
1644
- jump_host = cluster_info.get("jumpHost")
1645
- else:
1646
- jump_host = None
1639
+ jump_host = cluster_info.get("jumpHost") if self.use_jump_host else None
1647
1640
  if jump_host:
1648
1641
  self.set_jh_ports(jump_host)
1649
1642
  try:
@@ -1846,17 +1839,14 @@ class OpenshiftLazyDiscoverer(LazyDiscoverer):
1846
1839
  ]
1847
1840
  # If there are multiple matches, prefer non-List kinds
1848
1841
  if len(results) > 1 and not all( # pylint: disable=R1729
1849
- [isinstance(x, ResourceList) for x in results]
1842
+ isinstance(x, ResourceList) for x in results
1850
1843
  ):
1851
1844
  results = [
1852
1845
  result for result in results if not isinstance(result, ResourceList)
1853
1846
  ]
1854
1847
  # if multiple resources are found that share a GVK, prefer the one with the most supported verbs
1855
- if (
1856
- len(results) > 1
1857
- and len(set((x.group_version, x.kind) for x in results)) == 1
1858
- ):
1859
- if len(set(len(x.verbs) for x in results)) != 1:
1848
+ if len(results) > 1 and len({(x.group_version, x.kind) for x in results}) == 1:
1849
+ if len({len(x.verbs) for x in results}) != 1:
1860
1850
  results = [max(results, key=lambda x: len(x.verbs))]
1861
1851
  if len(results) == 1:
1862
1852
  return results[0]
@@ -828,7 +828,9 @@ class OCM: # pylint: disable=too-many-public-methods
828
828
  try:
829
829
  re.compile(b)
830
830
  except re.error:
831
- raise TypeError(f"blocked version is not a valid regex expression: {b}")
831
+ raise TypeError(
832
+ f"blocked version is not a valid regex expression: {b}"
833
+ ) from None
832
834
 
833
835
  @retry(max_attempts=10)
834
836
  def _do_get_request(self, api: str, params: Mapping[str, str]) -> dict[str, Any]:
@@ -354,7 +354,7 @@ class OCMProductRosa(OCMProduct):
354
354
  e.cleanup()
355
355
  raise OCMValidationException(
356
356
  f"last 10 lines from failed cluster creation job...\n\n{logs}"
357
- )
357
+ ) from None
358
358
 
359
359
  def update_cluster(
360
360
  self,
@@ -629,7 +629,7 @@ class OCMProductHypershift(OCMProduct):
629
629
  e.cleanup()
630
630
  raise OCMValidationException(
631
631
  f"last 10 lines from failed cluster creation job...\n\n{logs}"
632
- )
632
+ ) from None
633
633
 
634
634
  def update_cluster(
635
635
  self,
@@ -56,7 +56,7 @@ class ListCondition(ABC, FilterCondition):
56
56
  raise InvalidFilterError(f"Cannot merge {self} with {other}")
57
57
  return type(self)(
58
58
  key=self.key,
59
- values=sorted(list(set(self.values + other.values))),
59
+ values=sorted(set(self.values + other.values)),
60
60
  )
61
61
 
62
62
 
@@ -72,9 +72,7 @@ class EqCondition(ListCondition):
72
72
  def render(self) -> str:
73
73
  if len(self.values) == 1:
74
74
  return f"{self.key}='{self._escape_value(self.values[0])}'"
75
- quoted_values = ",".join(
76
- map(lambda x: f"'{self._escape_value(x)}'", self.values)
77
- )
75
+ quoted_values = ",".join(f"'{self._escape_value(x)}'" for x in self.values)
78
76
  return f"{self.key} in ({quoted_values})"
79
77
 
80
78
  def _escape_value(self, value: Any) -> str:
@@ -93,9 +91,7 @@ class LikeCondition(ListCondition):
93
91
  def render(self) -> str:
94
92
  if len(self.values) == 1:
95
93
  return f"{self.key} like '{self.values[0]}'"
96
- quoted_values = " or ".join(
97
- map(lambda x: f"{self.key} like '{x}'", self.values)
98
- )
94
+ quoted_values = " or ".join(f"{self.key} like '{x}'" for x in self.values)
99
95
  if len(self.values) > 1:
100
96
  return f"({quoted_values})"
101
97
  return quoted_values
@@ -284,10 +280,7 @@ class Filter:
284
280
  are None or empty, the condition is not added.
285
281
  """
286
282
  if values:
287
- if isinstance(values, list):
288
- value_list = values
289
- else:
290
- value_list = list(values)
283
+ value_list = values if isinstance(values, list) else list(values)
291
284
  value_list.sort()
292
285
  return self.add_condition(EqCondition(key, value_list))
293
286
  return self
@@ -84,10 +84,7 @@ class OCMBaseClient:
84
84
  max_page_size: int = 100,
85
85
  max_pages: int | None = None,
86
86
  ) -> Generator[dict[str, Any], None, None]:
87
- if not params:
88
- params_copy = {}
89
- else:
90
- params_copy = params.copy()
87
+ params_copy = {} if not params else params.copy()
91
88
  params_copy["size"] = max_page_size
92
89
 
93
90
  while True:
@@ -1,4 +1,6 @@
1
+ # ruff: noqa: SIM114
1
2
  import base64
3
+ import contextlib
2
4
  import copy
3
5
  import datetime
4
6
  import hashlib
@@ -172,28 +174,22 @@ class OpenshiftResource:
172
174
  "uid",
173
175
  "fieldRef",
174
176
  ]
175
- if val in ignorable_fields:
176
- return True
177
- return False
177
+ return val in ignorable_fields
178
178
 
179
179
  @staticmethod
180
180
  def ignorable_key_value_pair(key, val):
181
181
  ignorable_key_value_pair = {"annotations": None, "divisor": "0"}
182
- if key in ignorable_key_value_pair and ignorable_key_value_pair[key] == val:
183
- return True
184
- return False
182
+ return bool(
183
+ key in ignorable_key_value_pair and ignorable_key_value_pair[key] == val
184
+ )
185
185
 
186
186
  @staticmethod
187
187
  def cpu_equal(val1, val2):
188
188
  # normalize both to string
189
- try:
189
+ with contextlib.suppress(Exception):
190
190
  val1 = f"{int(float(val1) * 1000)}m"
191
- except Exception:
192
- pass
193
- try:
191
+ with contextlib.suppress(Exception):
194
192
  val2 = f"{int(float(val2) * 1000)}m"
195
- except Exception:
196
- pass
197
193
  return val1 == val2
198
194
 
199
195
  @staticmethod
@@ -240,11 +236,11 @@ class OpenshiftResource:
240
236
 
241
237
  def verify_valid_k8s_object(self):
242
238
  try:
243
- self.name # pylint: disable=pointless-statement
244
- self.kind # pylint: disable=pointless-statement
239
+ assert self.name
240
+ assert self.kind
245
241
  except (KeyError, TypeError) as e:
246
242
  msg = f"resource invalid data ({e.__class__.__name__}). details: {self.error_details}"
247
- raise ConstructResourceError(msg)
243
+ raise ConstructResourceError(msg) from None
248
244
 
249
245
  if self.kind not in {
250
246
  "Role",
@@ -348,10 +344,7 @@ class OpenshiftResource:
348
344
  openshift_resource: new OpenshiftResource object with
349
345
  annotations.
350
346
  """
351
- if canonicalize:
352
- body = self.canonicalize(self.body)
353
- else:
354
- body = self.body
347
+ body = self.canonicalize(self.body) if canonicalize else self.body
355
348
 
356
349
  sha256sum = self.calculate_sha256sum(self.serialize(body))
357
350
 
@@ -57,9 +57,7 @@ class QuayApi:
57
57
  def user_exists(self, user):
58
58
  url = f"{self.api_url}/users/{user}"
59
59
  r = requests.get(url, headers=self.auth_header, timeout=self._timeout)
60
- if not r.ok:
61
- return False
62
- return True
60
+ return r.ok
63
61
 
64
62
  def remove_user_from_team(self, user, team):
65
63
  """Deletes an user from a team.
@@ -194,15 +194,9 @@ class RepoOwners:
194
194
  @staticmethod
195
195
  def _set_to_sorted_list(owners):
196
196
  approvers = owners["approvers"]
197
- if approvers:
198
- sorted_approvers = sorted(approvers)
199
- else:
200
- sorted_approvers = []
197
+ sorted_approvers = sorted(approvers) if approvers else []
201
198
 
202
199
  reviewers = owners["reviewers"]
203
- if reviewers:
204
- sorted_reviewers = sorted(reviewers)
205
- else:
206
- sorted_reviewers = []
200
+ sorted_reviewers = sorted(reviewers) if reviewers else []
207
201
 
208
202
  return {"approvers": sorted_approvers, "reviewers": sorted_reviewers}
@@ -213,7 +213,7 @@ def _integration_dry_run(
213
213
  return_exceptions=True,
214
214
  )
215
215
 
216
- for shard, result in zip(affected_shard_list, results):
216
+ for shard, result in zip(affected_shard_list, results, strict=False):
217
217
  if _is_task_result_an_error(result):
218
218
  logging.error(f"Failed to run integration shard {shard}: {result}")
219
219
  failed_shards_count = sum(1 for _ in filter(_is_task_result_an_error, results))
@@ -698,11 +698,11 @@ class SaasHerder: # pylint: disable=too-many-public-methods
698
698
  return namespaces
699
699
 
700
700
  def _collect_repo_urls(self) -> set[str]:
701
- return set(
701
+ return {
702
702
  rt.url
703
703
  for saas_file in self.saas_files
704
704
  for rt in saas_file.resource_templates
705
- )
705
+ }
706
706
 
707
707
  @staticmethod
708
708
  def _get_file_contents_github(repo: Repository, path: str, commit_sha: str) -> str:
@@ -1189,8 +1189,8 @@ class SaasHerder: # pylint: disable=too-many-public-methods
1189
1189
  creds = self.secret_reader.read_all_secret(saas_file.authentication.image)
1190
1190
  required_docker_config_keys = [".dockerconfigjson"]
1191
1191
  required_keys_basic_auth = ["user", "token"]
1192
- ok = all(k in creds.keys() for k in required_keys_basic_auth) or all(
1193
- k in creds.keys() for k in required_docker_config_keys
1192
+ ok = all(k in creds for k in required_keys_basic_auth) or all(
1193
+ k in creds for k in required_docker_config_keys
1194
1194
  )
1195
1195
  if not ok:
1196
1196
  logging.warning(
@@ -164,7 +164,7 @@ class VaultSecretReader(SecretReaderBase):
164
164
  except Forbidden:
165
165
  raise VaultForbidden(
166
166
  f"permission denied reading vault secret " f"at {path}"
167
- )
167
+ ) from None
168
168
  except vault.SecretNotFound as e:
169
169
  raise SecretNotFound(*e.args) from e
170
170
  return data
@@ -316,7 +316,7 @@ class SecretReader(SecretReaderBase):
316
316
  except Forbidden:
317
317
  raise VaultForbidden(
318
318
  f"permission denied reading vault secret " f"at {path}"
319
- )
319
+ ) from None
320
320
  except vault.SecretNotFound as e:
321
321
  raise SecretNotFound(*e.args) from e
322
322
  else:
@@ -398,7 +398,7 @@ class SlackApi:
398
398
  result = self._sc.users_lookupByEmail(email=f"{user_name}@{mail_address}")
399
399
  except SlackApiError as e:
400
400
  if e.response["error"] == "users_not_found":
401
- raise UserNotFoundException(e.response["error"])
401
+ raise UserNotFoundException(e.response["error"]) from None
402
402
  raise
403
403
 
404
404
  return result["user"]["id"]
@@ -13,7 +13,7 @@ class SQSGateway:
13
13
  """Wrapper around SQS AWS SDK"""
14
14
 
15
15
  def __init__(self, accounts, secret_reader: SecretReader):
16
- queue_url = os.environ.get("gitlab_pr_submitter_queue_url")
16
+ queue_url = os.environ.get("gitlab_pr_submitter_queue_url") # noqa: SIM112
17
17
  if not queue_url:
18
18
  raise SQSGatewayInitError(
19
19
  "when /app-interface/app-interface-settings-1.yml#mergeRequestGateway "
reconcile/utils/state.py CHANGED
@@ -251,7 +251,7 @@ class State:
251
251
  except ClientError as details:
252
252
  raise StateInaccessibleException(
253
253
  f"Bucket {self.bucket} is not accessible - {str(details)}"
254
- )
254
+ ) from None
255
255
 
256
256
  def __enter__(self) -> Self:
257
257
  return self
@@ -302,7 +302,7 @@ class State:
302
302
  raise StateInaccessibleException(
303
303
  f"Can not access state key {key_path} "
304
304
  f"in bucket {self.bucket} - {str(details)}"
305
- )
305
+ ) from None
306
306
 
307
307
  def ls(self) -> list[str]:
308
308
  """
@@ -407,10 +407,10 @@ class State:
407
407
  return json.loads(response["Body"].read())
408
408
  except ClientError as details:
409
409
  if details.response["Error"]["Code"] == "NoSuchKey":
410
- raise KeyError(item)
410
+ raise KeyError(item) from None
411
411
  raise
412
412
  except json.decoder.JSONDecodeError:
413
- raise KeyError(item)
413
+ raise KeyError(item) from None
414
414
 
415
415
  def __setitem__(self, key: str, value: Any) -> None:
416
416
  self._set(key, value)
@@ -84,7 +84,7 @@ class TerraformConfigClientCollection:
84
84
  except KeyError:
85
85
  raise ClientNotRegisteredError(
86
86
  f"There aren't any clients registered with the account name: {spec.provisioner_name}"
87
- )
87
+ ) from None
88
88
  self.resource_spec_inventory[spec.id_object()] = spec
89
89
 
90
90
  def populate_resources(self) -> None:
@@ -407,7 +407,7 @@ class TerraformClient: # pylint: disable=too-many-public-methods
407
407
  f"[{account_name}] expiration not does not match "
408
408
  f"date format {DATE_FORMAT}. details: "
409
409
  f"type: {da['type']}, name: {da['name']}"
410
- )
410
+ ) from None
411
411
  if (
412
412
  resource_type == da["type"]
413
413
  and resource_name == da["name"]
@@ -585,7 +585,7 @@ class TerraformClient: # pylint: disable=too-many-public-methods
585
585
  secret_copy["db.password"] = replica_src_password
586
586
 
587
587
  # clean metadata
588
- for key in secret.keys():
588
+ for key in secret:
589
589
  if integration_prefix in key:
590
590
  secret_copy.pop(key)
591
591