diff --git a/src/pybindings/pycontroller/BUILD.gn b/src/pybindings/pycontroller/BUILD.gn index 48bc73ea38b4c4..fafbeb9476623d 100644 --- a/src/pybindings/pycontroller/BUILD.gn +++ b/src/pybindings/pycontroller/BUILD.gn @@ -54,13 +54,12 @@ shared_library("CHIPController") { } sources = [ - "${root_gen_dir}/include/pybindings/pycontroller/CHIPErrorToExceptionBindings.cpp", - "${root_gen_dir}/include/pybindings/pycontroller/CHIPErrorToExceptionBindings.h", + "ControllerBindings/PyChip_ChipError.cpp", + "ControllerBindings/PyChip_ErrorStr.cpp", "ControllerBindings/PyChip_Main.cpp", ] public_deps = [ - ":build_exceptions", "${chip_root}/src/app", "${chip_root}/src/controller/data_model", "${chip_root}/src/lib", @@ -82,29 +81,6 @@ shared_library("CHIPController") { libs = [ "python3.9" ] } } -pw_python_action("build_exceptions") { - script = "create_error_wrapper.py" - - header_file = "${root_gen_dir}/include/pybindings/pycontroller/CHIPErrorToExceptionBindings.h" - cpp_file = "${root_gen_dir}/include/pybindings/pycontroller/CHIPErrorToExceptionBindings.cpp" - inputs = [ - "${chip_root}/src/lib/core/CHIPError.h", - "${chip_root}/src/lib/core/CHIPConfig.h", - ] - outputs = [ - header_file, - cpp_file, - ] - - args = [ - "--output_cpp_file=" + rebase_path(cpp_file, root_build_dir), - "--output_header_file=" + rebase_path(header_file, root_build_dir), - "--error_header=" + - rebase_path("${chip_root}/src/lib/core/CHIPError.h", root_build_dir), - "--config_header=" + - rebase_path("${chip_root}/src/lib/core/CHIPConfig.h", root_build_dir), - ] -} pw_python_action("pycontroller") { script = "build-chip-wheel.py" @@ -112,7 +88,7 @@ pw_python_action("pycontroller") { _py_manifest_files = [ { src_dir = "." - sources = [] + sources = [ "pychip/__init__.py" ] }, { src_dir = target_out_dir @@ -126,10 +102,7 @@ pw_python_action("pycontroller") { _py_manifest_file = "${target_gen_dir}/${target_name}.py_manifest.json" - inputs = [ - "${root_gen_dir}/include/pybindings/pycontroller/CHIPErrorToExceptionBindings.cpp", - "${root_gen_dir}/include/pybindings/pycontroller/CHIPErrorToExceptionBindings.h", - ] + inputs = [] _py_manifest_files_rebased = [] foreach(_manifest_entry, _py_manifest_files) { inputs += _manifest_entry.sources diff --git a/src/pybindings/pycontroller/ControllerBindings/PyChip_ChipError.cpp b/src/pybindings/pycontroller/ControllerBindings/PyChip_ChipError.cpp new file mode 100644 index 00000000000000..6ecd43277d5e0d --- /dev/null +++ b/src/pybindings/pycontroller/ControllerBindings/PyChip_ChipError.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include + +#include +#include +#include + +#ifndef BINDER_PYBIND11_TYPE_CASTER +#define BINDER_PYBIND11_TYPE_CASTER +PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr) +PYBIND11_DECLARE_HOLDER_TYPE(T, T *) +PYBIND11_MAKE_OPAQUE(std::shared_ptr) +#endif + +void bind_PyChip_ChipError(std::function & M) +{ + { + pybind11::class_> cl( + M("chip"), "ChipError", + "This is a helper class for managing `CHIP_ERROR` numbers.\n\n At the top level, an error belongs to a `Range` and has " + "an integral Value whose meaning depends on the `Range`.\n One, `Range::kSDK`, is used for the CHIP SDK's own errors; " + "others encapsulate error codes from external sources\n (e.g. libraries, OS) into a `CHIP_ERROR`.\n\n CHIP SDK errors " + "inside `Range::kSDK` consist of a component identifier given by `SdkPart` and an arbitrary small\n integer Code."); + cl.def(pybind11::init([]() { return new chip::ChipError(); })); + cl.def(pybind11::init(), pybind11::arg("error")); + + cl.def(pybind11::init([](chip::ChipError const & o) { return new chip::ChipError(o); })); + + pybind11::enum_(cl, "Range", "Top-level error classification.") + .value("kSDK", chip::ChipError::Range::kSDK) + .value("kOS", chip::ChipError::Range::kOS) + .value("kPOSIX", chip::ChipError::Range::kPOSIX) + .value("kLwIP", chip::ChipError::Range::kLwIP) + .value("kOpenThread", chip::ChipError::Range::kOpenThread) + .value("kPlatform", chip::ChipError::Range::kPlatform); + + pybind11::enum_(cl, "SdkPart", "Secondary classification of errors in `Range::kSDK`.") + .value("kCore", chip::ChipError::SdkPart::kCore) + .value("kInet", chip::ChipError::SdkPart::kInet) + .value("kDevice", chip::ChipError::SdkPart::kDevice) + .value("kASN1", chip::ChipError::SdkPart::kASN1) + .value("kBLE", chip::ChipError::SdkPart::kBLE) + .value("kApplication", chip::ChipError::SdkPart::kApplication); + + cl.def("__eq__", (bool (chip::ChipError::*)(const class chip::ChipError &) const) & chip::ChipError::operator==, + "C++: chip::ChipError::operator==(const class chip::ChipError &) const --> bool", pybind11::arg("other")); + cl.def("__ne__", (bool (chip::ChipError::*)(const class chip::ChipError &) const) & chip::ChipError::operator!=, + "C++: chip::ChipError::operator!=(const class chip::ChipError &) const --> bool", pybind11::arg("other")); + cl.def_static("IsSuccess", (bool (*)(unsigned int)) & chip::ChipError::IsSuccess, + "C++: chip::ChipError::IsSuccess(unsigned int) --> bool", pybind11::arg("error")); + cl.def_static("IsSuccess", (bool (*)(class chip::ChipError)) & chip::ChipError::IsSuccess, + "C++: chip::ChipError::IsSuccess(class chip::ChipError) --> bool", pybind11::arg("error")); + } + M("chip").def("RegisterCHIPLayerErrorFormatter", (void (*)()) & chip::RegisterCHIPLayerErrorFormatter, + "C++: chip::RegisterCHIPLayerErrorFormatter() --> void"); + + M("chip").def("FormatCHIPError", (bool (*)(char *, unsigned short, unsigned int)) & chip::FormatCHIPError, + "C++: chip::FormatCHIPError(char *, unsigned short, unsigned int) --> bool", pybind11::arg("buf"), + pybind11::arg("bufSize"), pybind11::arg("err")); +} diff --git a/src/pybindings/pycontroller/ControllerBindings/PyChip_ErrorStr.cpp b/src/pybindings/pycontroller/ControllerBindings/PyChip_ErrorStr.cpp new file mode 100644 index 00000000000000..3093434317ba8a --- /dev/null +++ b/src/pybindings/pycontroller/ControllerBindings/PyChip_ErrorStr.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include + +#include +#include +#include + +#ifndef BINDER_PYBIND11_TYPE_CASTER +#define BINDER_PYBIND11_TYPE_CASTER +PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr) +PYBIND11_DECLARE_HOLDER_TYPE(T, T *) +PYBIND11_MAKE_OPAQUE(std::shared_ptr) +#endif + +void bind_PyChip_ErrorStr(std::function & M) +{ + { + pybind11::class_> cl(M("chip"), "ErrorFormatter", ""); + cl.def(pybind11::init([]() { return new chip::ErrorFormatter(); })); + } + M("chip").def("ErrorStr", (const char * (*) (CHIP_ERROR)) & chip::ErrorStr, + "C++: chip::ErrorStr(unsigned int) --> const char *", pybind11::return_value_policy::automatic, + pybind11::arg("err")); + + M("chip").def("RegisterErrorFormatter", (void (*)(struct chip::ErrorFormatter *)) & chip::RegisterErrorFormatter, + "C++: chip::RegisterErrorFormatter(struct chip::ErrorFormatter *) --> void", pybind11::arg("errFormatter")); + + M("chip").def("DeregisterErrorFormatter", (void (*)(struct chip::ErrorFormatter *)) & chip::DeregisterErrorFormatter, + "C++: chip::DeregisterErrorFormatter(struct chip::ErrorFormatter *) --> void", pybind11::arg("errFormatter")); + + M("chip").def("FormatError", (void (*)(char *, unsigned short, const char *, unsigned int, const char *)) & chip::FormatError, + "C++: chip::FormatError(char *, unsigned short, const char *, unsigned int, const char *) --> void", + pybind11::arg("buf"), pybind11::arg("bufSize"), pybind11::arg("subsys"), pybind11::arg("err"), + pybind11::arg("desc")); +} diff --git a/src/pybindings/pycontroller/ControllerBindings/PyChip_Main.cpp b/src/pybindings/pycontroller/ControllerBindings/PyChip_Main.cpp index 7398aeff54351e..d7cc4effcb3197 100644 --- a/src/pybindings/pycontroller/ControllerBindings/PyChip_Main.cpp +++ b/src/pybindings/pycontroller/ControllerBindings/PyChip_Main.cpp @@ -24,7 +24,8 @@ typedef std::function ModuleGetter; -void bind_CHIPController_ChipExceptions(std::function & M); +void bind_PyChip_ErrorStr(std::function & M); +void bind_PyChip_ChipError(std::function & M); PYBIND11_MODULE(PyChip, root_module) { @@ -40,10 +41,11 @@ PYBIND11_MODULE(PyChip, root_module) modules[""] = root_module; - std::vector> sub_modules{ { "", "ChipExceptions" } }; + std::vector> sub_modules{ { "", "chip" } }; for (auto & p : sub_modules) modules[p.first.size() ? p.first + "::" + p.second : p.second] = modules[p.first].def_submodule(p.second.c_str(), ("Bindings for " + p.first + "::" + p.second + " namespace").c_str()); - bind_CHIPController_ChipExceptions(M); + bind_PyChip_ErrorStr(M); + bind_PyChip_ChipError(M); } diff --git a/src/pybindings/pycontroller/create_error_wrapper.py b/src/pybindings/pycontroller/create_error_wrapper.py deleted file mode 100644 index a8accf745627db..00000000000000 --- a/src/pybindings/pycontroller/create_error_wrapper.py +++ /dev/null @@ -1,168 +0,0 @@ -# -# Copyright (c) 2021 Project CHIP Authors -# All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -import sys -import re -import os -import argparse - - -class ErrorCode(object): - def __init__(self, error_name, error_code): - self.name = error_name.replace('_', ' ').title().replace(' ', '') - self.message = error_name - self.code = int(error_code, 16) - - def __str__(self): - return ''.format(self.name, self.code) - - def __repr__(self): - return ''.format(self.name, self.code) - - def create_exception_class(self): - return ''' -struct : public std::exception -{ - const char * what () const throw () - { - return ""; - } -}; -'''.replace('', self.name).replace('', self.message) - - def create_py_bind(self, module_name): - return 'py::register_exception({}, "{}");'.format(self.name, module_name, self.name) - - def create_else_if(self, var_name): - return ''' - else if ( == ) { - throw chip::PythonBindings::(); - }'''.replace('', var_name).replace('', str(self.code)).replace('', self.name) - - -def generate_header(error_codes): - structs = "".join([x.create_exception_class() for x in error_codes]) - return ''' -#include -#include - -namespace chip { -namespace PythonBindings { - - -void CHIPErrorToException(chip::ChipError err); -} -} -'''.replace('', structs) - - -def generate_cpp(error_codes): - exception_binding = '\n\t'.join( - [x.create_py_bind('M("ChipExceptions")') for x in error_codes]) - elseifs = ''.join([x.create_else_if('err.AsInteger()') - for x in error_codes]) - return ''' -#include "pybind11/pybind11.h" -#include "CHIPErrorToExceptionBindings.h" -#include - -namespace py = pybind11; - -void CHIPErrorToException(chip::ChipError err) { - if (err == CHIP_NO_ERROR) { - //Do Nothing - } -} - -void bind_CHIPController_ChipExceptions(std::function< pybind11::module &(std::string const &namespace_) > &M) -{ - M("ChipExceptions").def("CHIPErrorToException", &CHIPErrorToException, "Converts a chip::ChipError to an Exception"); - - -} -'''.replace('', exception_binding).replace('', elseifs) - - -def create_error_bindings(error_path, config_path, header_out, cpp_out): - error_header = None - config_header = None - - with open(error_path, 'r') as f: - error_header = f.read() - - with open(config_path, 'r') as f: - config_header = f.read() - - if error_header != None and config_header != None: - error_code_re = re.compile( - r'#define ([^\s]+).*CHIP_CORE_ERROR\((0[xX][0-9a-fA-F]+)\)') - error_code_tuples = error_code_re.findall(error_header) - error_codes = [ErrorCode(x[0], x[1]) - for x in error_code_tuples] - header = generate_header(error_codes) - cpp = generate_cpp(error_codes) - - print("Creating Header file: {}".format(header_out)) - with open(header_out, 'w') as f: - f.write(header) - - print("Creating CPP file {}".format(cpp_out)) - with open(cpp_out, 'w') as f: - f.write(cpp) - else: - print("Unable to open required files :(") - sys.exit(1) - - -def main(): - p = argparse.ArgumentParser() - - p.add_argument('--output_cpp_file', required=True, - help='Output location for .cpp file') - p.add_argument('--output_header_file', required=True, - help='Output location for .h file') - p.add_argument('--error_header', required=False, - help='Location of Error Header file (ex CHIPError.h)') - p.add_argument('--config_header', required=False, - help='Location of Config Header file (ex CHIPConfig.h)') - - args = p.parse_args() - - output_cpp_file = args.output_cpp_file - output_header_file = args.output_header_file - - error_path = '' - config_path = '' - - if args.error_header != None and args.error_header != "": - error_path = args.error_header - - if not os.path.exists(error_path): - print("Error Header Path {} does not exist".format(error_path)) - sys.exit(1) - - if args.config_header != None and args.config_header != "": - config_path = args.config_header - - if not os.path.exists(config_path): - print("Config Header Path {} does not exist!".format(config_path)) - - create_error_bindings(error_path, config_path, - output_header_file, output_cpp_file) - - -if __name__ == '__main__': - main() diff --git a/src/pybindings/pycontroller/pychip/__init__.py b/src/pybindings/pycontroller/pychip/__init__.py new file mode 100644 index 00000000000000..59fe478151e825 --- /dev/null +++ b/src/pybindings/pycontroller/pychip/__init__.py @@ -0,0 +1 @@ +from .PyChip import chip