Skip to content

Commit 27a42ed

Browse files
author
bosd
committed
[FIX]:m2m_value_list m2m_id_list
1 parent ce6b083 commit 27a42ed

File tree

2 files changed

+49
-30
lines changed

2 files changed

+49
-30
lines changed

src/odoo_data_flow/lib/mapper.py

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import base64
1111
import inspect
1212
import os
13-
from typing import Any, Callable, cast
13+
from typing import Any, Callable, Optional, cast
1414

1515
import requests # type: ignore[import-untyped]
1616

@@ -53,9 +53,7 @@
5353
LineDict = dict[str, Any]
5454
StateDict = dict[str, Any]
5555
MapperFunc = Callable[[LineDict, StateDict], Any]
56-
57-
58-
# ... (rest of the file remains the same as your version) ...
56+
ListMapperFunc = Callable[[LineDict, StateDict], list[str]]
5957

6058

6159
def _get_field_value(line: LineDict, field: str, default: Any = "") -> Any:
@@ -402,7 +400,9 @@ def m2o_att_fun(line: LineDict, state: StateDict) -> dict[str, str]:
402400
return m2o_att_fun
403401

404402

405-
def m2m_id_list(prefix: str, *fields: Any, sep: str = ",") -> MapperFunc:
403+
def m2m_id_list(
404+
prefix: str, *fields: Any, sep: str = ",", const_values: Optional[list[str]] = None
405+
) -> ListMapperFunc:
406406
"""Returns a mapper for creating a list of M2M external IDs.
407407
408408
This is primarily used when creating the related records for a M2M field,
@@ -412,44 +412,63 @@ def m2m_id_list(prefix: str, *fields: Any, sep: str = ",") -> MapperFunc:
412412
prefix: The XML ID prefix to apply to each value.
413413
*fields: One or more source fields to read values from.
414414
sep: The separator to use when splitting values.
415+
const_values: A list of constant XML IDs to always include.
415416
416417
Returns:
417-
A mapper function that returns a comma-separated string of external IDs.
418+
A mapper function that returns a list of individual external IDs.
418419
"""
419-
concat_m = concat("", *fields)
420+
if const_values is None:
421+
const_values = []
420422

421-
def m2m_id_list_fun(line: LineDict, state: StateDict) -> str:
422-
value = concat_m(line, state)
423-
if not value:
424-
return ""
425-
values = [v.strip() for v in value.split(sep)]
426-
return ",".join(to_m2o(prefix, v) for v in values if v)
423+
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]
427430

428431
return m2m_id_list_fun
429432

430433

431-
def m2m_value_list(*fields: Any, sep: str = ",") -> MapperFunc:
432-
"""Returns a mapper that creates a Python list of unique values.
434+
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."""
438+
if const_values is None:
439+
const_values = []
433440

434-
This is used in conjunction with `m2m_id_list` when creating related
435-
records for a M2M field.
441+
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]
436448

437-
Args:
438-
*fields: One or more source fields to read values from.
439-
sep: The separator to use when splitting values.
449+
return m2m_value_list_fun
440450

441-
Returns:
442-
A mapper function that returns a list of strings.
443-
"""
451+
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] = []
444457
concat_m = concat("", *fields)
445458

446-
def m2m_value_list_fun(line: LineDict, state: StateDict) -> list[str]:
447-
value = concat_m(line, state)
448-
if not value:
449-
return []
450-
return [v.strip() for v in value.split(sep) if v.strip()]
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+
)
451465

452-
return m2m_value_list_fun
466+
# Extend with constant values
467+
all_raw_values.extend([v.strip() for v in const_values if v.strip()])
468+
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
453472

454473

455474
def map_val(

tests/test_mapper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ def test_m2m_map_with_empty_result() -> None:
221221
def test_m2m_id_list_empty() -> None:
222222
"""Tests that m2m_id_list returns an empty string for empty input."""
223223
mapper_func = mapper.m2m_id_list("prefix", "empty_col")
224-
assert mapper_func(LINE_SIMPLE, {}) == ""
224+
assert mapper_func(LINE_SIMPLE, {}) == []
225225

226226

227227
def test_m2m_value_list_empty() -> None:

0 commit comments

Comments
 (0)