qontract-reconcile 0.10.2.dev260__py3-none-any.whl → 0.10.2.dev262__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.
- {qontract_reconcile-0.10.2.dev260.dist-info → qontract_reconcile-0.10.2.dev262.dist-info}/METADATA +17 -1
- {qontract_reconcile-0.10.2.dev260.dist-info → qontract_reconcile-0.10.2.dev262.dist-info}/RECORD +11 -11
- reconcile/aws_saml_roles/integration.py +5 -5
- reconcile/aws_version_sync/integration.py +2 -3
- reconcile/ocm_labels/integration.py +1 -4
- reconcile/rhidp/common.py +1 -2
- reconcile/run_integration.py +16 -1
- reconcile/utils/glitchtip/models.py +6 -22
- reconcile/utils/mr/user_maintenance.py +1 -1
- {qontract_reconcile-0.10.2.dev260.dist-info → qontract_reconcile-0.10.2.dev262.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev260.dist-info → qontract_reconcile-0.10.2.dev262.dist-info}/entry_points.txt +0 -0
{qontract_reconcile-0.10.2.dev260.dist-info → qontract_reconcile-0.10.2.dev262.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: qontract-reconcile
|
3
|
-
Version: 0.10.2.
|
3
|
+
Version: 0.10.2.dev262
|
4
4
|
Summary: Collection of tools to reconcile services with their desired state as defined in the app-interface DB.
|
5
5
|
Project-URL: homepage, https://github.com/app-sre/qontract-reconcile
|
6
6
|
Project-URL: repository, https://github.com/app-sre/qontract-reconcile
|
@@ -449,6 +449,22 @@ GQL definitions and generated classes can be found [here](reconcile/gql_definiti
|
|
449
449
|
|
450
450
|
`faulthandler` is enabled for this project and SIGUSR1 is registered to dump the traceback. To do so, you can use `kill -USR1 pid` where pid is the ID of the qontract-reconcile process.
|
451
451
|
|
452
|
+
## Profiling
|
453
|
+
|
454
|
+
Enable the Python cProfile module by setting the environment variable `ENABLE_PROFILING=1` before running the integration. This will generate a profile file `/tmp/profile.prof`.
|
455
|
+
|
456
|
+
You can then analyze the profile using `snakeviz`:
|
457
|
+
|
458
|
+
```sh
|
459
|
+
snakeviz /tmp/profile.prof
|
460
|
+
```
|
461
|
+
|
462
|
+
> :information_source: Note
|
463
|
+
>
|
464
|
+
> `cProfile` doesn't support multithreading, but it can still highlight performance issues on the main thread.
|
465
|
+
> If you need to profile multithreaded code, consider using [py-spy](https://github.com/benfred/py-spy) or similar tools that support sampling profiling.
|
466
|
+
> Also [memray](https://github.com/bloomberg/memray) could be beneficial for memory profiling.
|
467
|
+
|
452
468
|
## Code style guide
|
453
469
|
|
454
470
|
Qontract-reconcile uses [PEP8](https://peps.python.org/pep-0008/) as the code style guide.
|
{qontract_reconcile-0.10.2.dev260.dist-info → qontract_reconcile-0.10.2.dev262.dist-info}/RECORD
RENAMED
@@ -93,7 +93,7 @@ reconcile/query_validator.py,sha256=MSh5pKLBksws4AqfuvT8nrIGucIbqX-IOzYyPYTLO7k,
|
|
93
93
|
reconcile/requests_sender.py,sha256=914iluuF4UVgG3VyxxtnHOu4yf6YKS2fIy6PViSsFTQ,3875
|
94
94
|
reconcile/resource_scraper.py,sha256=znXCHrU7YwPfKuxGBiUrV7T1tYtn4vlz9qmZlfy6Flg,2307
|
95
95
|
reconcile/resource_template_tester.py,sha256=DsKvBuNLPxm4Fa-e1YHHySnhThm5i_j-nF3G4b02Mz0,2416
|
96
|
-
reconcile/run_integration.py,sha256=
|
96
|
+
reconcile/run_integration.py,sha256=brbNFEQpHLeLIEN-sDpIctyrx8aiL5Vu9YLecdwwykk,10221
|
97
97
|
reconcile/saas_file_validator.py,sha256=tyvFYU6lnkfDYIkAIr5pWqSvO5Yc6TagZ-quJYD2dtI,2547
|
98
98
|
reconcile/sendgrid_teammates.py,sha256=oO8QbLb4s1o8A6CGiCagN9CmS05BSS_WLztuY0Ym9D8,4773
|
99
99
|
reconcile/service_dependencies.py,sha256=G2qCuYFc8wQLpRxkdhmibxSAl3nUM3hcan4x50W_mCA,4335
|
@@ -150,9 +150,9 @@ reconcile/aws_cloudwatch_log_retention/integration.py,sha256=QY5EtCpcMN0TgOQInID
|
|
150
150
|
reconcile/aws_saml_idp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
151
151
|
reconcile/aws_saml_idp/integration.py,sha256=Z2JtUx2YIbkn0KVrVa2CoAErPB8vTykOOkWD_ZPoB94,6511
|
152
152
|
reconcile/aws_saml_roles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
153
|
-
reconcile/aws_saml_roles/integration.py,sha256=
|
153
|
+
reconcile/aws_saml_roles/integration.py,sha256=inU10Yu0lZpJw_00vVe2bytJrecjLtu2hR7kQQIAbx0,11234
|
154
154
|
reconcile/aws_version_sync/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
155
|
-
reconcile/aws_version_sync/integration.py,sha256=
|
155
|
+
reconcile/aws_version_sync/integration.py,sha256=YeqvWMfMtTqTMG6_2iL8-wLds8Lb3CAbSQcR6ebeSlA,17863
|
156
156
|
reconcile/aws_version_sync/utils.py,sha256=x-45QT7zAwdNvCg7w_qJNwLaksFcfz1_6KQoD_0IVuA,1727
|
157
157
|
reconcile/aws_version_sync/merge_request_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
158
158
|
reconcile/aws_version_sync/merge_request_manager/merge_request.py,sha256=2FbqLLdqxycWNvX1eNbwMjWSVBb7q0p-8t5Db0m7b4Q,4842
|
@@ -447,7 +447,7 @@ reconcile/ocm/types.py,sha256=mPudTvjDSO-i7ruXG2oDn64scsKhr0Zf9KMvL0bBO_o,2405
|
|
447
447
|
reconcile/ocm_internal_notifications/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
448
448
|
reconcile/ocm_internal_notifications/integration.py,sha256=SjwoHJLA-l6Upezk_ukI38lJZwu7m0giPFxALdNmOww,4428
|
449
449
|
reconcile/ocm_labels/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
450
|
-
reconcile/ocm_labels/integration.py,sha256=
|
450
|
+
reconcile/ocm_labels/integration.py,sha256=cTwxszQrbYG4R5fCGo6IdoRSS_A98dTQZCwCJ2R9RaI,15235
|
451
451
|
reconcile/oum/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
452
452
|
reconcile/oum/base.py,sha256=WCFdHOHXLPrJcvxVqw6HjaJthT7olC5BQqqXlD4DM6c,13552
|
453
453
|
reconcile/oum/labelset.py,sha256=f5kDndbaIT4iNYxTRPSELTUgj_aMlzEJDPzooAkG2mE,2154
|
@@ -458,7 +458,7 @@ reconcile/oum/standalone.py,sha256=EN5y1S-3DwUZYzSRqRMtf63mI2slvBHKiU9zOTjYvWM,7
|
|
458
458
|
reconcile/prometheus_rules_tester/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
459
459
|
reconcile/prometheus_rules_tester/integration.py,sha256=8lXZSaNqZAemulVNDxanrxwl7ZGfUxtwfptJlMPX8ac,9308
|
460
460
|
reconcile/rhidp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
461
|
-
reconcile/rhidp/common.py,sha256=
|
461
|
+
reconcile/rhidp/common.py,sha256=rqifpncnE5--sYSx7ERMGDUjNHRI-SZkpuzwepZSps4,6766
|
462
462
|
reconcile/rhidp/metrics.py,sha256=Yp0GtpjhieEdru0qkG3osBTJiKUzg6CAjwPoFTQDnCg,417
|
463
463
|
reconcile/rhidp/ocm_oidc_idp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
464
464
|
reconcile/rhidp/ocm_oidc_idp/base.py,sha256=gcrQEmHQ2GF2MtSxBcxTRsK-I19rsfIn9NZvyx8ZbyQ,7133
|
@@ -687,7 +687,7 @@ reconcile/utils/dynatrace/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
|
|
687
687
|
reconcile/utils/dynatrace/client.py,sha256=H8EjqmZlB1a2ionAjV8_R1ozs9lWbmPCYKLe0J8kZAs,2838
|
688
688
|
reconcile/utils/glitchtip/__init__.py,sha256=FT6iBhGqoe7KExFdbgL8AYUb64iW_4snF5__Dcl7yt0,258
|
689
689
|
reconcile/utils/glitchtip/client.py,sha256=F_x18QMHfeNoS3vS_VvjVm1IKnwGOsXvopjR9iwj4aY,8948
|
690
|
-
reconcile/utils/glitchtip/models.py,sha256=
|
690
|
+
reconcile/utils/glitchtip/models.py,sha256=81u2lrQWSAZ5sjCy57M3C2oKq_3mHb5NGfIvLtTN78M,6398
|
691
691
|
reconcile/utils/internal_groups/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
692
692
|
reconcile/utils/internal_groups/client.py,sha256=NTw0nXN0ju-bW3E4GGiHbuZdBYDMWJL5-kRkB86FSjg,4675
|
693
693
|
reconcile/utils/internal_groups/models.py,sha256=y_IqBVqfGqNXiu0VudvBWFrm_-uafVm5KgLG-ca8XAs,2281
|
@@ -719,7 +719,7 @@ reconcile/utils/mr/ocm_update_recommended_version.py,sha256=KGOBURLE3XMynjAFej5D
|
|
719
719
|
reconcile/utils/mr/ocm_upgrade_scheduler_org_updates.py,sha256=0myPruETuT6V2bjSSVPVsQu0ZHE9Jf3kRx5htt_fhKM,3038
|
720
720
|
reconcile/utils/mr/promote_qontract.py,sha256=oOjfxkDAFhMDWCT9xaRyLSYHcc67jCc34s_tENOuHGw,7226
|
721
721
|
reconcile/utils/mr/update_access_report_base.py,sha256=LOXTIonpfxXrvZI9nPqkszW3OnuIgbFM7pFpqHxTMp0,4395
|
722
|
-
reconcile/utils/mr/user_maintenance.py,sha256=
|
722
|
+
reconcile/utils/mr/user_maintenance.py,sha256=OC9-3YkpXsYKZGsdOdx-NLq7AkjgrhDR2JL7hov7BV8,5669
|
723
723
|
reconcile/utils/ocm/__init__.py,sha256=Y-bp8GomMpyCo0tFW6kJ78-ZG1UIupYRtBzbMWU0kwM,798
|
724
724
|
reconcile/utils/ocm/addons.py,sha256=_LDdJ-gapM3s5exKlIUt-MlXZTAUoHezbYBU0QmvfWQ,7335
|
725
725
|
reconcile/utils/ocm/base.py,sha256=nbBP1ltdI_sZ5VyDaz0PSRWgBTpJmHDd53nvYyo5Z38,14576
|
@@ -797,7 +797,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
797
797
|
tools/saas_promotion_state/saas_promotion_state.py,sha256=oF7C4hpIgyMTwTRm3Aun3cDCHIjVar65JoLp6NcJHlU,3909
|
798
798
|
tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
|
799
799
|
tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
|
800
|
-
qontract_reconcile-0.10.2.
|
801
|
-
qontract_reconcile-0.10.2.
|
802
|
-
qontract_reconcile-0.10.2.
|
803
|
-
qontract_reconcile-0.10.2.
|
800
|
+
qontract_reconcile-0.10.2.dev262.dist-info/METADATA,sha256=2vPmKVIyNdHSJFEdK89zdCs50nAzSBpRWe28i-Ysx40,24501
|
801
|
+
qontract_reconcile-0.10.2.dev262.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
802
|
+
qontract_reconcile-0.10.2.dev262.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
|
803
|
+
qontract_reconcile-0.10.2.dev262.dist-info/RECORD,,
|
@@ -58,7 +58,7 @@ class AwsSamlRolesIntegrationParams(PydanticRunParams):
|
|
58
58
|
log_cached_log_output: bool = False
|
59
59
|
|
60
60
|
@validator("max_session_duration_hours")
|
61
|
-
def max_session_duration_range(cls, v: str | int) -> int:
|
61
|
+
def max_session_duration_range(cls, v: str | int) -> int:
|
62
62
|
if 1 <= int(v) <= 12:
|
63
63
|
return int(v)
|
64
64
|
raise ValueError("max_session_duration_hours must be between 1 and 12 hours")
|
@@ -69,7 +69,7 @@ class CustomPolicy(BaseModel):
|
|
69
69
|
policy: dict[str, Any]
|
70
70
|
|
71
71
|
@validator("name")
|
72
|
-
def name_size(cls, v: str) -> str:
|
72
|
+
def name_size(cls, v: str) -> str:
|
73
73
|
"""Check the policy name size.
|
74
74
|
|
75
75
|
See https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html
|
@@ -81,7 +81,7 @@ class CustomPolicy(BaseModel):
|
|
81
81
|
return v
|
82
82
|
|
83
83
|
@validator("policy")
|
84
|
-
def policy_size(cls, v: dict[str, Any]) -> dict[str, Any]:
|
84
|
+
def policy_size(cls, v: dict[str, Any]) -> dict[str, Any]:
|
85
85
|
"""Check the policy size.
|
86
86
|
|
87
87
|
See https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html
|
@@ -104,7 +104,7 @@ class AwsRole(BaseModel):
|
|
104
104
|
managed_policies: list[ManagedPolicy]
|
105
105
|
|
106
106
|
@validator("name")
|
107
|
-
def name_size(cls, v: str) -> str:
|
107
|
+
def name_size(cls, v: str) -> str:
|
108
108
|
"""Check the role name size.
|
109
109
|
|
110
110
|
See https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html
|
@@ -116,7 +116,7 @@ class AwsRole(BaseModel):
|
|
116
116
|
return v
|
117
117
|
|
118
118
|
@root_validator
|
119
|
-
def validate_policies(cls, values: dict[str, Any]) -> dict[str, Any]:
|
119
|
+
def validate_policies(cls, values: dict[str, Any]) -> dict[str, Any]:
|
120
120
|
"""Check the policies.
|
121
121
|
|
122
122
|
See https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html
|
@@ -108,15 +108,14 @@ class ExternalResource(BaseModel):
|
|
108
108
|
|
109
109
|
@validator("resource_engine_version", pre=True)
|
110
110
|
def parse_resource_engine_version(
|
111
|
-
cls,
|
112
|
-
v: str | semver.VersionInfo,
|
111
|
+
cls, v: str | semver.VersionInfo
|
113
112
|
) -> semver.VersionInfo:
|
114
113
|
if isinstance(v, semver.VersionInfo):
|
115
114
|
return v
|
116
115
|
return parse_semver(str(v), optional_minor_and_patch=True)
|
117
116
|
|
118
117
|
@root_validator(pre=True)
|
119
|
-
def set_resource_engine_version_format(cls, values: dict) -> dict:
|
118
|
+
def set_resource_engine_version_format(cls, values: dict) -> dict:
|
120
119
|
resource_engine_version, resource_engine_version_format = (
|
121
120
|
str(values.get("resource_engine_version")),
|
122
121
|
values.get("resource_engine_version_format"),
|
@@ -63,10 +63,7 @@ class OcmLabelsIntegrationParams(PydanticRunParams):
|
|
63
63
|
ignored_label_prefixes: list[str] = []
|
64
64
|
|
65
65
|
@validator("managed_label_prefixes", "ignored_label_prefixes")
|
66
|
-
def must_end_with_dot(
|
67
|
-
cls, # noqa: N805
|
68
|
-
v: list[str],
|
69
|
-
) -> list[str]:
|
66
|
+
def must_end_with_dot(cls, v: list[str]) -> list[str]:
|
70
67
|
return [prefix + "." if not prefix.endswith(".") else prefix for prefix in v]
|
71
68
|
|
72
69
|
|
reconcile/rhidp/common.py
CHANGED
@@ -62,8 +62,7 @@ class ClusterAuth(BaseModel):
|
|
62
62
|
|
63
63
|
@root_validator
|
64
64
|
def name_no_spaces(
|
65
|
-
cls,
|
66
|
-
values: MutableMapping[str, Any],
|
65
|
+
cls, values: MutableMapping[str, Any]
|
67
66
|
) -> MutableMapping[str, Any]:
|
68
67
|
values["name"] = values["name"].replace(" ", "-")
|
69
68
|
return values
|
reconcile/run_integration.py
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
|
3
|
+
import contextlib
|
4
|
+
import cProfile
|
3
5
|
import logging
|
4
6
|
import os
|
5
7
|
import sys
|
@@ -78,6 +80,15 @@ if LOG_FILE is not None:
|
|
78
80
|
logging.basicConfig(level=LOG_LEVEL, handlers=HANDLERS)
|
79
81
|
|
80
82
|
|
83
|
+
PROFILE_DUMP_FILE = os.environ.get("PROFILE_DUMP_FILE", "/tmp/profile.prof")
|
84
|
+
profiling_enabled = os.environ.get("ENABLE_PROFILING", "").lower() in {
|
85
|
+
"true",
|
86
|
+
"1",
|
87
|
+
"yes",
|
88
|
+
}
|
89
|
+
profiler = cProfile.Profile() if profiling_enabled else contextlib.nullcontext()
|
90
|
+
|
91
|
+
|
81
92
|
class PushgatewayBadConfigError(Exception):
|
82
93
|
pass
|
83
94
|
|
@@ -238,7 +249,11 @@ def main() -> None:
|
|
238
249
|
try:
|
239
250
|
with command.make_context(info_name=COMMAND_NAME, args=args) as ctx: # type: ignore
|
240
251
|
ctx.ensure_object(dict)
|
241
|
-
|
252
|
+
with profiler as pr:
|
253
|
+
command.invoke(ctx)
|
254
|
+
if pr:
|
255
|
+
LOG.info(f"Profiling data written to {PROFILE_DUMP_FILE}")
|
256
|
+
pr.dump_stats(PROFILE_DUMP_FILE)
|
242
257
|
return_code = 0
|
243
258
|
# This is for when the integration explicitly
|
244
259
|
# calls sys.exit(N)
|
@@ -49,8 +49,7 @@ class Team(BaseModel):
|
|
49
49
|
|
50
50
|
@root_validator(pre=True)
|
51
51
|
def name_xor_slug_must_be_set(
|
52
|
-
cls,
|
53
|
-
values: MutableMapping[str, Any],
|
52
|
+
cls, values: MutableMapping[str, Any]
|
54
53
|
) -> MutableMapping[str, Any]:
|
55
54
|
assert ("name" in values or "slug" in values) and not (
|
56
55
|
"name" in values and "slug" in values
|
@@ -58,10 +57,7 @@ class Team(BaseModel):
|
|
58
57
|
return values
|
59
58
|
|
60
59
|
@root_validator
|
61
|
-
def slugify(
|
62
|
-
cls, # noqa: N805
|
63
|
-
values: MutableMapping[str, Any],
|
64
|
-
) -> MutableMapping[str, Any]:
|
60
|
+
def slugify(cls, values: MutableMapping[str, Any]) -> MutableMapping[str, Any]:
|
65
61
|
values["slug"] = values.get("slug") or slugify(values.get("name", ""))
|
66
62
|
values["name"] = slugify(values.get("name", "")) or values.get("slug")
|
67
63
|
return values
|
@@ -98,10 +94,7 @@ class ProjectAlertRecipient(BaseModel):
|
|
98
94
|
use_enum_values = True
|
99
95
|
|
100
96
|
@validator("recipient_type")
|
101
|
-
def recipient_type_enforce_enum_type(
|
102
|
-
cls, # noqa: N805
|
103
|
-
v: str | RecipientType,
|
104
|
-
) -> RecipientType:
|
97
|
+
def recipient_type_enforce_enum_type(cls, v: str | RecipientType) -> RecipientType:
|
105
98
|
if isinstance(v, RecipientType):
|
106
99
|
return v
|
107
100
|
return RecipientType[v.upper()]
|
@@ -129,10 +122,7 @@ class ProjectAlert(BaseModel):
|
|
129
122
|
allow_population_by_field_name = True
|
130
123
|
|
131
124
|
@root_validator
|
132
|
-
def empty_name(
|
133
|
-
cls, # noqa: N805
|
134
|
-
values: MutableMapping[str, Any],
|
135
|
-
) -> MutableMapping[str, Any]:
|
125
|
+
def empty_name(cls, values: MutableMapping[str, Any]) -> MutableMapping[str, Any]:
|
136
126
|
# name is an empty string if the alert was created manually because it can't be set via UI
|
137
127
|
# use the pk instead.
|
138
128
|
values["name"] = values.get("name") or f"alert-{values.get('pk')}"
|
@@ -163,10 +153,7 @@ class Project(BaseModel):
|
|
163
153
|
allow_population_by_field_name = True
|
164
154
|
|
165
155
|
@root_validator
|
166
|
-
def slugify(
|
167
|
-
cls, # noqa: N805
|
168
|
-
values: MutableMapping[str, Any],
|
169
|
-
) -> MutableMapping[str, Any]:
|
156
|
+
def slugify(cls, values: MutableMapping[str, Any]) -> MutableMapping[str, Any]:
|
170
157
|
values["slug"] = values.get("slug") or slugify(values["name"])
|
171
158
|
return values
|
172
159
|
|
@@ -207,10 +194,7 @@ class Organization(BaseModel):
|
|
207
194
|
users: list[User] = []
|
208
195
|
|
209
196
|
@root_validator
|
210
|
-
def slugify(
|
211
|
-
cls, # noqa: N805
|
212
|
-
values: MutableMapping[str, Any],
|
213
|
-
) -> MutableMapping[str, Any]:
|
197
|
+
def slugify(cls, values: MutableMapping[str, Any]) -> MutableMapping[str, Any]:
|
214
198
|
values["slug"] = values.get("slug") or slugify(values["name"])
|
215
199
|
return values
|
216
200
|
|
{qontract_reconcile-0.10.2.dev260.dist-info → qontract_reconcile-0.10.2.dev262.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|