|
58 | 58 |
|
59 | 59 | def _get_field_value(line: LineDict, field: str, default: Any = "") -> Any: |
60 | 60 | """Safely retrieves a value from the current data row.""" |
61 | | - return line.get(field, default) or default |
| 61 | + value = line.get(field, default) |
| 62 | + log.debug( |
| 63 | + f"Getting field '{field}': value='{value}' from line keys: {list(line.keys())}" |
| 64 | + ) |
| 65 | + return value |
62 | 66 |
|
63 | 67 |
|
64 | 68 | def _str_to_mapper(field: Any) -> MapperFunc: |
@@ -401,74 +405,88 @@ def m2o_att_fun(line: LineDict, state: StateDict) -> dict[str, str]: |
401 | 405 |
|
402 | 406 |
|
403 | 407 | def m2m_id_list( |
404 | | - prefix: str, *fields: Any, sep: str = ",", const_values: Optional[list[str]] = None |
| 408 | + prefix: str, *args: Any, sep: str = ",", const_values: Optional[list[str]] = None |
405 | 409 | ) -> ListMapperFunc: |
406 | 410 | """Returns a mapper for creating a list of M2M external IDs. |
407 | 411 |
|
408 | | - This is primarily used when creating the related records for a M2M field, |
409 | | - such as creating all unique `res.partner.category` records. |
410 | | -
|
411 | | - Args: |
412 | | - prefix: The XML ID prefix to apply to each value. |
413 | | - *fields: One or more source fields to read values from. |
414 | | - sep: The separator to use when splitting values. |
415 | | - const_values: A list of constant XML IDs to always include. |
416 | | -
|
417 | | - Returns: |
418 | | - A mapper function that returns a list of individual external IDs. |
| 412 | + This function can take either raw field names (str) or other mapper functions |
| 413 | + as its arguments. It processes each argument to produce an individual ID. |
| 414 | + If a field's value contains the separator, it will be split. |
419 | 415 | """ |
420 | 416 | if const_values is None: |
421 | 417 | const_values = [] |
422 | 418 |
|
423 | 419 | def m2m_id_list_fun(line: LineDict, state: StateDict) -> list[str]: |
424 | | - # Call a shared internal helper to get unique, ordered raw values |
425 | | - raw_values = _get_unique_raw_values_from_fields( |
426 | | - line, state, fields, sep, const_values |
427 | | - ) |
428 | | - # Apply prefixing to each raw value |
429 | | - return [to_m2o(prefix, v) for v in raw_values if v] |
| 420 | + all_ids: list[str] = [] |
| 421 | + for arg in args: |
| 422 | + # Determine if arg is a field name or an already-created mapper |
| 423 | + if isinstance(arg, str): |
| 424 | + raw_value = _get_field_value(line, arg) |
| 425 | + elif callable(arg): # Assume it's a mapper function |
| 426 | + try: |
| 427 | + raw_value = arg(line, state) |
| 428 | + except ( |
| 429 | + TypeError |
| 430 | + ): # Fallback for mappers not taking 'state' (less common now) |
| 431 | + raw_value = arg(line) |
| 432 | + else: |
| 433 | + raw_value = "" # Or raise error, depending on desired strictness |
| 434 | + |
| 435 | + if raw_value and isinstance(raw_value, str): |
| 436 | + # Always split values by separator if they contain it. |
| 437 | + # This ensures "Color_Black" and "Gender_Woman" are separate. |
| 438 | + parts = [v.strip() for v in raw_value.split(sep) if v.strip()] |
| 439 | + all_ids.extend([to_m2o(prefix, p) for p in parts]) |
| 440 | + elif raw_value: # If not string but truthy (e.g., a number from mapper.num) |
| 441 | + all_ids.append(to_m2o(prefix, str(raw_value))) |
| 442 | + |
| 443 | + # Add constant values, applying prefix |
| 444 | + all_ids.extend([to_m2o(prefix, cv) for cv in const_values if cv]) |
| 445 | + |
| 446 | + # Ensure uniqueness and preserve order |
| 447 | + unique_ids = list(dict.fromkeys(all_ids)) |
| 448 | + return unique_ids |
430 | 449 |
|
431 | 450 | return m2m_id_list_fun |
432 | 451 |
|
433 | 452 |
|
434 | 453 | def m2m_value_list( |
435 | | - *fields: Any, sep: str = ",", const_values: Optional[list[str]] = None |
436 | | -) -> ListMapperFunc: # Changed to ListMapperFunc |
437 | | - """Returns a mapper that creates a Python list of unique values.""" |
| 454 | + *args: Any, sep: str = ",", const_values: Optional[list[str]] = None |
| 455 | +) -> ListMapperFunc: |
| 456 | + """Returns a mapper that creates a Python list of unique raw values. |
| 457 | +
|
| 458 | + It processes each argument to produce an individual raw value. |
| 459 | + If a field's value contains the separator, it will be split. |
| 460 | + """ |
438 | 461 | if const_values is None: |
439 | 462 | const_values = [] |
440 | 463 |
|
441 | 464 | def m2m_value_list_fun(line: LineDict, state: StateDict) -> list[str]: |
442 | | - # Call the same shared internal helper to get unique, ordered raw values |
443 | | - raw_values = _get_unique_raw_values_from_fields( |
444 | | - line, state, fields, sep, const_values |
445 | | - ) |
446 | | - # Return the raw values directly |
447 | | - return [v for v in raw_values if v] |
448 | | - |
449 | | - return m2m_value_list_fun |
450 | | - |
| 465 | + """Returns a mapper that creates a Python list of unique values.""" |
| 466 | + all_values: list[str] = [] |
| 467 | + for arg in args: |
| 468 | + if isinstance(arg, str): |
| 469 | + raw_value = _get_field_value(line, arg) |
| 470 | + elif callable(arg): |
| 471 | + try: |
| 472 | + raw_value = arg(line, state) |
| 473 | + except TypeError: |
| 474 | + raw_value = arg(line) |
| 475 | + else: |
| 476 | + raw_value = "" |
451 | 477 |
|
452 | | -def _get_unique_raw_values_from_fields( |
453 | | - line: LineDict, state: StateDict, fields: Any, sep: str, const_values: list[str] |
454 | | -) -> list[str]: |
455 | | - """Helper to get unique, ordered raw values from fields and const_values.""" |
456 | | - all_raw_values: list[str] = [] |
457 | | - concat_m = concat("", *fields) |
| 478 | + if raw_value and isinstance(raw_value, str): |
| 479 | + parts = [v.strip() for v in raw_value.split(sep) if v.strip()] |
| 480 | + all_values.extend(parts) |
| 481 | + elif raw_value: # If not string but truthy |
| 482 | + all_values.append(str(raw_value)) |
458 | 483 |
|
459 | | - value_from_fields = concat_m(line, state) |
460 | | - if value_from_fields: |
461 | | - # Split and extend with values from fields |
462 | | - all_raw_values.extend( |
463 | | - [v.strip() for v in value_from_fields.split(sep) if v.strip()] |
464 | | - ) |
| 484 | + all_values.extend([v.strip() for v in const_values if v.strip()]) |
465 | 485 |
|
466 | | - # Extend with constant values |
467 | | - all_raw_values.extend([v.strip() for v in const_values if v.strip()]) |
| 486 | + unique_values = list(dict.fromkeys(all_values)) |
| 487 | + return unique_values |
468 | 488 |
|
469 | | - # Preserve order and ensure uniqueness using dict.fromkeys (Python 3.7+) |
470 | | - unique_ordered_values = list(dict.fromkeys(all_raw_values)) |
471 | | - return unique_ordered_values |
| 489 | + return m2m_value_list_fun |
472 | 490 |
|
473 | 491 |
|
474 | 492 | def map_val( |
|
0 commit comments