Ejemplo n.º 1
0
    def test_generate_c_type_with_overload_pybind11(self) -> None:
        class TestClass:
            def __init__(self, arg0: str) -> None:
                """
                __init__(*args, **kwargs)
                Overloaded function.

                1. __init__(self: TestClass, arg0: str) -> None

                2. __init__(self: TestClass, arg0: str, arg1: str) -> None
                """
                pass
        output = []  # type: List[str]
        imports = []  # type: List[str]
        mod = ModuleType(TestClass.__module__, '')
        generate_c_function_stub(mod, '__init__', TestClass.__init__, output, imports,
                                 self_var='self', class_name='TestClass')
        assert_equal(output, [
            '@overload',
            'def __init__(self, arg0: str) -> None: ...',
            '@overload',
            'def __init__(self, arg0: str, arg1: str) -> None: ...',
            '@overload',
            'def __init__(*args, **kwargs) -> Any: ...'])
        assert_equal(set(imports), {'from typing import overload'})
    def test_generate_c_type_with_overload_pybind11(self) -> None:
        class TestClass:
            def __init__(self, arg0: str) -> None:
                """
                __init__(*args, **kwargs)
                Overloaded function.

                1. __init__(self: TestClass, arg0: str) -> None

                2. __init__(self: TestClass, arg0: str, arg1: str) -> None
                """
                pass

        output = []  # type: List[str]
        imports = []  # type: List[str]
        mod = ModuleType(TestClass.__module__, '')
        generate_c_function_stub(mod,
                                 '__init__',
                                 TestClass.__init__,
                                 output,
                                 imports,
                                 self_var='self',
                                 class_name='TestClass')
        assert_equal(output, [
            '@overload', 'def __init__(self, arg0: str) -> None: ...',
            '@overload',
            'def __init__(self, arg0: str, arg1: str) -> None: ...',
            '@overload', 'def __init__(*args, **kwargs) -> Any: ...'
        ])
        assert_equal(set(imports), {'from typing import overload'})
Ejemplo n.º 3
0
 def test_generate_c_function_other_module_ret(self) -> None:
     """Test that if return type references type from other module, module will be imported."""
     def test(arg0: str) -> None:
         """
         test(arg0: str) -> argparse.Action
         """
         pass
     output = []  # type: List[str]
     imports = []  # type: List[str]
     mod = ModuleType(self.__module__, '')
     generate_c_function_stub(mod, 'test', test, output, imports)
     assert_equal(output, ['def test(arg0: str) -> argparse.Action: ...'])
     assert_equal(imports, ['import argparse'])
Ejemplo n.º 4
0
 def test_generate_c_function_other_module_ret(self) -> None:
     """Test that if return type references type from other module, module will be imported."""
     def test(arg0: str) -> None:
         """
         test(arg0: str) -> argparse.Action
         """
         pass
     output = []  # type: List[str]
     imports = []  # type: List[str]
     mod = ModuleType(self.__module__, '')
     generate_c_function_stub(mod, 'test', test, output, imports)
     assert_equal(output, ['def test(arg0: str) -> argparse.Action: ...'])
     assert_equal(imports, ['import argparse'])
Ejemplo n.º 5
0
 def test_generate_c_type_with_docstring_empty_default(self) -> None:
     class TestClass:
         def test(self, arg0: str = "") -> None:
             """
             test(self: TestClass, arg0: str = "")
             """
             pass
     output = []  # type: List[str]
     imports = []  # type: List[str]
     mod = ModuleType(TestClass.__module__, '')
     generate_c_function_stub(mod, 'test', TestClass.test, output, imports,
                              self_var='self', class_name='TestClass')
     assert_equal(output, ['def test(self, arg0: str = ...) -> Any: ...'])
     assert_equal(imports, [])
Ejemplo n.º 6
0
 def test_generate_c_type_with_docstring_empty_default(self) -> None:
     class TestClass:
         def test(self, arg0: str = "") -> None:
             """
             test(self: TestClass, arg0: str = "")
             """
             pass
     output = []  # type: List[str]
     imports = []  # type: List[str]
     mod = ModuleType(TestClass.__module__, '')
     generate_c_function_stub(mod, 'test', TestClass.test, output, imports,
                              self_var='self', class_name='TestClass')
     assert_equal(output, ['def test(self, arg0: str = ...) -> Any: ...'])
     assert_equal(imports, [])
Ejemplo n.º 7
0
 def test_generate_c_type_with_generic_using_other_module_last(self) -> None:
     class TestClass:
         def test(self, arg0: str) -> None:
             """
             test(self: TestClass, arg0: Dict[str, argparse.Action])
             """
             pass
     output = []  # type: List[str]
     imports = []  # type: List[str]
     mod = ModuleType(TestClass.__module__, '')
     generate_c_function_stub(mod, 'test', TestClass.test, output, imports,
                              self_var='self', class_name='TestClass')
     assert_equal(output, ['def test(self, arg0: Dict[str,argparse.Action]) -> Any: ...'])
     assert_equal(imports, ['import argparse'])
Ejemplo n.º 8
0
 def test_generate_c_function_same_module_ret(self) -> None:
     """Test that if return type references type from same module but using full path,
     no module will be imported, and type specification will be striped to local reference.
     """
     def test(arg0: str) -> None:
         """
         test(arg0: str) -> argparse.Action
         """
         pass
     output = []  # type: List[str]
     imports = []  # type: List[str]
     mod = ModuleType('argparse', '')
     generate_c_function_stub(mod, 'test', test, output, imports)
     assert_equal(output, ['def test(arg0: str) -> Action: ...'])
     assert_equal(imports, [])
Ejemplo n.º 9
0
 def test_generate_c_function_other_module_arg(self) -> None:
     """Test that if argument references type from other module, module will be imported."""
     # Provide different type in python spec than in docstring to make sure, that docstring
     # information is used.
     def test(arg0: str) -> None:
         """
         test(arg0: argparse.Action)
         """
         pass
     output = []  # type: List[str]
     imports = []  # type: List[str]
     mod = ModuleType(self.__module__, '')
     generate_c_function_stub(mod, 'test', test, output, imports)
     assert_equal(output, ['def test(arg0: argparse.Action) -> Any: ...'])
     assert_equal(imports, ['import argparse'])
Ejemplo n.º 10
0
 def test_generate_c_function_other_module_arg(self) -> None:
     """Test that if argument references type from other module, module will be imported."""
     # Provide different type in python spec than in docstring to make sure, that docstring
     # information is used.
     def test(arg0: str) -> None:
         """
         test(arg0: argparse.Action)
         """
         pass
     output = []  # type: List[str]
     imports = []  # type: List[str]
     mod = ModuleType(self.__module__, '')
     generate_c_function_stub(mod, 'test', test, output, imports)
     assert_equal(output, ['def test(arg0: argparse.Action) -> Any: ...'])
     assert_equal(imports, ['import argparse'])
Ejemplo n.º 11
0
    def test_generate_c_type_with_nested_generic(self) -> None:
        class TestClass:
            def test(self, arg0: str) -> None:
                """
                test(self: TestClass, arg0: Dict[str, List[int]])
                """
                pass

        output: List[str] = []
        imports: List[str] = []
        mod = ModuleType(TestClass.__module__, '')
        generate_c_function_stub(mod, 'test', TestClass.test, output, imports,
                                 self_var='self', class_name='TestClass')
        assert_equal(output, ['def test(self, arg0: Dict[str,List[int]]) -> Any: ...'])
        assert_equal(imports, [])
Ejemplo n.º 12
0
 def test_generate_c_function_same_module_ret(self) -> None:
     """Test that if return type references type from same module but using full path,
     no module will be imported, and type specification will be striped to local reference.
     """
     def test(arg0: str) -> None:
         """
         test(arg0: str) -> argparse.Action
         """
         pass
     output = []  # type: List[str]
     imports = []  # type: List[str]
     mod = ModuleType('argparse', '')
     generate_c_function_stub(mod, 'test', test, output, imports)
     assert_equal(output, ['def test(arg0: str) -> Action: ...'])
     assert_equal(imports, [])
Ejemplo n.º 13
0
 def test_generate_c_function_same_module_arg(self) -> None:
     """Test that if argument references type from same module but using full path, no module
     will be imported, and type specification will be striped to local reference.
     """
     # Provide different type in python spec than in docstring to make sure, that docstring
     # information is used.
     def test(arg0: str) -> None:
         """
         test(arg0: argparse.Action)
         """
         pass
     output = []  # type: List[str]
     imports = []  # type: List[str]
     mod = ModuleType('argparse', '')
     generate_c_function_stub(mod, 'test', test, output, imports)
     assert_equal(output, ['def test(arg0: Action) -> Any: ...'])
     assert_equal(imports, [])
Ejemplo n.º 14
0
 def test_generate_c_function_same_module_arg(self) -> None:
     """Test that if argument references type from same module but using full path, no module
     will be imported, and type specification will be striped to local reference.
     """
     # Provide different type in python spec than in docstring to make sure, that docstring
     # information is used.
     def test(arg0: str) -> None:
         """
         test(arg0: argparse.Action)
         """
         pass
     output = []  # type: List[str]
     imports = []  # type: List[str]
     mod = ModuleType('argparse', '')
     generate_c_function_stub(mod, 'test', test, output, imports)
     assert_equal(output, ['def test(arg0: Action) -> Any: ...'])
     assert_equal(imports, [])
Ejemplo n.º 15
0
    def test_generate_c_type_classmethod(self) -> None:
        class TestClass:
            @classmethod
            def test(cls, arg0: str) -> None:
                pass

        output = []  # type: List[str]
        imports = []  # type: List[str]
        mod = ModuleType(TestClass.__module__, '')
        generate_c_function_stub(mod,
                                 'test',
                                 TestClass.test,
                                 output,
                                 imports,
                                 self_var='cls',
                                 class_name='TestClass')
        assert_equal(output, ['def test(cls, *args, **kwargs) -> Any: ...'])
        assert_equal(imports, [])
Ejemplo n.º 16
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)
Ejemplo n.º 17
0
def generate_stub_for_c_module(
    module_name: str,
    target: str,
    sigs: Optional[Dict[str, str]] = None,
    class_sigs: Optional[Dict[str, str]] = None,
) -> None:
    """Generate stub for C module.

    This combines simple runtime introspection (looking for docstrings and attributes
    with simple builtin types) and signatures inferred from .rst documentation (if given).

    If directory for target doesn't exist it will be created. Existing stub
    will be overwritten.
    """
    module = importlib.import_module(module_name)
    assert stubgenc.is_c_module(module), "%s is not a C module" % module_name
    subdir = os.path.dirname(target)
    if subdir and not os.path.isdir(subdir):
        os.makedirs(subdir)
    imports = []  # type: List[str]
    functions = []  # type: List[str]
    done = set()
    items = sorted(module.__dict__.items(), key=lambda x: x[0])
    for name, obj in items:
        if stubgenc.is_c_function(obj):
            stubgenc.generate_c_function_stub(module,
                                              name,
                                              obj,
                                              functions,
                                              imports=imports,
                                              sigs=sigs)
            done.add(name)
    types = []  # type: List[str]
    for name, obj in items:
        if name.startswith("__") and name.endswith("__"):
            continue
        if obj.__module__ != module.__name__:
            done.add(name)
            continue
        if stubgenc.is_c_type(obj):
            generate_c_type_stub(
                module,
                name,
                obj,
                types,
                imports=imports,
                sigs=sigs,
                class_sigs=class_sigs,
            )
            done.add(name)
    variables = []
    for name, obj in items:
        if name.startswith("__") and name.endswith("__"):
            continue
        if name not in done and not inspect.ismodule(obj):
            type_str = type(obj).__name__
            if type_str not in ("int", "str", "bytes", "float", "bool"):
                type_str = "Any"
            variables.append("%s: %s" % (name, type_str))
    output = ['import dataclasses', 'from typing import Any']
    for line in sorted(set(imports)):
        output.append(line)
    for line in variables:
        output.append(line)
    if output and functions:
        output.append("")
    for line in functions:
        output.append(line)
    for line in types:
        output.append(line)
    with open(target, "w") as file:
        for line in output:
            file.write("%s\n" % line)