brynq-sdk-brynq 4.0.7__tar.gz → 4.0.9__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.

Files changed (28) hide show
  1. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/PKG-INFO +1 -1
  2. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq/scenarios.py +6 -1
  3. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq/schemas/scenarios.py +49 -34
  4. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq.egg-info/PKG-INFO +1 -1
  5. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/setup.py +1 -1
  6. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq/__init__.py +0 -0
  7. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq/brynq.py +0 -0
  8. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq/credentials.py +0 -0
  9. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq/customers.py +0 -0
  10. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq/interfaces.py +0 -0
  11. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq/mappings.py +0 -0
  12. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq/organization_chart.py +0 -0
  13. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq/roles.py +0 -0
  14. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq/schemas/__init__.py +0 -0
  15. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq/schemas/credentials.py +0 -0
  16. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq/schemas/customers.py +0 -0
  17. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq/schemas/interfaces.py +0 -0
  18. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq/schemas/organization_chart.py +0 -0
  19. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq/schemas/roles.py +0 -0
  20. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq/schemas/users.py +0 -0
  21. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq/source_systems.py +0 -0
  22. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq/users.py +0 -0
  23. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq.egg-info/SOURCES.txt +0 -0
  24. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq.egg-info/dependency_links.txt +0 -0
  25. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq.egg-info/not-zip-safe +0 -0
  26. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq.egg-info/requires.txt +0 -0
  27. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/brynq_sdk_brynq.egg-info/top_level.txt +0 -0
  28. {brynq_sdk_brynq-4.0.7 → brynq_sdk_brynq-4.0.9}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.0
2
2
  Name: brynq_sdk_brynq
3
- Version: 4.0.7
3
+ Version: 4.0.9
4
4
  Summary: BrynQ SDK for the BrynQ.com platform
5
5
  Home-page: UNKNOWN
6
6
  Author: BrynQ
@@ -80,6 +80,8 @@ from brynq_sdk_functions import Functions
80
80
 
81
81
  from .schemas.scenarios import FieldProperties, ParsedScenario, Scenario
82
82
 
83
+ # TOOD: Value mapping return string None if empty, should be a real None
84
+ # TODO: employee_id, id and person_id are always kept when renaming fields, but thats only relevant for HiBob.
83
85
 
84
86
  class Scenarios():
85
87
  """
@@ -274,7 +276,7 @@ class Scenarios():
274
276
  return df, set()
275
277
 
276
278
  source_to_value_mappings = scenario.source_to_value_mappings
277
- alias_to_pythonic = scenario.alias_to_pythonic
279
+ alias_to_pythonic = scenario.alias_to_pythonic or {}
278
280
  handled_source_fields = set()
279
281
 
280
282
  # Process each source field that has value mappings
@@ -288,6 +290,9 @@ class Scenarios():
288
290
  all_fields_exist = True
289
291
  for field_alias in source_field_aliases:
290
292
  pythonic_field = alias_to_pythonic.get(field_alias, field_alias)
293
+ if pythonic_field not in df.columns and field_alias in df.columns:
294
+ # Dataframe already uses pythonic naming; fall back to the alias itself
295
+ pythonic_field = field_alias
291
296
  if pythonic_field not in df.columns or pythonic_field is None:
292
297
  warnings.warn(f"Source field {field_alias.strip()} not found in dataframe.")
293
298
  all_fields_exist = False
@@ -50,14 +50,30 @@ class CustomSourceTarget(BaseModel):
50
50
  populate_by_name = True
51
51
 
52
52
 
53
+ class LibraryFieldDescriptor(BaseModel):
54
+ """Rich metadata describing a library field target."""
55
+ id: Optional[int] = None
56
+ uuid: Optional[str] = None
57
+ required: Optional[bool] = None
58
+ field: Optional[str] = None
59
+ field_label: Optional[Dict[str, str]] = Field(default=None, alias="fieldLabel")
60
+ app_id: Optional[int] = Field(default=None, alias="appId")
61
+ category: Optional[Dict[str, Any]] = None
62
+
63
+ class Config:
64
+ frozen = True
65
+ strict = True
66
+ populate_by_name = True
67
+
68
+
53
69
  class LibrarySourceTarget(BaseModel):
54
70
  type: Literal["LIBRARY"] = Field(
55
71
  "LIBRARY",
56
72
  description="Discriminator—fixed value for library look-ups"
57
73
  )
58
- data: List[str] = Field(
74
+ data: List[Union[str, LibraryFieldDescriptor]] = Field(
59
75
  ...,
60
- description="List of library field identifiers"
76
+ description="List of library field identifiers or metadata objects"
61
77
  )
62
78
 
63
79
  class Config:
@@ -128,8 +144,9 @@ class ScenarioDetail(BaseModel):
128
144
 
129
145
  source: SourceTarget = Field(..., description="Source definition")
130
146
  target: SourceTarget = Field(..., description="Target definition")
131
- mapping: ScenarioMappingConfiguration = Field(
132
- ..., description="Mapping/value-translation configuration"
147
+ mapping: Optional[ScenarioMappingConfiguration] = Field(
148
+ default=None,
149
+ description="Mapping/value-translation configuration (may be absent)"
133
150
  )
134
151
 
135
152
  class Config:
@@ -266,45 +283,43 @@ class ParsedScenario(BaseModel):
266
283
  props: Dict[str, FieldProperties] = {}
267
284
  source_to_value_maps: Dict[str, List[ScenarioMappingConfiguration]] = defaultdict(list)
268
285
 
269
- def _extract_name(path: dict, data_type: str = "LIBRARY") -> Optional[str]:
270
- """Extracts a name from a path object based on its data type."""
271
- # Process dictionary-based paths.
272
- if isinstance(path, dict):
273
- if data_type == "CUSTOM":
274
- return path.get("technical_name")
275
- if data_type == "LIBRARY":
276
- return path.get("data")
277
- else:
278
- return None
279
- # For data_type == "FIXED" or any other unhandled type, implicitly return None.
280
- elif isinstance(path, str): #string-based paths
281
- if data_type != "FIXED":
282
- return path.split("-")[-1]
283
- else:
284
- return None
285
- else:
286
- return None
286
+ def _extract_names_from_branch(branch: SourceTarget) -> Set[str]:
287
+ """Normalise source/target branch data into canonical field names."""
288
+ if isinstance(branch, CustomSourceTarget):
289
+ names = {item.technical_name for item in branch.data if item.technical_name}
290
+ if names:
291
+ return names
292
+ return {item.uuid for item in branch.data if getattr(item, "uuid", None)}
293
+ if isinstance(branch, LibrarySourceTarget):
294
+ names: Set[str] = set()
295
+ for entry in branch.data:
296
+ if isinstance(entry, str):
297
+ names.add(entry)
298
+ else:
299
+ if entry.field:
300
+ names.add(entry.field)
301
+ elif entry.uuid:
302
+ names.add(entry.uuid)
303
+ return names
304
+ if isinstance(branch, FixedSourceTarget):
305
+ return set()
306
+ return set()
287
307
 
288
308
  for detail in details:
289
- source_data = detail.get("source", {}).get("data", [])
290
- source_type = detail.get("source", {}).get("type", "LIBRARY")
291
- target_data = detail.get("target", {}).get("data", [])
292
- target_type = detail.get("target", {}).get("type", "LIBRARY")
309
+ detail_model = ScenarioDetail.model_validate(detail)
293
310
 
294
- source_names = {name for p in source_data for name in [ _extract_name(p, source_type) ] if name is not None}
295
- target_names = {name for p in target_data for name in [ _extract_name(p, target_type) ] if name is not None}
311
+ source_names = _extract_names_from_branch(detail_model.source)
312
+ target_names = _extract_names_from_branch(detail_model.target)
296
313
 
297
314
  for s_name in source_names:
298
315
  src_map[s_name].update(target_names)
299
316
  for t_name in target_names:
300
317
  tgt_map[t_name].update(source_names)
301
318
 
302
- mapping_config_data = detail.get("mapping")
303
- if mapping_config_data:
304
- mapping_config = ScenarioMappingConfiguration.model_validate(mapping_config_data)
305
- if mapping_config.values:
306
- key = '|'.join(source_names)
307
- source_to_value_maps[key].append(mapping_config)
319
+ mapping_config = detail_model.mapping
320
+ if mapping_config and mapping_config.values:
321
+ key = '|'.join(sorted(source_names)) if source_names else detail_model.id
322
+ source_to_value_maps[key].append(mapping_config)
308
323
 
309
324
  base_props = FieldProperties.model_validate(detail)
310
325
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.0
2
2
  Name: brynq-sdk-brynq
3
- Version: 4.0.7
3
+ Version: 4.0.9
4
4
  Summary: BrynQ SDK for the BrynQ.com platform
5
5
  Home-page: UNKNOWN
6
6
  Author: BrynQ
@@ -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.7',
5
+ version='4.0.9',
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',