Ejemplo n.º 1
0
def collect(cls: _Value, *, w: Walker) -> _Value:
    props = {}
    for name, typeinfo, metadata in w.walk_fields(cls):
        fieldname = w.resolver.metadata.resolve_name(metadata, default=name)
        value = getattr(cls, name, None)
        if value is None:
            value = typeinfo.raw
        props[fieldname] = collect(value, w=w)
    return props
Ejemplo n.º 2
0
def scan(walker: Walker, ) -> Context:
    ctx = Context(walker)
    builder = Builder(ctx, walker=walker)

    try:
        for cls in walker.walk():
            schema = builder.build_schema_data(cls)
            ctx.register_schema(cls, schema)
    finally:
        ctx.config.callbacks.teardown()  # xxx:
    return ctx
Ejemplo n.º 3
0
def walk(
    w: MetashapeWalker,
    *,
    metadata_handler: metadata_.MetadataHandlerFunction,
    _nonetype: t.Type[t.Any] = type(None),
    kinds: t.Optional[t.List[t.Optional[NodeKind]]] = None,
) -> t.Iterator[Item]:
    kinds = kinds or ["object", None, "enum"]
    for cls in w.walk(kinds=kinds):
        origin = getattr(cls, "__origin__", None)
        if origin is not None:
            args = list(typing_get_args(cls))
            if origin == t.Union and _nonetype not in args:  # union
                yield Item(name=guess_name(cls),
                           type_=cls,
                           fields=[],
                           args=args,
                           origin=origin)  # fixme
                for subtype in _get_flatten_args(cls):
                    w.append(subtype)
                continue
            elif origin == tx.Literal:  # literal
                yield Item(
                    name=resolve_name(cls),
                    type_=cls,
                    fields=[],
                    args=args,
                    origin=origin,
                )  # fixme name
                continue
            else:
                raise RuntimeError("unexpected type {cls!r}")

        fields: t.List[Row] = []
        for name, info, _metadata in w.for_type(cls).walk(
                ignore_private=False):
            if name.startswith("_") and name.endswith("_"):
                continue

            filled_metadata: metadata_.Metadata = metadata_.metadata()
            filled_metadata.update(_metadata)  # type:ignore

            if filled_metadata.get("default") == MISSING:
                filled_metadata.pop("default")
            if info.is_optional:
                filled_metadata["required"] = False

            # handling tags
            metadata_handler(cls,
                             name=name,
                             info=info,
                             metadata=filled_metadata)
            fields.append((name, info, filled_metadata))

            # append to walker, if needed
            for subtype in _get_flatten_args(info.type_):
                w.append(subtype)

        yield Item(name=resolve_name(cls), type_=cls, fields=fields, args=[])
Ejemplo n.º 4
0
def emit_class(m: Module, item: Item, *, w: Walker,
               resolver: TypeResolver) -> Symbol:
    name = item.name
    cls = item.type_

    i = 1
    m.stmt(f"message {name} {{")
    with m.scope():
        for name, info, _metadata in w.for_type(cls).walk(
                ignore_private=False):
            typ = resolver.resolve_type(info.type_)
            m.stmt(f"{typ} {name} = {i};")  # todo: deprecated
            i += 1
    m.stmt("}")
    return m.symbol(name)
Ejemplo n.º 5
0
def scan(walker: Walker, *, definitions: t.Optional[str] = None) -> Context:
    ctx = Context(walker)
    scanner = Scanner(ctx)

    try:
        for i, cls in enumerate(walker.walk()):
            scanner.scan(cls)
            if i == 0 and definitions is None:
                scanner.ctx.result.result[
                    "$ref"
                ] = f"#/definitions/{walker.resolver.resolve_typename(cls)}"

    finally:
        ctx.config.callbacks.teardown()  # xxx:
    return ctx
Ejemplo n.º 6
0
def _mark_recursive(
    w: Walker,
    members: t.List[Member],
    *,
    seen: t.Set[t.Type[t.Any]],
    guess_member: GuessMemberFunc,
) -> t.Iterable[t.Type[t.Any]]:
    from collections import deque

    q: t.Deque[t.Type[t.Any]] = deque()
    for m in members:
        q.append(m)

    while True:
        try:
            m = q.popleft()
        except IndexError:
            break
        if m in seen:
            continue
        seen.add(m)
        yield m

        kind = guess_member(m)
        if kind != "object":
            logger.debug("skip recursive walk, kind=%r, type=%r", kind, m)
            assert kind is not None
            mark(m, kind=kind)
            continue

        for _, info, _ in w.walk_fields(m):
            if info.type_ in seen:
                continue

            for x in info.args or [info]:
                if x.type_ in seen:
                    continue

                kind = guess_member(x.type_)
                if kind is None:
                    continue

                mark(x.type_, kind=kind)
                yield x.type_
                q.append(x.type_)
Ejemplo n.º 7
0
def scan(walker: Walker) -> Context:
    ctx = Context(walker)

    resolver = ctx.walker.resolver
    result = ctx.result

    scanned = _scan(walker)

    for enum in scanned.enums:
        result.enums[enum.__name__] = enum

    for cls in scanned.objects:
        schema = make_dict()
        typename = resolver.resolve_typename(cls)
        for field_name, info, metadata in walker.walk_fields(cls):
            field_name = resolver.metadata.resolve_name(metadata, default=field_name)
            prop = {"type": (scanned.get_name(info.type_) or detect.schema_type(info))}
            resolver.metadata.fill_extra_metadata(prop, metadata, name="graphql")
            schema[field_name] = prop

        result.types[typename] = schema
    return ctx
Ejemplo n.º 8
0
def emit(walker: Walker, *, output: t.Optional[t.IO[str]] = None) -> None:
    output = output or walker.config.option.output
    for m in walker.walk(ignore_private=walker.config.option.ignore_private):
        print(guess_mark(m), m, file=output)
Ejemplo n.º 9
0
def get_walker(
    target: t.Union[
        None,
        types.ModuleType,
        t.Type[t.Any],
        t.List[t.Type[t.Any]],
        t.Dict[str, t.Type[t.Any]],
    ] = None,
    *,
    config: t.Optional[Config] = None,
    aggressive: bool = False,
    recursive: bool = False,
    sort: bool = False,
    only: t.Optional[t.List[str]] = None,
    unwrap_type: t.Callable[[t.Type[t.Any]], t.Type[t.Any]] = _unwrap_type,
    _depth: int = 1,  # xxx: for black magic
    _extra_target_name: str = "__ADDITIONAL_TARGETS__",
    _seen_modules: t.Optional[t.Set[types.ModuleType]] = None,
    _guess_kind: t.Callable[[t.Any], t.Optional[Kind]] = _guess_kind,
) -> Walker:
    if _seen_modules is None:
        _seen_modules = set()

    config = config or Config()

    if target is None:
        if aggressive:
            logger.info(
                "aggressive=True and target=None, guessing target module... this is unsafe action"
            )
            # xxx: extract caller module (black magic)
            frame = sys._getframe(_depth)
            here = frame.f_globals["__name__"]
            try:
                target = sys.modules[here]
            except KeyError:
                raise ValueError("supported only module name")

    if target is None:
        raise ValueError("support target=None, only aggresive=True")
    elif isinstance(target, types.ModuleType):
        _seen_modules.add(target)
        d = target.__dict__
        if aggressive and only is None:
            only = [get_name(target)]

    elif isinstance(target, dict):
        d = target
        for x in d.values():
            mark(x, kind=_guess_kind(x) or "object")
    elif isinstance(target, (list, tuple)):
        d = {get_name(x): x for x in target}
        for x in target:
            mark(x, kind=_guess_kind(x) or "object")
    else:
        d = {get_name(target): target}
        mark(target, kind=_guess_kind(target) or "object")

    if only is not None:
        d = {
            k: v
            for k, v in d.items()
            if getattr(v, "__module__", "") in only or hasattr(v, "__origin__")
        }  # xxx: for supporting enum, see __origin__

    if aggressive:
        for name, v in list(d.items()):
            kind = _guess_kind(v)
            if kind is not None:
                if kind == "enum":
                    v.__name__ = name  # xxx TODO: use tx.Annotated
                mark(v, kind=kind)

    recursive = recursive or config.option.recursive
    sort = sort or config.option.sort

    itr = sorted(d.items()) if sort else d.items()
    members = [unwrap_type(v) for _, v in itr if is_marked(v)]

    named = {id(val): name for name, val in d.items()}
    resolver = Resolver(config=config, named=named)
    w = Walker(members, resolver=resolver, config=config)

    if recursive:
        if aggressive:
            guess_member = _guess_kind
        else:
            guess_member = guess_mark
        w._members = list(
            _mark_recursive(w, w._members, seen=set(), guess_member=guess_member)
        )  # xxx:

    if isinstance(target, types.ModuleType):
        for x in getattr(target, _extra_target_name, None) or []:
            if isinstance(x, types.ModuleType):
                _seen_modules.add(x)
                sw = get_walker(
                    x,
                    config=config,
                    aggressive=aggressive,
                    recursive=recursive,
                    sort=sort,
                    only=None,
                    _depth=_depth + 1,
                    _extra_target_name=_extra_target_name,
                    _seen_modules=_seen_modules,
                    _guess_kind=_guess_kind,
                )
                w._members.extend(sw._members)
            else:
                mark(x, kind=_guess_kind(x) or "object")
                w._members.append(x)

    return w