def on_xml_record(self, xml_record): record = xml_record.record_node record_id = record.get("id") if ( not record_id or xml_record.noupdate or xml_record.path not in xml_record.addon.data_files ): return addon_name, _ = split_external_id(record_id) if addon_name and addon_name != xml_record.addon.name: return model = record.attrib["model"] if model in MODELS: yield Issue( "expected_noupdate_flag", f'`{model}` model records should be declared in a `noupdate="1"` ' f"XML data element to allow user modifications", xml_record.addon.manifest_path, [ Location( xml_record.path, [record.sourceline, record.getparent().sourceline], ) ], categories=["correctness"], )
def _ref_or_def(addon, filename, position, external_id, model) -> typing.Union[ExternalID, ExternalIDReference]: addon_name, record_id = split_external_id(external_id) cls_ = ExternalIDReference if not addon_name or addon_name == addon.name: cls_ = ExternalID return cls_(addon, addon_name, record_id, model, Location(filename, [position]))
def on_xml_record(self, xml_record): record = xml_record.record_node if record.attrib["model"] != "ir.ui.view": return view_xml_id = record.get("id") # Skip inherited views. inherit_id = record.xpath("./field[@name='inherit_id']") if inherit_id and inherit_id[0].attrib.get("ref"): return # Skip `arch` override in an extending addon. if view_xml_id: addon_name, _ = split_external_id(view_xml_id) if addon_name and addon_name != xml_record.addon.name: return arch = get_view_arch(record) if arch is None: _LOG.warning( "`ir.ui.view` record has no `arch` field " "in file: %s at line %d", xml_record.path, record.sourceline, ) return children = [ c for c in arch.getchildren() if c.tag is not etree.Comment ] if len(children) != 1: _LOG.warning( "Unexpected number of children in `ir.ui.view` " "`arch` in file: %s at line %d", xml_record.path, arch.sourceline, ) return fields = collections.defaultdict(list) for path, line_no in find_fields(arch, ()): fields[path].append(line_no) for path, line_nos in fields.items(): if len(line_nos) > 1: field_name = path.split("/")[-1] yield Issue( "duplicate_view_field", f'"{view_xml_id}" `ir.ui.view` has duplicate field ' f'"{field_name}"' if view_xml_id else (f'`ir.ui.view` has duplicate field "{field_name}"'), xml_record.addon.manifest_path, [ Location(xml_record.path, [line_no]) for line_no in line_nos ], categories=["correctness"], )
def on_csv_row(self, csv_row): if csv_row.path.name.lower() != "ir.model.access.csv": return external_id = csv_row.row.get("model_id:id") or csv_row.row.get( "model_id/id") if external_id: _, record_id = split_external_id(external_id) self._access_rules.add(record_id) yield from ()
def on_xml_record(self, xml_record): if xml_record.record_node.attrib["model"] != "ir.model.access": return for model_el in xml_record.record_node.xpath( "./field[@name='model_id']"): external_id = model_el.attrib.get("ref") if external_id: _, record_id = split_external_id(external_id) self._access_rules.add(record_id) yield from ()
def _ref(addon, filename, position, external_id, model, unknown_addon=False) -> ExternalIDReference: addon_name, record_id = split_external_id(external_id) return ExternalIDReference( addon, UNKNOWN if unknown_addon else addon_name, record_id, model, Location(filename, [position]), )
def _ref_or_def(addon, filename, position: typing.Union[int, Position], external_id, model) -> typing.Union[ExternalID, ExternalIDReference]: addon_name, record_id = split_external_id(external_id) cls_ = ExternalIDReference if not addon_name or addon_name == addon.name: cls_ = ExternalID return cls_( addon, addon_name, record_id, model, Location( filename, Position(position) if isinstance(position, int) else position), )
def _ref( addon, filename, position: typing.Union[int, Position], external_id, model, unknown_addon=False, ) -> ExternalIDReference: addon_name, record_id = split_external_id(external_id) return ExternalIDReference( addon, UNKNOWN if unknown_addon else addon_name, record_id, model, Location( filename, Position(position) if isinstance(position, int) else position), )
def on_csv_row(self, csv_row): model = csv_row.path.stem addon, path, row = csv_row.addon, csv_row.path, csv_row.row yield ExternalIDReference(addon, UNKNOWN, _model_record_id(model), "ir.model", Location(path)) if path not in self._csv_external_id_fields: for field_name in row: if (field_name.split(":")[-1] == "id" or field_name.split("/")[-1] == "id"): self._csv_external_id_fields[path].add(field_name) # Add references to fields from the CSV file header. field_external_id = _field_record_id( model, (field_name[:-3] if field_name.endswith( (":id", "/id")) else field_name), ) yield ExternalIDReference( addon, UNKNOWN, field_external_id, "ir.model.fields", Location(path, [1]), ) for field_name in self._csv_external_id_fields[path]: # TODO: Add support for KNOWN_FIELD_MODELS. external_id = csv_row.row[field_name] if not external_id: continue addon_name, record_id = split_external_id(external_id) cls_ = ExternalID if field_name == "id" else ExternalIDReference yield cls_( csv_row.addon, addon_name, record_id, model if field_name == "id" else UNKNOWN, Location(csv_row.path, [csv_row.line_no]), )