예제 #1
0
파일: noupdate.py 프로젝트: srekal/odd
    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"],
            )
예제 #2
0
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]))
예제 #3
0
    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"],
                )
예제 #4
0
 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 ()
예제 #5
0
 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 ()
예제 #6
0
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]),
    )
예제 #7
0
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),
    )
예제 #8
0
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),
    )
예제 #9
0
    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]),
            )