Exemple #1
0
def gitsource(thing):
    # type: (sources.Sourceable) -> None
    for source in sources.find_source(thing):
        try:
            fmt = format_source(source)
        except GitSourceError as exc:
            fmt = "{}: {}".format(color.module(source.module),
                                  color.missing(str(exc)))
        print(fmt)
Exemple #2
0
    def grep_(self, *args, **kwargs):
        # type: (object, object) -> None
        """grep through the combined source code of the model.

        See help(odoo_repl.grep) for more information.
        """
        assert self._real is not None
        # TODO: handle multiple classes in single file properly
        argv = grep.build_grep_argv(args, kwargs)
        seen = set()  # type: t.Set[t.Text]
        for src in sources.find_source(self._real):
            if src.fname not in seen:
                seen.add(src.fname)
                argv.append(src.fname)
        subprocess.Popen(argv).wait()
Exemple #3
0
def edit(thing, index=0, bg=None):
    # type: (sources.Sourceable, t.Union[int, t.Text], t.Optional[bool]) -> None
    """Open a model or field definition in an editor."""
    # TODO: editor kwarg and/or argparse flag
    src = sources.find_source(thing)
    if not src:
        raise RuntimeError("Can't find source file!")
    if isinstance(index, int):
        try:
            module, fname, lnum = src[index]
        except IndexError:
            raise RuntimeError("Can't find match #{}".format(index))
    elif isinstance(index, Text):
        for module, fname, lnum in src:
            if module == index:
                break
        else:
            raise RuntimeError(
                "Can't find match for module {!r}".format(index))
    else:
        raise TypeError(index)
    return _edit(fname, lnum=lnum, bg=bg)
Exemple #4
0
def rule_repr(rule):
    # type: (odoo.models.IrRule) -> t.Text
    parts = []
    parts.append(color.record_header(rule))
    parts.append(color.display_name(rule.display_name))
    groups = ", ".join(
        color.record(group.name) + util.xml_id_tag(group)
        for group in rule.groups)
    if not groups:
        parts.append(
            color.green.bold("Everyone") if rule["global"] else color.red.
            bold("No-one"))
    else:
        parts.append(groups)
    parts.append(_crud_format(rule))
    if rule.domain_force not in {
            None, False, "[]", "[(1, '=', 1)]", '[(1, "=", 1)]'
    }:
        assert rule.domain_force
        parts.append(
            color.highlight(_domain_format(rule.env, rule.domain_force)))
    parts.extend(sources.format_sources(sources.find_source(rule)))
    return "\n".join(parts)
Exemple #5
0
def model_repr(obj):
    # type: (t.Union[ModelProxy, BaseModel]) -> t.Text
    """Summarize a model's fields."""
    if isinstance(obj, ModelProxy) and obj._real is None:
        return repr(obj)
    obj = util.unwrap(obj)

    field_names = []
    delegated = []
    for field in sorted(obj._fields):
        if field in FIELD_BLACKLIST:
            continue
        if getattr(obj._fields[field], "related", False):
            delegated.append(obj._fields[field])
            continue
        field_names.append(field)
    max_len = max(len(f) for f in field_names) if field_names else 0
    parts = []

    original_module = obj._module
    for parent in type(obj).__bases__:
        if getattr(parent, "_name", None) == obj._name:
            original_module = getattr(parent, "_module", original_module)

    parts.append(color.header(obj._name))
    if obj._transient:
        parts[-1] += " (transient)"
    if getattr(obj, "_abstract", False):
        parts[-1] += " (abstract)"
    elif not obj._auto:
        parts[-1] += " (no automatic table)"
    if getattr(obj, "_description", False) and obj._description != obj._name:
        parts.append(color.display_name(obj._description))
    if getattr(obj, "_inherits", False):
        for model_name, field_name in obj._inherits.items():
            parts.append("Inherits from {} through {}".format(
                color.model(model_name), color.field(field_name)))
    inherits = _find_inheritance(obj)
    if inherits:
        # Giving this a very similar message to the one for _inherits feels dirty
        # But then _inherit is already very similar to _inherits so maybe it's ok
        parts.append("Inherits from {}".format(", ".join(
            color.model(inherit) for inherit in sorted(inherits))))
    docs = list(
        sources.find_docs((util.module(cls), cls)
                          for cls in type(obj).__bases__
                          if getattr(cls, "_name", obj._name) == obj._name))
    parts.extend(sources.format_docs(docs))

    src = sources.find_source(obj)

    by_module = collections.defaultdict(list)
    for field in field_names:
        f_obj = obj._fields[field]
        rep = format_single_field(f_obj, max_len=max_len)
        f_module = sources.find_field_module(f_obj) or original_module
        by_module[f_module].append(rep)

    ordered_modules = [original_module]
    for src_item in reversed(src):
        if src_item.module not in ordered_modules:
            ordered_modules.append(src_item.module)
    for module in by_module:
        if module not in ordered_modules:
            ordered_modules.append(module)

    for module in ordered_modules:
        if module not in by_module:
            continue
        parts.append("")
        parts.append("{}:".format(color.module(module)))
        parts.extend(by_module[module])

    if delegated:
        buckets = collections.defaultdict(
            list)  # type: t.DefaultDict[t.Tuple[t.Text, ...], t.List[t.Text]]
        for f_obj in delegated:
            assert f_obj.related
            buckets[tuple(f_obj.related[:-1])].append(
                color.field(f_obj.name) if f_obj.related[-1] == f_obj.name else
                "{} (.{})".format(color.field(f_obj.name), f_obj.related[-1]))
        parts.append("")
        for related_field, field_names in buckets.items():
            # TODO: figure out name of model of real field
            parts.append("Delegated to {}: {}".format(
                color.yellow.bold(".".join(related_field)),
                ", ".join(field_names)))
    parts.append("")
    parts.extend(sources.format_sources(src))
    return "\n".join(parts)
Exemple #6
0
def record_repr(obj):
    # type: (BaseModel) -> t.Text
    """Display all of a record's fields."""
    obj = util.unwrap(obj)

    if not hasattr(obj, "_ids"):
        return repr(obj)
    elif not obj:
        return u"{}[]".format(obj._name)
    elif len(obj) > 1:
        return color.basic_render_record(obj)

    if obj.env.cr.closed:
        return color.basic_render_record(obj) + " (closed cursor)"

    field_names = sorted(field for field in obj._fields
                         if field not in odoo_repl.models.FIELD_BLACKLIST
                         and not obj._fields[field].related)
    max_len = max(len(f) for f in field_names) if field_names else 0
    parts = []

    parts.append(color.record_header(obj))
    name = obj.sudo().display_name
    default_name = "{},{}".format(obj._name, obj.id)
    if name and name != default_name:
        parts.append(color.display_name(name))

    if not obj.exists():
        parts.append(color.missing("Missing"))
        return "\n".join(parts)

    # Odoo precomputes a field for up to 200 records at a time.
    # This can be a problem if we're only interested in one of them.
    # So we do our best to disable it.

    # For Odoo 8, we do everything in a separate env where the ID cache is
    # empty. We make a separate env by changing the context. This has the added
    # advantage of informing models that they're running in odoo_repl, in case
    # they care. In _color_repr we clear the cache in case it got filled.

    # For Odoo 10-13, we slice the record. Odoo tries to be smart and narrows
    # the prefetch cache if we slice while keeping it when iterating.

    # I don't know what Odoo 9 does but I hope it's one of the above.

    # TODO: When .print_()ing a recordset we do want prefetching.

    if isinstance(obj.id, odoo.models.NewId):
        # Cache gets wonky if we start a new environment
        no_prefetch_obj = obj
    else:
        no_prefetch_obj = obj.with_context(odoo_repl=True)[:]

    for field in field_names:
        parts.append("{}: ".format(color.field(field)) +
                     (max_len - len(field)) * " " +
                     _color_repr(no_prefetch_obj, field))

    history_lines = _get_create_write_history(obj.sudo())
    if history_lines:
        parts.append("")
        parts.extend(history_lines)

    src = sources.find_source(obj)
    if src:
        parts.append("")
        parts.extend(sources.format_sources(src))

    return "\n".join(parts)