Mapper¶
Mappers¶
Mappers are the ConnectorUnit classes responsible to transform external records into OpenERP records and conversely.
-
class
connector.unit.mapper.
ExportMapChild
(connector_env)[source]¶ Bases:
connector.unit.mapper.MapChild
MapChild
for the Exports
-
class
connector.unit.mapper.
ExportMapper
(connector_env)[source]¶ Bases:
connector.unit.mapper.Mapper
Mapper
for exports.Transform a record from OpenERP to a backend record
-
class
connector.unit.mapper.
ImportMapChild
(connector_env)[source]¶ Bases:
connector.unit.mapper.MapChild
MapChild
for the Imports-
format_items
(items_values)[source]¶ Format the values of the items mapped from the child Mappers.
It can be overridden for instance to add the OpenERP relationships commands
(6, 0, [IDs])
, …As instance, it can be modified to handle update of existing items: check if an ‘id’ has been defined by
get_item_values()
then use the(1, ID, {values}
) commandParameters: items_values (list) – list of values for the items to create
-
-
class
connector.unit.mapper.
ImportMapper
(connector_env)[source]¶ Bases:
connector.unit.mapper.Mapper
Mapper
for imports.Transform a record from a backend to an OpenERP record
-
class
connector.unit.mapper.
MapChild
(connector_env)[source]¶ Bases:
connector.connector.ConnectorUnit
MapChild is responsible to convert items.
Items are sub-records of a main record. In this example, the items are the records in
lines
:sales = {'name': 'SO10', 'lines': [{'product_id': 1, 'quantity': 2}, {'product_id': 2, 'quantity': 2}]}
A MapChild is always called from another
Mapper
which provides achildren
configuration.Considering the example above, the “main”
Mapper
would returns something as follows:{'name': 'SO10', 'lines': [(0, 0, {'product_id': 11, 'quantity': 2}), (0, 0, {'product_id': 12, 'quantity': 2})]}
A MapChild is responsible to:
- Find the
Mapper
to convert the items - Possibly filter out some lines (can be done by inheriting
skip_item()
) - Convert the items’ records using the found
Mapper
- Format the output values to the format expected by OpenERP or the
backend (as seen above with
(0, 0, {values})
A MapChild can be extended like any other
ConnectorUnit
. However, it is not mandatory to explicitly create a MapChild for each children mapping, the default one will be used (ImportMapChild
orExportMapChild
).The implementation by default does not take care of the updates: if I import a sales order 2 times, the lines will be duplicated. This is not a problem as long as an importation should only support the creation (typical for sales orders). It can be implemented on a case-by-case basis by inheriting
get_item_values()
andformat_items()
.-
format_items
(items_values)[source]¶ Format the values of the items mapped from the child Mappers.
It can be overridden for instance to add the OpenERP relationships commands
(6, 0, [IDs])
, …As instance, it can be modified to handle update of existing items: check if an ‘id’ has been defined by
get_item_values()
then use the(1, ID, {values}
) commandParameters: items_values (list) – mapped values for the items
-
get_item_values
(map_record, to_attr, options)[source]¶ Get the raw values from the child Mappers for the items.
It can be overridden for instance to:
- Change options
- Use a
Binder
to know if an item already exists to modify an existing item, rather than to add it
Parameters:
-
get_items
(items, parent, to_attr, options)[source]¶ Returns the formatted output values of items from a main record
Parameters: Returns: formatted output values for the item
- Find the
-
class
connector.unit.mapper.
MapOptions
[source]¶ Bases:
dict
Container for the options of mappings.
Options can be accessed using attributes of the instance. When an option is accessed and does not exist, it returns None.
-
class
connector.unit.mapper.
MapRecord
(mapper, source, parent=None)[source]¶ Bases:
object
A record prepared to be converted using a
Mapper
.MapRecord instances are prepared by
Mapper.map_record()
.Usage:
mapper = SomeMapper(env) map_record = mapper.map_record(record) output_values = map_record.values()
See
values()
for more information on the available arguments.-
parent
¶ Parent record if the current record is an item
-
source
¶ Source record to be converted
-
update
(*args, **kwargs)[source]¶ Force values to be applied after a mapping.
Usage:
mapper = SomeMapper(env) map_record = mapper.map_record(record) map_record.update(a=1) output_values = map_record.values() # output_values will at least contain {'a': 1}
The values assigned with
update()
are in any case applied, they have a greater priority than the mapping values.
-
values
(for_create=None, fields=None, **kwargs)[source]¶ Build and returns the mapped values according to the options.
Usage:
mapper = SomeMapper(env) map_record = mapper.map_record(record) output_values = map_record.values()
- Creation of records
When using the option
for_create
, only the mappings decorated with@only_create
will be mapped.output_values = map_record.values(for_create=True)
- Filter on fields
When using the
fields
argument, the mappings will be filtered using either the source key indirect
arguments, either thechanged_by
arguments for the mapping methods.output_values = map_record.values(fields=['name', 'street'])
- Custom options
Arbitrary key and values can be defined in the
kwargs
arguments. They can later be used in the mapping methods usingself.options
.output_values = map_record.values(tax_include=True)
Parameters: - for_create (boolean) – specify if only the mappings for creation
(
@only_create
) should be mapped. - fields (list) – filter on fields
- **kwargs –
custom options, they can later be used in the mapping methods
-
-
class
connector.unit.mapper.
Mapper
(connector_env)[source]¶ Bases:
connector.connector.ConnectorUnit
A Mapper translates an external record to an OpenERP record and conversely. The output of a Mapper is a
dict
.3 types of mappings are supported:
- Direct Mappings
Example:
direct = [('source', 'target')]
Here, the
source
field will be copied in thetarget
field.A modifier can be used in the source item. The modifier will be applied to the source field before being copied in the target field. It should be a closure function respecting this idiom:
def a_function(field): ''' ``field`` is the name of the source field. Naming the arg: ``field`` is required for the conversion''' def modifier(self, record, to_attr): ''' self is the current Mapper, record is the current record to map, to_attr is the target field''' return record[field] return modifier
And used like that:
direct = [ (a_function('source'), 'target'), ]
A more concrete example of modifier:
def convert(field, conv_type): ''' Convert the source field to a defined ``conv_type`` (ex. str) before returning it''' def modifier(self, record, to_attr): value = record[field] if not value: return None return conv_type(value) return modifier
And used like that:
direct = [ (convert('myfield', float), 'target_field'), ]
More examples of modifiers:
- Method Mappings
A mapping method allows to execute arbitrary code and return one or many fields:
@mapping def compute_state(self, record): # compute some state, using the ``record`` or not state = 'pending' return {'state': state}
We can also specify that a mapping methods should be applied only when an object is created, and never applied on further updates:
@only_create @mapping def default_warehouse(self, record): # get default warehouse warehouse_id = ... return {'warehouse_id': warehouse_id}
- Submappings
When a record contains sub-items, like the lines of a sales order, we can convert the children using another Mapper:
children = [('items', 'line_ids', 'model.name')]
It allows to create the sales order and all its lines with the same call to
openerp.models.BaseModel.create()
.When using
children
for items of a record, we need to create aMapper
for the model of the items, and optionally aMapChild
.
Usage of a Mapper:
mapper = Mapper(env) map_record = mapper.map_record(record) values = map_record.values() values = map_record.values(only_create=True) values = map_record.values(fields=['name', 'street'])
-
children
= []¶
-
direct
= []¶
-
finalize
(map_record, values)[source]¶ Called at the end of the mapping.
Can be used to modify the values before returning them, as the
on_change
.Parameters: - map_record (
MapRecord
) – source map_record - values – mapped values
Returns: mapped values
Return type: - map_record (
-
map_methods
¶ Yield all the methods decorated with
@mapping
-
map_record
(record, parent=None)[source]¶ Get a
MapRecord
with record, ready to be converted using the current Mapper.Parameters: - record – record to transform
- parent – optional parent record, for items
-
options
¶ Options can be accessed in the mapping methods with
self.options
.
-
class
connector.unit.mapper.
MappingDefinition
(changed_by, only_create)¶ Bases:
tuple
-
changed_by
¶ Alias for field number 0
-
only_create
¶ Alias for field number 1
-
-
class
connector.unit.mapper.
MetaMapper
(name, bases, attrs)[source]¶ Bases:
connector.connector.MetaConnectorUnit
Metaclass for Mapper
Build a
_map_methods
dict of mappings methods. The keys of the dict are the method names. The values of the dict are a namedtuple containing:
-
connector.unit.mapper.
backend_to_m2o
(field, binding=None)[source]¶ A modifier intended to be used on the
direct
mappings.For a field from a backend which is an ID, search the corresponding binding in OpenERP and returns its ID.
When the field’s relation is not a binding (i.e. it does not point to something like
magento.*
), the binding model needs to be provided in thebinding
keyword argument.Example:
direct = [(backend_to_m2o('country', binding='magento.res.country'), 'country_id'), (backend_to_m2o('country'), 'magento_country_id')]
Parameters: - field – name of the source field in the record
- binding – name of the binding model is the relation is not a binding
-
connector.unit.mapper.
changed_by
(*args)[source]¶ Decorator for the mapping methods (
mapping()
)When fields are modified in OpenERP, we want to export only the modified fields. Using this decorator, we can specify which fields updates should trigger which mapping method.
If
changed_by
is empty, the mapping is always active.As far as possible, this decorator should be used for the exports, thus, when we do an update on only a small number of fields on a record, the size of the output record will be limited to only the fields really having to be exported.
Usage:
@changed_by('input_field') @mapping def any(self, record): return {'output_field': record['input_field']}
Parameters: *args – field names which trigger the mapping when modified
-
connector.unit.mapper.
convert
(field, conv_type)[source]¶ A modifier intended to be used on the
direct
mappings.Convert a field’s value to a given type.
Example:
direct = [(convert('source', str), 'target')]
Parameters: - field – name of the source field in the record
- binding – True if the relation is a binding record
-
connector.unit.mapper.
follow_m2o_relations
(field)[source]¶ A modifier intended to be used on
direct
mappings.‘Follows’ Many2one relations and return the final field value.
- Examples:
Assuming model is
product.product
:- direct = [
- (follow_m2o_relations(‘product_tmpl_id.categ_id.name’), ‘cat’)]
Parameters: field – field “path”, using dots for relations as usual in Odoo
-
connector.unit.mapper.
m2o_to_backend
(field, binding=None)[source]¶ A modifier intended to be used on the
direct
mappings.For a many2one, get the ID on the backend and returns it.
When the field’s relation is not a binding (i.e. it does not point to something like
magento.*
), the binding model needs to be provided in thebinding
keyword argument.Example:
direct = [(m2o_to_backend('country_id', binding='magento.res.country'), 'country'), (m2o_to_backend('magento_country_id'), 'country')]
Parameters: - field – name of the source field in the record
- binding – name of the binding model is the relation is not a binding
-
connector.unit.mapper.
mapping
(func)[source]¶ Declare that a method is a mapping method.
It is then used by the
Mapper
to convert the records.Usage:
@mapping def any(self, record): return {'output_field': record['input_field']}
-
connector.unit.mapper.
none
(field)[source]¶ A modifier intended to be used on the
direct
mappings.Replace the False-ish values by None. It can be used in a pipeline of modifiers when .
Example:
direct = [(none('source'), 'target'), (none(m2o_to_backend('rel_id'), 'rel_id')]
Parameters: - field – name of the source field in the record
- binding – True if the relation is a binding record