Exemplo n.º 1
0
    def test_generate_c_property_with_pybind11(self) -> None:
        """Signatures included by PyBind11 inside property.fget are read."""
        class TestClass:
            def get_attribute(self) -> None:
                """
                (self: TestClass) -> str
                """
                pass
            attribute = property(get_attribute, doc="")

        output = []  # type: List[str]
        generate_c_property_stub('attribute', TestClass.attribute, output, readonly=True)
        assert_equal(output, ['@property', 'def attribute(self) -> str: ...'])
Exemplo n.º 2
0
    def test_generate_c_property_with_pybind11(self) -> None:
        """Signatures included by PyBind11 inside property.fget are read."""
        class TestClass:
            def get_attribute(self) -> None:
                """
                (self: TestClass) -> str
                """
                pass

            attribute = property(get_attribute, doc="")

        readwrite_properties: List[str] = []
        readonly_properties: List[str] = []
        generate_c_property_stub('attribute', TestClass.attribute, [],
                                 readwrite_properties, readonly_properties,
                                 is_c_property_readonly(TestClass.attribute))
        assert_equal(readwrite_properties, [])
        assert_equal(readonly_properties,
                     ['@property', 'def attribute(self) -> str: ...'])
Exemplo n.º 3
0
    def test_generate_c_property_with_rw_property(self) -> None:
        class TestClass:
            def __init__(self) -> None:
                self._attribute = 0

            @property
            def attribute(self) -> int:
                return self._attribute

            @attribute.setter
            def attribute(self, value: int) -> None:
                self._attribute = value

        readwrite_properties: List[str] = []
        readonly_properties: List[str] = []
        generate_c_property_stub("attribute", type(TestClass.attribute), [],
                                 readwrite_properties, readonly_properties,
                                 is_c_property_readonly(TestClass.attribute))
        assert_equal(readwrite_properties, ['attribute: Any'])
        assert_equal(readonly_properties, [])
Exemplo n.º 4
0
def generate_c_type_stub(
    module: ModuleType,
    class_name: str,
    obj: type,
    output: List[str],
    imports: List[str],
    sigs: Optional[Dict[str, str]] = None,
    class_sigs: Optional[Dict[str, str]] = None,
) -> None:
    """Generate stub for a single class using runtime introspection.

    The result lines will be appended to 'output'. If necessary, any
    required names will be added to 'imports'.
    """
    # typeshed gives obj.__dict__ the not quite correct type Dict[str, Any]
    # (it could be a mappingproxy!), which makes mypyc mad, so obfuscate it.
    obj_dict = getattr(obj, "__dict__")  # type: Mapping[str, Any]  # noqa
    items = sorted(obj_dict.items(),
                   key=lambda x: stubgenc.method_name_sort_key(x[0]))
    methods = []  # type: List[str]
    properties = []  # type: List[str]
    done = set()  # type: Set[str]
    for attr, value in items:
        if stubgenc.is_c_method(value) or stubgenc.is_c_classmethod(value):
            done.add(attr)
            if not is_skipped_attribute(attr):
                if attr == "__new__":
                    # TODO: We should support __new__.
                    if "__init__" in obj_dict:
                        # Avoid duplicate functions if both are present.
                        # But is there any case where .__new__() has a
                        # better signature than __init__() ?
                        continue
                    attr = "__init__"
                if stubgenc.is_c_classmethod(value):
                    methods.append("@classmethod")
                    self_var = "cls"
                else:
                    self_var = "self"
                stubgenc.generate_c_function_stub(
                    module,
                    attr,
                    value,
                    methods,
                    imports=imports,
                    self_var=self_var,
                    sigs=sigs,
                    class_name=class_name,
                    class_sigs=class_sigs,
                )
        elif stubgenc.is_c_property(value):
            done.add(attr)
            stubgenc.generate_c_property_stub(
                attr, value, properties,
                stubgenc.is_c_property_readonly(value))

        elif attr in obj.__annotations__:
            done.add(attr)
            properties.append("%s: %s = ..." %
                              (attr, obj.__annotations__[attr].__name__))

    variables = []
    for attr, value in items:
        if stubgenc.is_skipped_attribute(attr):
            continue
        for base in obj.mro()[1:]:
            if attr in base.__dict__:
                break
        else:
            if attr not in done:
                variables.append("%s: Any = ..." % attr)
    all_bases = obj.mro()
    if all_bases[-1] is object:
        # TODO: Is this always object?
        del all_bases[-1]
    # remove pybind11_object. All classes generated by pybind11 have pybind11_object in their MRO,
    # which only overrides a few functions in object type
    if all_bases and all_bases[-1].__name__ == "pybind11_object":
        del all_bases[-1]
    # remove the class itself
    all_bases = all_bases[1:]
    # Remove base classes of other bases as redundant.
    bases = []  # type: List[type]
    for base in all_bases:
        if not any(issubclass(b, base) for b in bases):
            bases.append(base)
    if bases:
        bases_str = "(%s)" % ", ".join(
            stubgenc.strip_or_import(stubgenc.get_type_fullname(base), module,
                                     imports) for base in bases)
    else:
        bases_str = ""
    output.append('')
    if dataclasses.is_dataclass(obj):
        output.append("@dataclasses.dataclass")
    if not methods and not variables and not properties:
        output.append("class %s%s: ..." % (class_name, bases_str))
    else:
        output.append("class %s%s:" % (class_name, bases_str))
        for variable in variables:
            output.append("    %s" % variable)
        for method in methods:
            output.append("    %s" % method)
        for prop in properties:
            output.append("    %s" % prop)