Namespaces#
It is possible to define a “root” namespace, for which no submodule is emitted. Thanks to the option below, the “Main” namespace will not be outputted as a submodule. However its content is exported.
options.namespaces_root = ["Main"]
For other namespace, litgen will output them as python submodules. If a namespace occurs twice in the C++ code, its content will grouped in the Python stubs
Note: in the python stub file, a namespace is shown as a fake class (although it is really a python submodule). This avoids the creation of an additional stub file, while maintaining a perfect code completion inside IDEs!
In the example below:
the namespace “details” is ignored
any anonymous namespace is ignored
occurrences of the namespace “Inner” are grouped
namespaces names are converted to snake_case
cpp_code = """
void FooRoot(); // A function in the root namespace
namespace details // This namespace should be excluded (see options.namespace_exclude__regex)
{
void FooDetails();
}
namespace // This anonymous namespace should be excluded
{
void LocalFunction();
}
// This namespace should not be outputted as a submodule,
// since it is present in options.namespaces_root
namespace Main
{
// this is an inner namespace (this comment should become the namespace doc)
namespace Inner
{
void FooInner();
}
// This is a second occurrence of the same inner namespace
// The generated python module will merge these occurrences
// (and this comment will be ignored, since the Inner namespace already has a doc)
namespace Inner
{
void FooInner2();
}
}
"""
import litgen
from litgen.demo import litgen_demo
options = litgen.LitgenOptions()
options.namespaces_root = ["Main"]
# options.namespace_exclude__regex = r"[Ii]nternal|[Dd]etail" # this is the default!
options.python_run_black_formatter = True
# options.python_convert_to_snake_case = False # uncomment this in order to keep the original namespaces and functions names
litgen_demo.demo(options, cpp_code)
void FooRoot(); // A function in the root namespace
namespace details // This namespace should be excluded (see options.namespace_exclude__regex)
{
void FooDetails();
}
namespace // This anonymous namespace should be excluded
{
void LocalFunction();
}
// This namespace should not be outputted as a submodule,
// since it is present in options.namespaces_root
namespace Main
{
// this is an inner namespace (this comment should become the namespace doc)
namespace Inner
{
void FooInner();
}
// This is a second occurrence of the same inner namespace
// The generated python module will merge these occurrences
// (and this comment will be ignored, since the Inner namespace already has a doc)
namespace Inner
{
void FooInner2();
}
}
def foo_root() -> None:
""" A function in the root namespace"""
pass
# <submodule inner>
class inner: # Proxy class that introduces typings for the *submodule* inner
pass # (This corresponds to a C++ namespace. All method are static!)
""" this is an inner namespace (this comment should become the namespace doc)"""
@staticmethod
def foo_inner() -> None:
pass
@staticmethod
def foo_inner2() -> None:
pass
# </submodule inner>
m.def("foo_root",
FooRoot, "A function in the root namespace");
{ // <namespace Inner>
py::module_ pyNsInner = m.def_submodule("inner", "this is an inner namespace (this comment should become the namespace doc)");
pyNsInner.def("foo_inner",
Main::Inner::FooInner);
pyNsInner.def("foo_inner2",
Main::Inner::FooInner2);
} // </namespace Inner>
m.def("foo_root",
FooRoot, "A function in the root namespace");
{ // <namespace Inner>
nb::module_ pyNsInner = m.def_submodule("inner", "this is an inner namespace (this comment should become the namespace doc)");
pyNsInner.def("foo_inner",
Main::Inner::FooInner);
pyNsInner.def("foo_inner2",
Main::Inner::FooInner2);
} // </namespace Inner>