brynq-sdk-brynq 4.0.10__tar.gz → 4.1.0__tar.gz
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.
Potentially problematic release.
This version of brynq-sdk-brynq might be problematic. Click here for more details.
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/PKG-INFO +1 -1
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq/schemas/scenarios.py +52 -3
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq.egg-info/PKG-INFO +1 -1
- brynq_sdk_brynq-4.1.0/brynq_sdk_brynq.egg-info/requires.txt +2 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/setup.py +3 -2
- brynq_sdk_brynq-4.0.10/brynq_sdk_brynq.egg-info/requires.txt +0 -1
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq/__init__.py +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq/brynq.py +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq/credentials.py +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq/customers.py +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq/interfaces.py +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq/mappings.py +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq/organization_chart.py +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq/roles.py +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq/scenarios.py +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq/schemas/__init__.py +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq/schemas/credentials.py +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq/schemas/customers.py +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq/schemas/interfaces.py +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq/schemas/organization_chart.py +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq/schemas/roles.py +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq/schemas/users.py +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq/source_systems.py +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq/users.py +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq.egg-info/SOURCES.txt +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq.egg-info/dependency_links.txt +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq.egg-info/not-zip-safe +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq.egg-info/top_level.txt +0 -0
- {brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/setup.cfg +0 -0
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import re
|
|
1
2
|
from collections import defaultdict
|
|
2
3
|
from datetime import date
|
|
3
4
|
from typing import Any, Dict, List, Literal, Optional, Set, Tuple, Type, Union
|
|
4
5
|
|
|
6
|
+
import pandera as pa
|
|
7
|
+
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
5
8
|
from pydantic import BaseModel, ConfigDict, Field
|
|
9
|
+
from pandera.typing import Series, String # type: ignore[attr-defined]
|
|
6
10
|
from typing_extensions import Annotated
|
|
7
11
|
|
|
8
12
|
|
|
@@ -186,8 +190,8 @@ class ParsedScenario(BaseModel):
|
|
|
186
190
|
all_target_fields: Set[str]
|
|
187
191
|
unique_fields: List[str]
|
|
188
192
|
required_fields: List[str]
|
|
189
|
-
|
|
190
|
-
|
|
193
|
+
custom_source_fields: List[str]
|
|
194
|
+
custom_fields_model: Optional[type] = None
|
|
191
195
|
alias_to_pythonic: Optional[Dict[str, str]] = None
|
|
192
196
|
pythonic_to_alias: Optional[Dict[str, str]] = None
|
|
193
197
|
all_pythonic_source_fields: Optional[List[str]] = None
|
|
@@ -336,6 +340,11 @@ class ParsedScenario(BaseModel):
|
|
|
336
340
|
all_source_fields = set(src_map.keys())
|
|
337
341
|
unique_fields = [fid for fid, props in props.items() if props.unique]
|
|
338
342
|
required_fields = [fid for fid, props in props.items() if props.required]
|
|
343
|
+
custom_source_fields = list(dict.fromkeys(
|
|
344
|
+
fid for fid, field_props in props.items()
|
|
345
|
+
if field_props.system_type == "source" and
|
|
346
|
+
field_props.source.get('type') == 'CUSTOM'
|
|
347
|
+
))
|
|
339
348
|
source_to_target_map = {k: sorted(v) for k, v in src_map.items()}
|
|
340
349
|
target_to_source_map = {k: sorted(v) for k, v in tgt_map.items()}
|
|
341
350
|
all_target_fields = set(tgt_map.keys())
|
|
@@ -380,6 +389,8 @@ class ParsedScenario(BaseModel):
|
|
|
380
389
|
|
|
381
390
|
|
|
382
391
|
# --- 3. Construct the final, frozen instance in a single call ---
|
|
392
|
+
custom_fields_model = cls._build_custom_field_model(custom_source_fields) if custom_source_fields else None
|
|
393
|
+
|
|
383
394
|
instance = cls(
|
|
384
395
|
name=scenario.get("name", "Unnamed"),
|
|
385
396
|
id=scenario.get("id", ""),
|
|
@@ -389,6 +400,7 @@ class ParsedScenario(BaseModel):
|
|
|
389
400
|
field_properties=props,
|
|
390
401
|
unique_fields=unique_fields,
|
|
391
402
|
required_fields=required_fields,
|
|
403
|
+
custom_source_fields=custom_source_fields,
|
|
392
404
|
all_source_fields=all_source_fields,
|
|
393
405
|
all_pythonic_source_fields=all_pythonic_source_fields,
|
|
394
406
|
all_target_fields=all_target_fields,
|
|
@@ -396,7 +408,8 @@ class ParsedScenario(BaseModel):
|
|
|
396
408
|
alias_to_pythonic=alias_to_pythonic,
|
|
397
409
|
source_pythonic_to_target=source_pythonic_to_target,
|
|
398
410
|
target_to_source_pythonic=target_to_source_pythonic,
|
|
399
|
-
pythonic_to_alias={v: k for k, v in alias_to_pythonic.items()} if alias_to_pythonic else None
|
|
411
|
+
pythonic_to_alias={v: k for k, v in alias_to_pythonic.items()} if alias_to_pythonic else None,
|
|
412
|
+
custom_fields_model=custom_fields_model
|
|
400
413
|
)
|
|
401
414
|
return instance
|
|
402
415
|
|
|
@@ -446,6 +459,42 @@ class ParsedScenario(BaseModel):
|
|
|
446
459
|
source_alias_to_pythonic[alias] = pythonic_field_name
|
|
447
460
|
|
|
448
461
|
return source_alias_to_pythonic
|
|
462
|
+
|
|
463
|
+
@staticmethod
|
|
464
|
+
def _build_custom_field_model(custom_fields: List[str]) -> Optional[type]:
|
|
465
|
+
"""
|
|
466
|
+
Create a Pandera schema model for custom fields configured in a scenario.
|
|
467
|
+
|
|
468
|
+
Args:
|
|
469
|
+
custom_fields: Source field names from the BrynQ scenario.
|
|
470
|
+
|
|
471
|
+
Returns:
|
|
472
|
+
A dynamically generated BrynQ Pandera model class or None when no fields can be mapped.
|
|
473
|
+
"""
|
|
474
|
+
annotations: Dict[str, Any] = {}
|
|
475
|
+
model_fields: Dict[str, Any] = {}
|
|
476
|
+
|
|
477
|
+
for field in custom_fields:
|
|
478
|
+
alias = str(field)
|
|
479
|
+
|
|
480
|
+
# Convert to valid pythonic identifier
|
|
481
|
+
if alias.isidentifier():
|
|
482
|
+
pythonic_name = alias
|
|
483
|
+
else:
|
|
484
|
+
# Sanitize: replace non-word chars with underscore, handle digits
|
|
485
|
+
pythonic_name = re.sub(r"\W|^(?=\d)", "_", alias)
|
|
486
|
+
pythonic_name = re.sub(r"_+", "_", pythonic_name).strip("_").lower()
|
|
487
|
+
if not pythonic_name:
|
|
488
|
+
pythonic_name = "field"
|
|
489
|
+
if pythonic_name[0].isdigit():
|
|
490
|
+
pythonic_name = f"field_{pythonic_name}"
|
|
491
|
+
|
|
492
|
+
annotations[pythonic_name] = Optional[Series[String]]
|
|
493
|
+
model_fields[pythonic_name] = pa.Field(coerce=True, nullable=True, alias=str(alias))
|
|
494
|
+
|
|
495
|
+
model_fields["__annotations__"] = annotations
|
|
496
|
+
model = type("CustomFieldModel", (BrynQPanderaDataFrameModel,), model_fields)
|
|
497
|
+
return model
|
|
449
498
|
class Config:
|
|
450
499
|
frozen = True
|
|
451
500
|
strict = True
|
|
@@ -2,7 +2,7 @@ from setuptools import find_namespace_packages, setup
|
|
|
2
2
|
|
|
3
3
|
setup(
|
|
4
4
|
name='brynq_sdk_brynq',
|
|
5
|
-
version='4.0
|
|
5
|
+
version='4.1.0',
|
|
6
6
|
description='BrynQ SDK for the BrynQ.com platform',
|
|
7
7
|
long_description='BrynQ SDK for the BrynQ.com platform',
|
|
8
8
|
author='BrynQ',
|
|
@@ -10,7 +10,8 @@ setup(
|
|
|
10
10
|
packages=find_namespace_packages(include=['brynq_sdk*']),
|
|
11
11
|
license='BrynQ License',
|
|
12
12
|
install_requires=[
|
|
13
|
-
'requests>=2,<=3'
|
|
13
|
+
'requests>=2,<=3',
|
|
14
|
+
'pandera>=0.26.0,<=1.0.0'
|
|
14
15
|
],
|
|
15
16
|
zip_safe=False,
|
|
16
17
|
)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
requests<=3,>=2
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq/schemas/organization_chart.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{brynq_sdk_brynq-4.0.10 → brynq_sdk_brynq-4.1.0}/brynq_sdk_brynq.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|