catalystwan 0.41.2.dev3__py3-none-any.whl → 0.41.2.dev5__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.
- catalystwan/exceptions.py +7 -0
- catalystwan/integration_tests/feature_profile/test_parcel.py +54 -0
- catalystwan/models/configuration/feature_profile/parcel.py +12 -6
- catalystwan/models/configuration/feature_profile/sdwan/service/appqoe.py +3 -3
- catalystwan/models/configuration/network_hierarchy/cflowd.py +16 -15
- catalystwan/models/policy/definition/dns_security.py +1 -1
- {catalystwan-0.41.2.dev3.dist-info → catalystwan-0.41.2.dev5.dist-info}/METADATA +1 -1
- {catalystwan-0.41.2.dev3.dist-info → catalystwan-0.41.2.dev5.dist-info}/RECORD +10 -9
- {catalystwan-0.41.2.dev3.dist-info → catalystwan-0.41.2.dev5.dist-info}/LICENSE +0 -0
- {catalystwan-0.41.2.dev3.dist-info → catalystwan-0.41.2.dev5.dist-info}/WHEEL +0 -0
catalystwan/exceptions.py
CHANGED
|
@@ -216,3 +216,10 @@ class CatalystwanDeprecationWarning(DeprecationWarning):
|
|
|
216
216
|
f" The public API SHOULD NOT be considered stable."
|
|
217
217
|
)
|
|
218
218
|
return message
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
class ParcelModelNotFound(CatalystwanException):
|
|
222
|
+
"""Raised when there is no model matching parcelType field"""
|
|
223
|
+
|
|
224
|
+
def __init__(self, type_):
|
|
225
|
+
self.message = f"Cannot determine model class for parcel type: {type_}"
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Copyright 2025 Cisco Systems, Inc. and its affiliates
|
|
2
|
+
from typing import Literal, Union
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
5
|
+
from pydantic import Field
|
|
6
|
+
from typing_extensions import Annotated
|
|
7
|
+
|
|
8
|
+
from catalystwan.api.configuration_groups.parcel import _ParcelBase
|
|
9
|
+
from catalystwan.exceptions import ParcelModelNotFound
|
|
10
|
+
from catalystwan.models.configuration.feature_profile.parcel import find_type, list_types
|
|
11
|
+
from catalystwan.models.configuration.feature_profile.sdwan.topology import (
|
|
12
|
+
AnyTopologyParcel,
|
|
13
|
+
CustomControlParcel,
|
|
14
|
+
HubSpokeParcel,
|
|
15
|
+
MeshParcel,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_list_types():
|
|
20
|
+
observed_types = list_types(AnyTopologyParcel)
|
|
21
|
+
assert set(observed_types) == {MeshParcel, HubSpokeParcel, CustomControlParcel}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_find_type():
|
|
25
|
+
observed_type = find_type("mesh", AnyTopologyParcel)
|
|
26
|
+
assert observed_type == MeshParcel
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_find_type_raises_when_no_match():
|
|
30
|
+
with pytest.raises(ParcelModelNotFound):
|
|
31
|
+
find_type("unknown", AnyTopologyParcel)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_find_type_raises_for_bogus_param():
|
|
35
|
+
with pytest.raises(ParcelModelNotFound):
|
|
36
|
+
find_type("unknown", None)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_find_type_custom():
|
|
40
|
+
# Arrange
|
|
41
|
+
class CustomParcel(_ParcelBase):
|
|
42
|
+
type_: Literal["custom"] = Field(default="custom", exclude=True)
|
|
43
|
+
|
|
44
|
+
CustomUnion = Annotated[
|
|
45
|
+
Union[
|
|
46
|
+
MeshParcel,
|
|
47
|
+
CustomParcel,
|
|
48
|
+
],
|
|
49
|
+
Field(discriminator="type_"),
|
|
50
|
+
]
|
|
51
|
+
# Act
|
|
52
|
+
observed_type = find_type("custom", CustomUnion)
|
|
53
|
+
# Assert
|
|
54
|
+
assert observed_type == CustomParcel
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# Copyright 2024 Cisco Systems, Inc. and its affiliates
|
|
2
2
|
from functools import lru_cache
|
|
3
|
-
from typing import Generic, List, Literal, Optional, Sequence, TypeVar, Union, cast
|
|
3
|
+
from typing import Generic, List, Literal, Optional, Sequence, Type, TypeVar, Union, cast
|
|
4
4
|
from uuid import UUID
|
|
5
5
|
|
|
6
6
|
from pydantic import AliasChoices, BaseModel, ConfigDict, Field, model_validator
|
|
7
7
|
from typing_extensions import Annotated
|
|
8
8
|
|
|
9
|
+
from catalystwan.api.configuration_groups.parcel import _ParcelBase
|
|
10
|
+
from catalystwan.exceptions import ParcelModelNotFound
|
|
9
11
|
from catalystwan.models.configuration.feature_profile.sdwan.application_priority import AnyApplicationPriorityParcel
|
|
10
12
|
from catalystwan.models.configuration.feature_profile.sdwan.cli import AnyCliParcel
|
|
11
13
|
from catalystwan.models.configuration.feature_profile.sdwan.dns_security import AnyDnsSecurityParcel
|
|
@@ -160,6 +162,7 @@ AnyParcel = Annotated[
|
|
|
160
162
|
]
|
|
161
163
|
|
|
162
164
|
T = TypeVar("T", bound=AnyParcel)
|
|
165
|
+
UT = TypeVar("UT", bound=_ParcelBase)
|
|
163
166
|
|
|
164
167
|
|
|
165
168
|
class Parcel(BaseModel, Generic[T]):
|
|
@@ -227,12 +230,15 @@ class ParcelId(BaseModel):
|
|
|
227
230
|
|
|
228
231
|
|
|
229
232
|
@lru_cache
|
|
230
|
-
def list_types(any_union:
|
|
231
|
-
return cast(Sequence[
|
|
233
|
+
def list_types(any_union: Type[UT]) -> Sequence[UT]:
|
|
234
|
+
return cast(Sequence[UT], resolve_nested_base_model_unions(any_union))
|
|
232
235
|
|
|
233
236
|
|
|
234
237
|
@lru_cache
|
|
235
|
-
def find_type(name: str, any_union:
|
|
238
|
+
def find_type(name: str, any_union: Type[UT]) -> UT:
|
|
236
239
|
parcel_types = list_types(any_union)
|
|
237
|
-
|
|
238
|
-
|
|
240
|
+
try:
|
|
241
|
+
parcel_type = next(t for t in parcel_types if t._get_parcel_type() == name)
|
|
242
|
+
except StopIteration:
|
|
243
|
+
raise ParcelModelNotFound(name)
|
|
244
|
+
return cast(UT, parcel_type)
|
|
@@ -5,7 +5,7 @@ from typing import List, Literal, Optional, Union
|
|
|
5
5
|
|
|
6
6
|
from pydantic import AliasPath, BaseModel, ConfigDict, Field
|
|
7
7
|
|
|
8
|
-
from catalystwan.api.configuration_groups.parcel import Default, Global, Variable, _ParcelBase,
|
|
8
|
+
from catalystwan.api.configuration_groups.parcel import Default, Global, Variable, _ParcelBase, as_global
|
|
9
9
|
|
|
10
10
|
VirtualApplicationType = Literal["dreopt"]
|
|
11
11
|
|
|
@@ -254,12 +254,12 @@ class AppqoeParcel(_ParcelBase):
|
|
|
254
254
|
model_config = ConfigDict(arbitrary_types_allowed=True, populate_by_name=True, extra="forbid")
|
|
255
255
|
|
|
256
256
|
dreopt: Optional[Union[Global[bool], Default[bool]]] = Field(
|
|
257
|
-
default=
|
|
257
|
+
default=None, validation_alias=AliasPath("data", "dreopt")
|
|
258
258
|
)
|
|
259
259
|
virtual_application: Optional[List[VirtualApplication]] = Field(
|
|
260
260
|
default=None, validation_alias=AliasPath("data", "virtualApplication")
|
|
261
261
|
)
|
|
262
|
-
appqoe_device_role: Global[
|
|
262
|
+
appqoe_device_role: Global[AppqoeDeviceRole] = Field(
|
|
263
263
|
default=as_global("forwarder"), validation_alias=AliasPath("data", "appqoeDeviceRole")
|
|
264
264
|
)
|
|
265
265
|
|
|
@@ -3,7 +3,7 @@ from typing import List, Literal, Optional
|
|
|
3
3
|
|
|
4
4
|
from pydantic import AliasPath, BaseModel, ConfigDict, Field
|
|
5
5
|
|
|
6
|
-
from catalystwan.api.configuration_groups.parcel import Global, _ParcelBase,
|
|
6
|
+
from catalystwan.api.configuration_groups.parcel import Global, _ParcelBase, as_optional_global
|
|
7
7
|
|
|
8
8
|
Protocol = Literal[
|
|
9
9
|
"both",
|
|
@@ -73,7 +73,9 @@ class CflowdParcel(_ParcelBase):
|
|
|
73
73
|
flow_sampling_interval: Optional[Global[int]] = Field(
|
|
74
74
|
default=Global[int](value=1), validation_alias=AliasPath("data", "flowSamplingInterval")
|
|
75
75
|
)
|
|
76
|
-
protocol: Optional[Global[Protocol]] = Field(
|
|
76
|
+
protocol: Optional[Global[Protocol]] = Field(
|
|
77
|
+
default=Global[Protocol](value="ipv4"), validation_alias=AliasPath("data", "protocol")
|
|
78
|
+
)
|
|
77
79
|
|
|
78
80
|
def add_collector(
|
|
79
81
|
self,
|
|
@@ -97,24 +99,23 @@ class CflowdParcel(_ParcelBase):
|
|
|
97
99
|
)
|
|
98
100
|
)
|
|
99
101
|
|
|
100
|
-
def set_customized_ipv4_record_fields(
|
|
101
|
-
self, collect_dscp_output: Optional[bool] = False, collect_tos: Optional[bool] = False
|
|
102
|
-
):
|
|
102
|
+
def set_customized_ipv4_record_fields(self, collect_dscp_output: bool = False, collect_tos: bool = False):
|
|
103
103
|
self.customized_ipv4_record_fields = CustomizedIpv4RecordFields(
|
|
104
|
-
collect_dscp_output=
|
|
104
|
+
collect_dscp_output=Global[bool](value=collect_dscp_output),
|
|
105
|
+
collect_tos=Global[bool](value=collect_tos),
|
|
105
106
|
)
|
|
106
107
|
|
|
107
108
|
def set_flow(
|
|
108
109
|
self,
|
|
109
|
-
active_timeout: Optional[int]
|
|
110
|
-
inactive_timeout: Optional[int]
|
|
111
|
-
refresh_time: Optional[int]
|
|
112
|
-
sampling_interval: Optional[int]
|
|
110
|
+
active_timeout: Optional[int],
|
|
111
|
+
inactive_timeout: Optional[int],
|
|
112
|
+
refresh_time: Optional[int],
|
|
113
|
+
sampling_interval: Optional[int],
|
|
113
114
|
):
|
|
114
|
-
self.flow_active_timeout =
|
|
115
|
-
self.flow_inactive_timeout =
|
|
116
|
-
self.flow_refresh_time =
|
|
117
|
-
self.flow_sampling_interval =
|
|
115
|
+
self.flow_active_timeout = Global[int](value=active_timeout or 600)
|
|
116
|
+
self.flow_inactive_timeout = Global[int](value=inactive_timeout or 60)
|
|
117
|
+
self.flow_refresh_time = Global[int](value=refresh_time or 600)
|
|
118
|
+
self.flow_sampling_interval = Global[int](value=sampling_interval or 1)
|
|
118
119
|
|
|
119
120
|
def set_protocol(self, protocol: Protocol):
|
|
120
|
-
self.protocol =
|
|
121
|
+
self.protocol = Global[Protocol](value=protocol)
|
|
@@ -118,7 +118,7 @@ class DnsSecurityDefinition(BaseModel):
|
|
|
118
118
|
|
|
119
119
|
|
|
120
120
|
class DnsSecurityPolicy(PolicyDefinitionBase):
|
|
121
|
-
type: Literal["dnsSecurity"] = "
|
|
121
|
+
type: Literal["DNSSecurity", "dnsSecurity"] = "DNSSecurity"
|
|
122
122
|
definition: DnsSecurityDefinition
|
|
123
123
|
|
|
124
124
|
|
|
@@ -212,7 +212,7 @@ catalystwan/endpoints/tenant_management.py,sha256=c-kIRoS60aVklVPPrmbnW5kaiNgU23
|
|
|
212
212
|
catalystwan/endpoints/tenant_migration.py,sha256=e6eIzRvlrnzUWqamKbWsYjX8drtB-GQKvhrJtX2VDKY,3649
|
|
213
213
|
catalystwan/endpoints/troubleshooting_tools/device_connectivity.py,sha256=JkTZfebTwcambJsgjcJ8qxxBDE5XbUFyYpNqr9681DQ,3661
|
|
214
214
|
catalystwan/endpoints/url_monitoring.py,sha256=ZySOjuCpIAZ4SIsah56yJ-uybYw0W9s6OjQp2FujN0g,802
|
|
215
|
-
catalystwan/exceptions.py,sha256=
|
|
215
|
+
catalystwan/exceptions.py,sha256=MAtoZ9xrXmUgG-zMbdtChF7B2sHAgVlzv-euHOY1kKo,6620
|
|
216
216
|
catalystwan/integration_tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
217
217
|
catalystwan/integration_tests/base.py,sha256=0BcKgDZcGjdPH2316C-1Se4FUeAtdrNXdkUVp_aXEZc,2367
|
|
218
218
|
catalystwan/integration_tests/feature_profile/sdwan/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -231,6 +231,7 @@ catalystwan/integration_tests/feature_profile/sdwan/test_system.py,sha256=ab6fG7
|
|
|
231
231
|
catalystwan/integration_tests/feature_profile/sdwan/test_tracker.py,sha256=GnIEHmUoIZObtBK-YvjYYtDsFnGSDpAVwi4rk9-r7XE,5117
|
|
232
232
|
catalystwan/integration_tests/feature_profile/sdwan/test_transport.py,sha256=xRS880JCUD06xL_EaHKNylvaXB9wRHqUYsORhU2MYus,78923
|
|
233
233
|
catalystwan/integration_tests/feature_profile/sdwan/topology/test_topology.py,sha256=2vsAd0pk3wcfo8wFTRttnw4gjSPJi1KFfFCu5lGAiJQ,4340
|
|
234
|
+
catalystwan/integration_tests/feature_profile/test_parcel.py,sha256=4dqt5IP39lJ6vTsx3X7OdAHpYdbsIlDdpASFAM6d87Y,1517
|
|
234
235
|
catalystwan/integration_tests/profile_builder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
235
236
|
catalystwan/integration_tests/profile_builder/test_pb_service.py,sha256=WO6VVA7kNXesyGtk67e0lMDZBd4Z8wB7espBh0TzUTA,9420
|
|
236
237
|
catalystwan/integration_tests/profile_builder/test_pb_transport.py,sha256=QQ5f1q6OV9dIyRQy1lb3Wp9beIKaWDaDLnNoGm4XY6A,10376
|
|
@@ -245,7 +246,7 @@ catalystwan/models/configuration/common.py,sha256=2X9gj5awWPKtLPFgWfxhkRrMoX22t1
|
|
|
245
246
|
catalystwan/models/configuration/feature_profile/README.md,sha256=IQMhbnEAbLtotT80aL2emekH-ou8CqR0WSYXhZXilJw,10050
|
|
246
247
|
catalystwan/models/configuration/feature_profile/builder.py,sha256=GDqK7ZxnWHTKWHRw13xvD1aDl60xe6gFsP_B9z5T8a8,663
|
|
247
248
|
catalystwan/models/configuration/feature_profile/common.py,sha256=a5xohaoXzAewtqYYdk2GJy7B-rxxlxYatlP2WZ1eZqY,30423
|
|
248
|
-
catalystwan/models/configuration/feature_profile/parcel.py,sha256=
|
|
249
|
+
catalystwan/models/configuration/feature_profile/parcel.py,sha256=k3IyNVzjtDrTjUEBYvzQeQWeqNhRNk2tXDYqbQXWX2o,7583
|
|
249
250
|
catalystwan/models/configuration/feature_profile/sdwan/acl/__init__.py,sha256=-AXvVMLyaAYWUnwzTT_mvar37ZpO2vNRy_ZsUIA5dGo,324
|
|
250
251
|
catalystwan/models/configuration/feature_profile/sdwan/acl/ipv4acl.py,sha256=HpiY0DCZWE9EHCbMbyIJ-iRharSRO3IGcSV3kWbMXjY,12167
|
|
251
252
|
catalystwan/models/configuration/feature_profile/sdwan/acl/ipv6acl.py,sha256=MRtDNb2v1TNNf3yijLFlzL3H1KxHOquPmww1V9ZCacI,12969
|
|
@@ -314,7 +315,7 @@ catalystwan/models/configuration/feature_profile/sdwan/routing/bgp.py,sha256=4vX
|
|
|
314
315
|
catalystwan/models/configuration/feature_profile/sdwan/routing/ospf.py,sha256=hfsfL9Fy4q7eUybhSzPDGTFgdlK1VO3zPUy1aNOOCIc,7647
|
|
315
316
|
catalystwan/models/configuration/feature_profile/sdwan/routing/ospfv3.py,sha256=KW0UgMPt08OxLbX4JoShNby83HCMhlHICRLLW8pYinQ,13268
|
|
316
317
|
catalystwan/models/configuration/feature_profile/sdwan/service/__init__.py,sha256=AzPWWFozmwg5nzwEj-bYhg2HTeJJ8FFPQHmvyxDvSnQ,2378
|
|
317
|
-
catalystwan/models/configuration/feature_profile/sdwan/service/appqoe.py,sha256=
|
|
318
|
+
catalystwan/models/configuration/feature_profile/sdwan/service/appqoe.py,sha256=6_diZuOtJnq0x6QFuwHQ3IgSmV5a6S-Yql7uN-JlF8c,10223
|
|
318
319
|
catalystwan/models/configuration/feature_profile/sdwan/service/dhcp_server.py,sha256=XCYUektYRLZaIzJAiAuSeuKg2DdAYio38t0niN8CkhA,5289
|
|
319
320
|
catalystwan/models/configuration/feature_profile/sdwan/service/dual_router_ha.py,sha256=MMwnBKBth3E91EYCPLtGJqwQYilZPWelGF6KLJmtOPw,1134
|
|
320
321
|
catalystwan/models/configuration/feature_profile/sdwan/service/eigrp.py,sha256=d02hMwUFq5ycoknQci0SAgRlxuiYh0kSKDBxOzn-ves,4075
|
|
@@ -385,7 +386,7 @@ catalystwan/models/configuration/feature_profile/sdwan/uc_voice/trunk_group.py,s
|
|
|
385
386
|
catalystwan/models/configuration/feature_profile/sdwan/uc_voice/voice_global.py,sha256=9v3-IBHo0Qzxlguq6k8UbCE1SKJdoeoOO0q65HsoWIQ,2290
|
|
386
387
|
catalystwan/models/configuration/feature_profile/sdwan/uc_voice/voice_tenant.py,sha256=7av6UzCBbztqFNbfhRIbJGDJg87n3QrTzZL9KT7Pems,1365
|
|
387
388
|
catalystwan/models/configuration/network_hierarchy/__init__.py,sha256=jGlyKaRRsfrK0gGKoPXqRPmO-myVgfbZVm3FzVkWSts,425
|
|
388
|
-
catalystwan/models/configuration/network_hierarchy/cflowd.py,sha256=
|
|
389
|
+
catalystwan/models/configuration/network_hierarchy/cflowd.py,sha256=AEWc29t-fF3eKJDfTzlBFfBEP5z4RyaGWMAXPgshgOg,5216
|
|
389
390
|
catalystwan/models/configuration/network_hierarchy/node.py,sha256=Ex1OMLl00uU3y4fSSD-xl-t1AJYotYhFRr0KQ826pK8,2792
|
|
390
391
|
catalystwan/models/configuration/policy_group.py,sha256=8A_TsNmjSRVx1BAlYUgQQWkpp_SizDL_ZTS8zUTtHgs,2235
|
|
391
392
|
catalystwan/models/configuration/profile_type.py,sha256=qIlobJmEYQ5qEGZeYJZsVMaXtFbR7RgFr6eH8YyoNAo,157
|
|
@@ -407,7 +408,7 @@ catalystwan/models/policy/definition/control.py,sha256=tjS8SjhbMUIt8LPfA3HVX7t09
|
|
|
407
408
|
catalystwan/models/policy/definition/device_access.py,sha256=SOVwcqtZRN1aKABnGpsxqsSArc_hK_Lpslsh6EuzH_o,4219
|
|
408
409
|
catalystwan/models/policy/definition/device_access_ipv6.py,sha256=AGX8Ax4UNXs7nOjd2DeB1r12QZoDPszUgFI3UUEdiZ8,4303
|
|
409
410
|
catalystwan/models/policy/definition/dial_peer.py,sha256=GRKlK-vY1A1i6sB5cNKzRim8970d16ba16707OefD2M,2190
|
|
410
|
-
catalystwan/models/policy/definition/dns_security.py,sha256=
|
|
411
|
+
catalystwan/models/policy/definition/dns_security.py,sha256=UHx1k4e_eTHu3ytPaP0Kr2C5H7Ls_D3xinTbz8QPo_g,4632
|
|
411
412
|
catalystwan/models/policy/definition/fxo_port.py,sha256=_6que7pcvvIELqj6Vfm4B7a2DxXRdLB2lP2mvRkeSmE,2461
|
|
412
413
|
catalystwan/models/policy/definition/fxs_did_port.py,sha256=CVEWHAT_17EAOhwyjlFdZf15sHFNlZthuQFmG2wvoO8,2214
|
|
413
414
|
catalystwan/models/policy/definition/fxs_port.py,sha256=L7Ot4ZupJdaK9IJQNYVlgiqk8I_WqGuGVBcArEBx7ms,2045
|
|
@@ -630,7 +631,7 @@ catalystwan/version.py,sha256=X5yIMPIrWPbdoF9eJfwxfjcvWr7JMfWQF98hQhlGB5I,3032
|
|
|
630
631
|
catalystwan/vmanage_auth.py,sha256=UZ57lTihsLsXw4AdU7Vn8XuY1jo3732Vc9WuFoHSiiQ,10780
|
|
631
632
|
catalystwan/workflows/backup_restore_device_templates.py,sha256=BoR2KlRbpCI6RxIWG7j7tucaLpw5w3ESN20dLhsrZFY,19796
|
|
632
633
|
catalystwan/workflows/tenant_migration.py,sha256=4KLbqUwH4gEegE92PCGfRd226eZd_crCUpaYUWoGXDI,9790
|
|
633
|
-
catalystwan-0.41.2.
|
|
634
|
-
catalystwan-0.41.2.
|
|
635
|
-
catalystwan-0.41.2.
|
|
636
|
-
catalystwan-0.41.2.
|
|
634
|
+
catalystwan-0.41.2.dev5.dist-info/LICENSE,sha256=97ROi91Vxrj_Jio2v8FI9E8-y6x2uYdQRaFlrEbVjkc,11375
|
|
635
|
+
catalystwan-0.41.2.dev5.dist-info/METADATA,sha256=kTQoN0EBu5YwwcnrgBQPmE-rwcm54WI2UVMkhqFTzoQ,21275
|
|
636
|
+
catalystwan-0.41.2.dev5.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
637
|
+
catalystwan-0.41.2.dev5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|