Skip to content

Port to 4.x: submodule or a class scope for exported classes #21488#21553

Merged
alalek merged 4 commits intoopencv:4.xfrom
VadimLevin:dev/vlevin/scope-for-classes-4x-port
Feb 24, 2022
Merged

Port to 4.x: submodule or a class scope for exported classes #21488#21553
alalek merged 4 commits intoopencv:4.xfrom
VadimLevin:dev/vlevin/scope-for-classes-4x-port

Conversation

@VadimLevin
Copy link
Copy Markdown
Contributor

@VadimLevin VadimLevin commented Feb 2, 2022

Port of #21488

Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
  • The PR is proposed to the proper branch
  • There is a reference to the original bug report and related work
  • There is accuracy test, performance test and test data in opencv_extra repository, if applicable
    Patch to opencv_extra has the same branch name.
  • The feature is well documented and sample code can be built with the project CMake
buildworker:Custom=linux-1
build_image:Custom=ubuntu:20.04

All classes are registered in the scope that corresponds to C++
namespace or exported class.

Example:
`cv::ml::Boost` is exported as `cv.ml.Boost`
`cv::SimpleBlobDetector::Params` is exported as
`cv.SimpleBlobDetector.Params`

For backward compatibility all classes are registered in the global
module with their mangling name containing scope information.
Example:
`cv::ml::Boost` has `cv.ml_Boost` alias to `cv.ml.Boost` type
@VadimLevin VadimLevin added port/backport done Label for maintainers. Authors of PR can ignore this category: python bindings labels Feb 2, 2022

cv.gapi.streaming.queue_capacity = cv.gapi_streaming_queue_capacity

cv.gapi.wip.GStreamerPipeline = cv.gapi_wip_gst_GStreamerPipeline
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still required because GStreamerPipeline is registered as cv.gapi.wip.gst.GStreamerPipeline

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/cc @TolyaTalamanov FYI

Copy link
Copy Markdown
Contributor

@TolyaTalamanov TolyaTalamanov Feb 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@OrestChura do you know why GStreamerPipeline can't be just in cv.gapi.wip.gst (not cv.gapi.wip) ?
Is it because we have alias in c++?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TolyaTalamanov Yes, we have cv::gapi::wip::GStreamerPipeline alias, but the initial declaration is in cv::gapi::wip::gst.
But it is not necessary to have it in Python, I think.

We can discuss and if needed fix it in a separate PR

@VadimLevin
Copy link
Copy Markdown
Contributor Author

VadimLevin commented Feb 2, 2022

It's kind of strange to see -Wunused-variable warnings on Linux machine in CI with GCC 5.4.0 when all variables are used.

On Ubuntu 20.04 GCC 9.3.0 and Clang 10 with and without -DPYTHON3_LIMITED_API=1 everything compiles without any troubles.

Other CI builds are fine too....

@alalek
Copy link
Copy Markdown
Member

alalek commented Feb 2, 2022

Looks like the problem is related to opencv_contrib.
Passed "Linux x64 Debug" and "Linux32" builders don't use opencv_contrib modules.
Other Linux builders are failed with Ubuntu 16.04 / 18.04 base images.


pyopencv_generated_types.h file looks malformed:

CVPY_TYPE(Algorithm, Algorithm, Ptr<cv::Algorithm>, Ptr, NoBase, 0, );
...
CVPY_TYPE(cuda_GpuData, GpuData, Ptr<cv::cuda::GpuData>, Ptr, NoBase, 0, .cuda);
...

Strings should be passed as strings instead of identifier or empty argument.

@VadimLevin
Copy link
Copy Markdown
Contributor Author

VadimLevin commented Feb 2, 2022

My configuration works without any errors

Details
-- General configuration for OpenCV 4.5.5-dev =====================================
--   Version control:               4.5.5-136-gb760e6a366
-- 
--   Extra modules:
--     Location (extra):            /home/vlevin/Projects/OpenCV/opencv_contrib/modules
--     Version control (extra):     4.5.5-19-gd4719b28
-- 
--   Platform:
--     Timestamp:                   2022-02-02T16:09:03Z
--     Host:                        Linux 5.13.0-27-generic x86_64
--     CMake:                       3.16.3
--     CMake generator:             Unix Makefiles
--     CMake build tool:            /usr/bin/make
--     Configuration:               Debug
-- 
--   CPU/HW features:
--     Baseline:                    SSE SSE2 SSE3
--       requested:                 SSE3
--     Dispatched code generation:  SSE4_1 SSE4_2 FP16 AVX AVX2 AVX512_SKX
--       requested:                 SSE4_1 SSE4_2 AVX FP16 AVX2 AVX512_SKX
--       SSE4_1 (18 files):         + SSSE3 SSE4_1
--       SSE4_2 (2 files):          + SSSE3 SSE4_1 POPCNT SSE4_2
--       FP16 (1 files):            + SSSE3 SSE4_1 POPCNT SSE4_2 FP16 AVX
--       AVX (5 files):             + SSSE3 SSE4_1 POPCNT SSE4_2 AVX
--       AVX2 (33 files):           + SSSE3 SSE4_1 POPCNT SSE4_2 FP16 FMA3 AVX AVX2
--       AVX512_SKX (8 files):      + SSSE3 SSE4_1 POPCNT SSE4_2 FP16 FMA3 AVX AVX2 AVX_512F AVX512_COMMON AVX512_SKX
-- 
--   C/C++:
--     Built as dynamic libs?:      YES
--     C++ standard:                11
--     C++ Compiler:                /bin/g++-9  (ver 9.3.0)
--     C++ flags (Release):         -fsigned-char -W -Wall -Wreturn-type -Wnon-virtual-dtor -Waddress -Wsequence-point -Wformat -Wformat-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Wsuggest-override -Wno-delete-non-virtual-dtor -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -Wno-long-long -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections  -msse -msse2 -msse3 -fvisibility=hidden -fvisibility-inlines-hidden -O3 -DNDEBUG  -DNDEBUG
--     C++ flags (Debug):           -fsigned-char -W -Wall -Wreturn-type -Wnon-virtual-dtor -Waddress -Wsequence-point -Wformat -Wformat-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Wsuggest-override -Wno-delete-non-virtual-dtor -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -Wno-long-long -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections  -msse -msse2 -msse3 -fvisibility=hidden -fvisibility-inlines-hidden -g  -O0 -DDEBUG -D_DEBUG
--     C Compiler:                  /bin/gcc-9
--     C flags (Release):           -fsigned-char -W -Wall -Wreturn-type -Waddress -Wsequence-point -Wformat -Wformat-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wuninitialized -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -Wno-long-long -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections  -msse -msse2 -msse3 -fvisibility=hidden -O3 -DNDEBUG  -DNDEBUG
--     C flags (Debug):             -fsigned-char -W -Wall -Wreturn-type -Waddress -Wsequence-point -Wformat -Wformat-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wuninitialized -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -Wno-long-long -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections  -msse -msse2 -msse3 -fvisibility=hidden -g  -O0 -DDEBUG -D_DEBUG
--     Linker flags (Release):      -Wl,--exclude-libs,libippicv.a -Wl,--exclude-libs,libippiw.a   -Wl,--gc-sections -Wl,--as-needed -Wl,--no-undefined  
--     Linker flags (Debug):        -Wl,--exclude-libs,libippicv.a -Wl,--exclude-libs,libippiw.a   -Wl,--gc-sections -Wl,--as-needed -Wl,--no-undefined  
--     ccache:                      NO
--     Precompiled headers:         NO
--     Extra dependencies:          dl m pthread rt
--     3rdparty dependencies:
-- 
--   OpenCV modules:
--     To be built:                 alphamat aruco barcode bgsegm bioinspired calib3d ccalib core datasets dnn dnn_objdetect dnn_superres dpm face features2d flann freetype fuzzy gapi hfs highgui img_hash imgcodecs imgproc intensity_transform line_descriptor mcc ml objdetect optflow phase_unwrapping photo plot python2 python3 quality rapid reg rgbd saliency shape stereo stitching structured_light superres surface_matching text tracking ts video videoio videostab wechat_qrcode xfeatures2d ximgproc xobjdetect xphoto
--     Disabled:                    world
--     Disabled by dependency:      -
--     Unavailable:                 cudaarithm cudabgsegm cudacodec cudafeatures2d cudafilters cudaimgproc cudalegacy cudaobjdetect cudaoptflow cudastereo cudawarping cudev cvv hdf java julia matlab ovis sfm viz
--     Applications:                tests perf_tests apps
--     Documentation:               NO
--     Non-free algorithms:         NO
-- 
--   GUI:                           GTK3
--     GTK+:                        YES (ver 3.24.20)
--       GThread :                  YES (ver 2.64.6)
--       GtkGlExt:                  NO
--     VTK support:                 NO
-- 
--   Media I/O: 
--     ZLib:                        /usr/lib/x86_64-linux-gnu/libz.so (ver 1.2.11)
--     JPEG:                        /usr/lib/x86_64-linux-gnu/libjpeg.so (ver 80)
--     WEBP:                        build (ver encoder: 0x020f)
--     PNG:                         /usr/lib/x86_64-linux-gnu/libpng.so (ver 1.6.37)
--     TIFF:                        /usr/lib/x86_64-linux-gnu/libtiff.so (ver 42 / 4.1.0)
--     JPEG 2000:                   build (ver 2.4.0)
--     OpenEXR:                     build (ver 2.3.0)
--     HDR:                         YES
--     SUNRASTER:                   YES
--     PXM:                         YES
--     PFM:                         YES
-- 
--   Video I/O:
--     DC1394:                      NO
--     FFMPEG:                      YES
--       avcodec:                   YES (58.54.100)
--       avformat:                  YES (58.29.100)
--       avutil:                    YES (56.31.100)
--       swscale:                   YES (5.5.100)
--       avresample:                YES (4.0.0)
--     GStreamer:                   YES (1.16.2)
--     v4l/v4l2:                    YES (linux/videodev2.h)
-- 
--   Parallel framework:            pthreads
-- 
--   Trace:                         YES (with Intel ITT)
-- 
--   Other third-party libraries:
--     Intel IPP:                   2020.0.0 Gold [2020.0.0]
--            at:                   /home/vlevin/Projects/OpenCV/opencv/build/3rdparty/ippicv/ippicv_lnx/icv
--     Intel IPP IW:                sources (2020.0.0)
--               at:                /home/vlevin/Projects/OpenCV/opencv/build/3rdparty/ippicv/ippicv_lnx/iw
--     VA:                          NO
--     Lapack:                      NO
--     Eigen:                       YES (ver 3.3.90)
--     Custom HAL:                  NO
--     Protobuf:                    build (3.19.1)
-- 
--   OpenCL:                        YES (no extra features)
--     Include path:                /home/vlevin/Projects/OpenCV/opencv/3rdparty/include/opencl/1.2
--     Link libraries:              Dynamic load
-- 
--   Python 2:
--     Interpreter:                 /usr/bin/python2.7 (ver 2.7.18)
--     Libraries:                   /usr/lib/x86_64-linux-gnu/libpython2.7.so (ver 2.7.18)
--     numpy:                       /usr/lib/python2.7/dist-packages/numpy/core/include (ver 1.16.5)
--     install path:                lib/python2.7/dist-packages/cv2/python-2.7
-- 
--   Python 3:
--     Interpreter:                 /home/vlevin/.pyenv/shims/python3 (ver 3.8.10)
--     Libraries:                   /usr/lib/x86_64-linux-gnu/libpython3.8.so (ver 3.8.10)
--     numpy:                       /home/vlevin/.local/lib/python3.8/site-packages/numpy/core/include (ver 1.22.1)
--     install path:                lib/python3.8/site-packages/cv2/python-3.8
-- 
--   Python (for build):            /usr/bin/python2.7
-- 
--   Java:                          
--     ant:                         NO
--     JNI:                         NO
--     Java wrappers:               NO
--     Java tests:                  NO
-- 
--   Install to:                    /usr/local
-- -----------------------------------------------------------------

Strings should be passed as strings instead of identifier or empty argument.

C++11 pre-print draft
16.3.4 statement:

If the identifier-list in the macro definition does not end with an ellipsis, the number of arguments (including
those arguments consisting of no preprocessing tokens) in an invocation of a function-like macro shall equal
the number of parameters in the macro definition.

According to this statement the following code is completely valid (unfortunately) even with -Werror -Wextra -Wall -pedantic
https://godbolt.org/z/MrGqdcaK5

#include <iostream>

#define foo(x, y) x ## y

int main() {
    const char* helloworld = "hello, world!";

    std::cout << "Two arguments: '" <<  foo(hello, world)
              << "'\nFirst argument only: '" << foo(helloworld, )
              << "'\nSecond argument only: '"<< foo(, 1)
              << "'\nCompletely empty: '" << foo(,) "'\n";
    return 0;
}

Outputs:

Program returned: 0
Two arguments: 'hello, world!'
First argument only: 'hello, world!'
Second argument only: '1'
Completely empty: ''

Let's try specify strings arguments explicitly

@VadimLevin
Copy link
Copy Markdown
Contributor Author

VadimLevin commented Feb 2, 2022

Explicit string arguments in macros are not fixing builds for Linux configuration with opencv_contrib.
It looks like the error is related to the some contrib module, need to examine.

@VadimLevin
Copy link
Copy Markdown
Contributor Author

VadimLevin commented Feb 3, 2022

@alalek Can you share a content of the pyopencv_generated_types_content.h and pyopencv_generated_types.h from failed Linux builds?

Details

Unavailable modules diff: x - means not built

Modules Linux OSX Windows
alphamat x x
cudaarithm x x x
cudabgsegm x x x
cudacodec x x x
cudafeatures2d x x x
cudafilters x x x
cudaimgproc x x x
cudalegacy x x x
cudaobjdetect x x x
cudaoptflow x x x
cudastereo x x x
cudawarping x x x
cudev x x x
cvv x x x
julia x x x
matlab x x x
ovis x x x
sfm x x
freetype x
hdf x
viz x

alphamat doesn't define any class.
sfm is available in 3.4 branch too, but Linux builds are fine on 3.4 with the same changes...

@alalek
Copy link
Copy Markdown
Member

alalek commented Feb 3, 2022

According to error messages on Ubuntu 16/18/20 this problem is related to "viz" module:

In file included from /build/precommit_custom_linux/4.x/opencv/modules/python/src2/cv2.cpp:90:
/build/precommit_custom_linux/build/modules/python_bindings_generator/pyopencv_generated_types_content.h:89557:54: error: 'pyopencv_viz_PyAffine3d_t' was not declared in this scope; did you mean 'pyopencv_viz_Affine3d_t'?
89557 | static int pyopencv_cv_viz_viz_PyAffine3d_PyAffine3d(pyopencv_viz_PyAffine3d_t* self, PyObject* py_args, PyObject* kw)
      |                                                      ^~~~~~~~~~~~~~~~~~~~~~~~~
      |                                                      pyopencv_viz_Affine3d_t

There is mess between:

  • pyopencv_viz_Affine3d_t
  • pyopencv_viz_PyAffine3d_t

Wrapper is defined through alias name:

struct CV_EXPORTS_W_SIMPLE CV_WRAP_AS(Affine3d) PyAffine3d

Probably It makes sense to bring similar test case into core's bindings_utils.hpp.

To reproduce original error please install libvtk7-dev package, re-run CMake from scratch and run gen_opencv_python_source target.

@VadimLevin
Copy link
Copy Markdown
Contributor Author

Yep, thanks for reproducer. I'll add the appropriate test case with a fix.

It makes sense to use wname to generate methods table for all classes, because it is a unique identifier.
Aliasing should influence only exported class name.

@VadimLevin VadimLevin changed the title Port to 4.x: submodule or a class scope for exported classes #21488 WIP: Port to 4.x: submodule or a class scope for exported classes #21488 Feb 4, 2022
@VadimLevin VadimLevin force-pushed the dev/vlevin/scope-for-classes-4x-port branch from 43271bc to 0cc7954 Compare February 7, 2022 11:41
self.export_name = self.original_name
self.scope_name = re.sub(r"^cv\.?", "", self.scope_name)

self.class_id = normalize_class_name(name)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to rename .name, .wname, .cname, .sname wtf fields then we should do it anywhere (for all entities, and for all bindings generators and with clear documentation).

Is it possible to have minimal patch here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but there is already a mess with the naming, because different parts treats them as they want.
Something uses wname as identifier, something uses it as general class name.
At least better naming helps to describe the actual intent.
What is sname in this case?

Copy link
Copy Markdown
Member

@alalek alalek Feb 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I completely agree with that.
My statement that we should not have this change now in the current PR. Lets try to keep it minimal.

{ \
char str[1000]; \
sprintf(str, "<"#WNAME" %p>", self); \
sprintf(str, "< " MODULESTR SCOPE"."#NAME" %p>", self); \
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO, patch just switched semantic of macro parameters (switched the first and the second parameter).

Previously:

  • NAME is internal, C++ code connected identifier.
  • WNAME is wrapper name.

If we really want to do that, then robust patch should rename the macro too to avoid misusing mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actual name of the NAME macro should be a CLASS_ID, WNAME should be actually NAME in this case.

self.scope_name, self.original_name = name.rsplit(".", 1)

self.export_name = self.original_name
self.scope_name = re.sub(r"^cv\.?", "", self.scope_name)
Copy link
Copy Markdown
Member

@alalek alalek Feb 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current code emits (pyopencv_generated_modules_content.h):

static PyMethodDef methods_viz[] = {
    {"PyAffine3d_Identity", CV_PY_FN_WITH_KW_(pyopencv_cv_viz_PyAffine3d_Identity, 0), "PyAffine3d_Identity() -> retval\n."},
    ...
  1. "PyAffine3d_Identity" -> "Affine3d_Identity" as we see and use Affine3d from Python.
  2. pyopencv_cv_viz_PyAffine3d_Identity. With similar case in Java it is important to have "wrapper" name in method declaration, e.g: pyopencv_cv_viz_Affine3d_Identity()
  3. Doc string should be replaced too.

Next (pyopencv_generated_types_content.h):

if( PyArg_ParseTupleAndKeywords(py_args, kw, "O:viz_Affine3d.product", (char**)keywords, &pyobj_t)
  1. "O:viz_PyAffine3d.product" => "O:viz_Affine3d.product"

struct CV_EXPORTS_W_SIMPLE CV_WRAP_AS(Affine3d) PyAffine3d
                                         ^          ^
                we must see this in binding         |
                                                  we use this internally in C++ code only

Test case:

// class CV_EXPORTS_W CV_WRAP_AS(ExportClassName) OriginalClassName
static PyMethodDef methods_utils_nested[] = {
    {"OriginalClassName_create", CV_PY_FN_WITH_KW_(pyopencv_cv_utils_nested_OriginalClassName_create, 0), "OriginalClassName_create() -> retval\n."},

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I know, that's why the patch is in WIP

@VadimLevin VadimLevin force-pushed the dev/vlevin/scope-for-classes-4x-port branch from 0cc7954 to 559c32e Compare February 15, 2022 12:17
@VadimLevin VadimLevin changed the title WIP: Port to 4.x: submodule or a class scope for exported classes #21488 Port to 4.x: submodule or a class scope for exported classes #21488 Feb 15, 2022
@VadimLevin VadimLevin marked this pull request as ready for review February 15, 2022 15:48
@VadimLevin VadimLevin requested a review from alalek February 15, 2022 15:48
}
else if (PyType_CheckExact(scope))
{
scope = getScopeFromTypeObject(scope, current_scope_name);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getScopeFromTypeObject() may trigger error (through PyErr_Format() with NULL result).
But its message will be overwritten below (line 412)

Can we "stack" errors?

Copy link
Copy Markdown
Contributor Author

@VadimLevin VadimLevin Feb 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it was rejected. PEP 490. Manual solution is out of the current patch scope.

@VadimLevin VadimLevin force-pushed the dev/vlevin/scope-for-classes-4x-port branch from 559c32e to 433b1eb Compare February 16, 2022 08:19
Copy link
Copy Markdown
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

Could you please update 3.4 PR with new tests?

@alalek alalek merged commit 119d8b3 into opencv:4.x Feb 24, 2022
@opencv-pushbot opencv-pushbot mentioned this pull request Apr 23, 2022
a-sajjad72 pushed a commit to a-sajjad72/opencv that referenced this pull request Mar 30, 2023
…classes-4x-port

4.x: submodule or a class scope for exported classes

* feature: submodule or a class scope for exported classes

All classes are registered in the scope that corresponds to C++
namespace or exported class.

Example:
`cv::ml::Boost` is exported as `cv.ml.Boost`
`cv::SimpleBlobDetector::Params` is exported as
`cv.SimpleBlobDetector.Params`

For backward compatibility all classes are registered in the global
module with their mangling name containing scope information.
Example:
`cv::ml::Boost` has `cv.ml_Boost` alias to `cv.ml.Boost` type

* refactor: remove redundant GAPI aliases

* fix: use explicit string literals in CVPY_TYPE macro

* fix: add handling for class aliases
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

category: python bindings port/backport done Label for maintainers. Authors of PR can ignore this

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants