From cbeff3a06c2280633768f5cda65cd35fde2da5c9 Mon Sep 17 00:00:00 2001
From: Sergey Yakubov <sergey.yakubov@desy.de>
Date: Tue, 20 Aug 2019 12:33:31 +0200
Subject: [PATCH] start work at python libs for producer

---
 README.md                                     |  2 +-
 config/bamboo/bamboo.java                     |  2 +-
 examples/pipeline/in_to_out/CMakeLists.txt    |  2 +-
 .../dummy-data-producer/CMakeLists.txt        |  2 +-
 .../CMakeLists_separate.in                    |  2 +-
 producer/CMakeLists.txt                       |  4 +-
 producer/api/README.md                        | 22 --------
 producer/api/{ => cpp}/CMakeLists.txt         |  2 +-
 .../api/{ => cpp}/include/asapo_producer.h    |  0
 .../api/{ => cpp}/include/producer/common.h   |  0
 .../api/{ => cpp}/include/producer/producer.h |  0
 .../include/producer/producer_error.h         |  0
 producer/api/{ => cpp}/src/producer.cpp       |  5 +-
 producer/api/{ => cpp}/src/producer_impl.cpp  |  0
 producer/api/{ => cpp}/src/producer_impl.h    |  0
 .../api/{ => cpp}/src/producer_logger.cpp     |  0
 producer/api/{ => cpp}/src/producer_logger.h  |  0
 .../api/{ => cpp}/src/producer_request.cpp    |  0
 producer/api/{ => cpp}/src/producer_request.h |  0
 .../src/producer_request_handler_factory.h    |  0
 ...er_data_server_request_handler_factory.cpp |  0
 .../src/receiver_discovery_service.cpp        |  0
 .../src/receiver_discovery_service.h          |  0
 .../src/request_handler_filesystem.cpp        |  0
 .../src/request_handler_filesystem.h          |  0
 .../api/{ => cpp}/src/request_handler_tcp.cpp |  0
 .../api/{ => cpp}/src/request_handler_tcp.h   |  0
 producer/api/{ => cpp}/unittests/mocking.h    |  0
 .../api/{ => cpp}/unittests/test_producer.cpp | 10 ++++
 .../unittests/test_producer_impl.cpp          |  0
 .../unittests/test_producer_request.cpp       |  0
 .../test_receiver_discovery_service.cpp       |  0
 .../test_request_handler_factory.cpp          |  0
 .../test_request_handler_filesystem.cpp       |  0
 .../unittests/test_request_handler_tcp.cpp    |  0
 producer/api/python/CMakeLists.txt            | 17 +++++++
 producer/api/python/CMakeLists_Linux.cmake    | 27 ++++++++++
 producer/api/python/CMakeLists_Windows.cmake  | 30 +++++++++++
 producer/api/python/asapo_producer.pxd        | 39 ++++++++++++++
 producer/api/python/asapo_producer.pyx.in     | 51 +++++++++++++++++++
 producer/api/python/asapo_wrappers.h          | 16 ++++++
 .../python/binary_dist_windows/CMakeLists.txt | 16 ++++++
 .../python/binary_dist_windows/setup.py.in    | 12 +++++
 producer/api/python/cythonize.py              |  3 ++
 producer/api/python/setup.py.in               | 19 +++++++
 .../python/source_dist_linux/CMakeLists.txt   | 26 ++++++++++
 .../api/python/source_dist_linux/MANIFEST.in  |  3 ++
 .../api/python/source_dist_linux/setup.py.in  | 22 ++++++++
 .../event_monitor_producer/CMakeLists.txt     |  2 +-
 .../producer/beamtime_metadata/CMakeLists.txt |  2 +-
 tests/manual/python_tests/producer/run.sh     |  4 ++
 tests/manual/python_tests/producer/test.py    | 20 ++++++++
 .../python/binary_dist_windows/CMakeLists.txt | 12 ++---
 .../python/source_dist_linux/CMakeLists.txt   |  8 +--
 54 files changed, 339 insertions(+), 43 deletions(-)
 delete mode 100644 producer/api/README.md
 rename producer/api/{ => cpp}/CMakeLists.txt (97%)
 rename producer/api/{ => cpp}/include/asapo_producer.h (100%)
 rename producer/api/{ => cpp}/include/producer/common.h (100%)
 rename producer/api/{ => cpp}/include/producer/producer.h (100%)
 rename producer/api/{ => cpp}/include/producer/producer_error.h (100%)
 rename producer/api/{ => cpp}/src/producer.cpp (79%)
 rename producer/api/{ => cpp}/src/producer_impl.cpp (100%)
 rename producer/api/{ => cpp}/src/producer_impl.h (100%)
 rename producer/api/{ => cpp}/src/producer_logger.cpp (100%)
 rename producer/api/{ => cpp}/src/producer_logger.h (100%)
 rename producer/api/{ => cpp}/src/producer_request.cpp (100%)
 rename producer/api/{ => cpp}/src/producer_request.h (100%)
 rename producer/api/{ => cpp}/src/producer_request_handler_factory.h (100%)
 rename producer/api/{ => cpp}/src/receiver_data_server_request_handler_factory.cpp (100%)
 rename producer/api/{ => cpp}/src/receiver_discovery_service.cpp (100%)
 rename producer/api/{ => cpp}/src/receiver_discovery_service.h (100%)
 rename producer/api/{ => cpp}/src/request_handler_filesystem.cpp (100%)
 rename producer/api/{ => cpp}/src/request_handler_filesystem.h (100%)
 rename producer/api/{ => cpp}/src/request_handler_tcp.cpp (100%)
 rename producer/api/{ => cpp}/src/request_handler_tcp.h (100%)
 rename producer/api/{ => cpp}/unittests/mocking.h (100%)
 rename producer/api/{ => cpp}/unittests/test_producer.cpp (87%)
 rename producer/api/{ => cpp}/unittests/test_producer_impl.cpp (100%)
 rename producer/api/{ => cpp}/unittests/test_producer_request.cpp (100%)
 rename producer/api/{ => cpp}/unittests/test_receiver_discovery_service.cpp (100%)
 rename producer/api/{ => cpp}/unittests/test_request_handler_factory.cpp (100%)
 rename producer/api/{ => cpp}/unittests/test_request_handler_filesystem.cpp (100%)
 rename producer/api/{ => cpp}/unittests/test_request_handler_tcp.cpp (100%)
 create mode 100644 producer/api/python/CMakeLists.txt
 create mode 100644 producer/api/python/CMakeLists_Linux.cmake
 create mode 100644 producer/api/python/CMakeLists_Windows.cmake
 create mode 100644 producer/api/python/asapo_producer.pxd
 create mode 100644 producer/api/python/asapo_producer.pyx.in
 create mode 100644 producer/api/python/asapo_wrappers.h
 create mode 100644 producer/api/python/binary_dist_windows/CMakeLists.txt
 create mode 100644 producer/api/python/binary_dist_windows/setup.py.in
 create mode 100644 producer/api/python/cythonize.py
 create mode 100644 producer/api/python/setup.py.in
 create mode 100644 producer/api/python/source_dist_linux/CMakeLists.txt
 create mode 100644 producer/api/python/source_dist_linux/MANIFEST.in
 create mode 100644 producer/api/python/source_dist_linux/setup.py.in
 create mode 100755 tests/manual/python_tests/producer/run.sh
 create mode 100644 tests/manual/python_tests/producer/test.py

diff --git a/README.md b/README.md
index 6ce92cb59..26e8f8c69 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
  
  **Library:** Common library which get shared between the producer and receiver 
  
- - /producer/producer-api
+ - /producer/asapo-producer
  
  **Library:** ProducerImpl library which can send data to the receiver
  
diff --git a/config/bamboo/bamboo.java b/config/bamboo/bamboo.java
index df6225a69..15b2429c6 100644
--- a/config/bamboo/bamboo.java
+++ b/config/bamboo/bamboo.java
@@ -77,7 +77,7 @@ public class PlanSpec {
                                 new Artifact()
                                     .name("Coverage-Producer")
                                     .copyPattern("**/*")
-                                    .location("build/coverage-producer-api"),
+                                    .location("build/coverage-asapo-producer"),
                                 new Artifact()
                                     .name("Coverage-Worker")
                                     .copyPattern("**/*")
diff --git a/examples/pipeline/in_to_out/CMakeLists.txt b/examples/pipeline/in_to_out/CMakeLists.txt
index a7bfa9e71..d8579506c 100644
--- a/examples/pipeline/in_to_out/CMakeLists.txt
+++ b/examples/pipeline/in_to_out/CMakeLists.txt
@@ -2,7 +2,7 @@ set(TARGET_NAME pipeline_inout)
 set(SOURCE_FILES in_to_out.cpp)
 
 add_executable(${TARGET_NAME} ${SOURCE_FILES})
-target_link_libraries(${TARGET_NAME} asapo-worker producer-api)
+target_link_libraries(${TARGET_NAME} asapo-worker asapo-producer)
 
 #use expression generator to get rid of VS adding Debug/Release folders
 set_target_properties(${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY
diff --git a/examples/producer/dummy-data-producer/CMakeLists.txt b/examples/producer/dummy-data-producer/CMakeLists.txt
index 5fda57ae7..c0d81a32f 100644
--- a/examples/producer/dummy-data-producer/CMakeLists.txt
+++ b/examples/producer/dummy-data-producer/CMakeLists.txt
@@ -10,7 +10,7 @@ target_include_directories(${TARGET_NAME} PUBLIC include ${CMAKE_SOURCE_DIR}/com
 GET_PROPERTY(ASAPO_COMMON_IO_LIBRARIES GLOBAL PROPERTY ASAPO_COMMON_IO_LIBRARIES)
 target_link_libraries(${TARGET_NAME} ${ASAPO_COMMON_IO_LIBRARIES})
 
-target_link_libraries(${TARGET_NAME} producer-api)
+target_link_libraries(${TARGET_NAME} asapo-producer)
 set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
 
 set_target_properties(${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY
diff --git a/examples/producer/dummy-data-producer/CMakeLists_separate.in b/examples/producer/dummy-data-producer/CMakeLists_separate.in
index f0b390f03..a8bdf4615 100644
--- a/examples/producer/dummy-data-producer/CMakeLists_separate.in
+++ b/examples/producer/dummy-data-producer/CMakeLists_separate.in
@@ -18,4 +18,4 @@ link_directories(@CMAKE_INSTALL_PREFIX@/lib)
 
 add_executable(${TARGET_NAME} ${SOURCE_FILES})
 target_include_directories(${TARGET_NAME} PUBLIC @CMAKE_INSTALL_PREFIX@/include)
-target_link_libraries(${TARGET_NAME} producer-api ${CMAKE_THREAD_LIBS_INIT})
+target_link_libraries(${TARGET_NAME} asapo-producer ${CMAKE_THREAD_LIBS_INIT})
diff --git a/producer/CMakeLists.txt b/producer/CMakeLists.txt
index 5f5aaa937..62ecdca0c 100644
--- a/producer/CMakeLists.txt
+++ b/producer/CMakeLists.txt
@@ -1,2 +1,4 @@
-add_subdirectory(api)
+add_subdirectory(api/cpp)
+add_subdirectory(api/python)
+
 add_subdirectory(event_monitor_producer)
diff --git a/producer/api/README.md b/producer/api/README.md
deleted file mode 100644
index 50ff42695..000000000
--- a/producer/api/README.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# cpp-producer
-
-This is the producer implementation in c++
-
-## Building this project
-
-### Requirements
-
-#### System
- - Linux Kernel >= 4
-
-#### Build Dependencies
- - cmake4
-
-##### Optional
- - astyle
- - doxygen
-
-### How to build
-
- - TODO
-
diff --git a/producer/api/CMakeLists.txt b/producer/api/cpp/CMakeLists.txt
similarity index 97%
rename from producer/api/CMakeLists.txt
rename to producer/api/cpp/CMakeLists.txt
index 86d882adc..896c05265 100644
--- a/producer/api/CMakeLists.txt
+++ b/producer/api/cpp/CMakeLists.txt
@@ -1,4 +1,4 @@
-set(TARGET_NAME producer-api)
+set(TARGET_NAME asapo-producer)
 set(SOURCE_FILES
         src/producer.cpp
         src/producer_impl.cpp
diff --git a/producer/api/include/asapo_producer.h b/producer/api/cpp/include/asapo_producer.h
similarity index 100%
rename from producer/api/include/asapo_producer.h
rename to producer/api/cpp/include/asapo_producer.h
diff --git a/producer/api/include/producer/common.h b/producer/api/cpp/include/producer/common.h
similarity index 100%
rename from producer/api/include/producer/common.h
rename to producer/api/cpp/include/producer/common.h
diff --git a/producer/api/include/producer/producer.h b/producer/api/cpp/include/producer/producer.h
similarity index 100%
rename from producer/api/include/producer/producer.h
rename to producer/api/cpp/include/producer/producer.h
diff --git a/producer/api/include/producer/producer_error.h b/producer/api/cpp/include/producer/producer_error.h
similarity index 100%
rename from producer/api/include/producer/producer_error.h
rename to producer/api/cpp/include/producer/producer_error.h
diff --git a/producer/api/src/producer.cpp b/producer/api/cpp/src/producer.cpp
similarity index 79%
rename from producer/api/src/producer.cpp
rename to producer/api/cpp/src/producer.cpp
index bc308be85..c219c7ca7 100644
--- a/producer/api/src/producer.cpp
+++ b/producer/api/cpp/src/producer.cpp
@@ -3,8 +3,9 @@
 
 std::unique_ptr<asapo::Producer> asapo::Producer::Create(const std::string& endpoint, uint8_t n_processing_threads,
         asapo::RequestHandlerType type, SourceCredentials source_cred, Error* err) {
-    if (n_processing_threads > kMaxProcessingThreads) {
-        *err = TextError("Too many processing threads: " + std::to_string(n_processing_threads));
+
+    if (n_processing_threads > kMaxProcessingThreads || n_processing_threads == 0) {
+        *err = TextError("Set number of processing threads > 0 and <= " + std::to_string(kMaxProcessingThreads));
         return nullptr;
     }
 
diff --git a/producer/api/src/producer_impl.cpp b/producer/api/cpp/src/producer_impl.cpp
similarity index 100%
rename from producer/api/src/producer_impl.cpp
rename to producer/api/cpp/src/producer_impl.cpp
diff --git a/producer/api/src/producer_impl.h b/producer/api/cpp/src/producer_impl.h
similarity index 100%
rename from producer/api/src/producer_impl.h
rename to producer/api/cpp/src/producer_impl.h
diff --git a/producer/api/src/producer_logger.cpp b/producer/api/cpp/src/producer_logger.cpp
similarity index 100%
rename from producer/api/src/producer_logger.cpp
rename to producer/api/cpp/src/producer_logger.cpp
diff --git a/producer/api/src/producer_logger.h b/producer/api/cpp/src/producer_logger.h
similarity index 100%
rename from producer/api/src/producer_logger.h
rename to producer/api/cpp/src/producer_logger.h
diff --git a/producer/api/src/producer_request.cpp b/producer/api/cpp/src/producer_request.cpp
similarity index 100%
rename from producer/api/src/producer_request.cpp
rename to producer/api/cpp/src/producer_request.cpp
diff --git a/producer/api/src/producer_request.h b/producer/api/cpp/src/producer_request.h
similarity index 100%
rename from producer/api/src/producer_request.h
rename to producer/api/cpp/src/producer_request.h
diff --git a/producer/api/src/producer_request_handler_factory.h b/producer/api/cpp/src/producer_request_handler_factory.h
similarity index 100%
rename from producer/api/src/producer_request_handler_factory.h
rename to producer/api/cpp/src/producer_request_handler_factory.h
diff --git a/producer/api/src/receiver_data_server_request_handler_factory.cpp b/producer/api/cpp/src/receiver_data_server_request_handler_factory.cpp
similarity index 100%
rename from producer/api/src/receiver_data_server_request_handler_factory.cpp
rename to producer/api/cpp/src/receiver_data_server_request_handler_factory.cpp
diff --git a/producer/api/src/receiver_discovery_service.cpp b/producer/api/cpp/src/receiver_discovery_service.cpp
similarity index 100%
rename from producer/api/src/receiver_discovery_service.cpp
rename to producer/api/cpp/src/receiver_discovery_service.cpp
diff --git a/producer/api/src/receiver_discovery_service.h b/producer/api/cpp/src/receiver_discovery_service.h
similarity index 100%
rename from producer/api/src/receiver_discovery_service.h
rename to producer/api/cpp/src/receiver_discovery_service.h
diff --git a/producer/api/src/request_handler_filesystem.cpp b/producer/api/cpp/src/request_handler_filesystem.cpp
similarity index 100%
rename from producer/api/src/request_handler_filesystem.cpp
rename to producer/api/cpp/src/request_handler_filesystem.cpp
diff --git a/producer/api/src/request_handler_filesystem.h b/producer/api/cpp/src/request_handler_filesystem.h
similarity index 100%
rename from producer/api/src/request_handler_filesystem.h
rename to producer/api/cpp/src/request_handler_filesystem.h
diff --git a/producer/api/src/request_handler_tcp.cpp b/producer/api/cpp/src/request_handler_tcp.cpp
similarity index 100%
rename from producer/api/src/request_handler_tcp.cpp
rename to producer/api/cpp/src/request_handler_tcp.cpp
diff --git a/producer/api/src/request_handler_tcp.h b/producer/api/cpp/src/request_handler_tcp.h
similarity index 100%
rename from producer/api/src/request_handler_tcp.h
rename to producer/api/cpp/src/request_handler_tcp.h
diff --git a/producer/api/unittests/mocking.h b/producer/api/cpp/unittests/mocking.h
similarity index 100%
rename from producer/api/unittests/mocking.h
rename to producer/api/cpp/unittests/mocking.h
diff --git a/producer/api/unittests/test_producer.cpp b/producer/api/cpp/unittests/test_producer.cpp
similarity index 87%
rename from producer/api/unittests/test_producer.cpp
rename to producer/api/cpp/unittests/test_producer.cpp
index 134691656..11359b693 100644
--- a/producer/api/unittests/test_producer.cpp
+++ b/producer/api/cpp/unittests/test_producer.cpp
@@ -49,6 +49,16 @@ TEST(CreateProducer, TooManyThreads) {
     ASSERT_THAT(err, Ne(nullptr));
 }
 
+
+TEST(CreateProducer, ZeroThreads) {
+    asapo::Error err;
+    std::unique_ptr<asapo::Producer> producer = asapo::Producer::Create("", 0,
+                                                                        asapo::RequestHandlerType::kTcp, SourceCredentials{"bt", "", ""}, &err);
+    ASSERT_THAT(producer, Eq(nullptr));
+    ASSERT_THAT(err, Ne(nullptr));
+}
+
+
 TEST(Producer, SimpleWorkflowWihoutConnection) {
     asapo::Error err;
     std::unique_ptr<asapo::Producer> producer = asapo::Producer::Create("hello", 5, asapo::RequestHandlerType::kTcp,
diff --git a/producer/api/unittests/test_producer_impl.cpp b/producer/api/cpp/unittests/test_producer_impl.cpp
similarity index 100%
rename from producer/api/unittests/test_producer_impl.cpp
rename to producer/api/cpp/unittests/test_producer_impl.cpp
diff --git a/producer/api/unittests/test_producer_request.cpp b/producer/api/cpp/unittests/test_producer_request.cpp
similarity index 100%
rename from producer/api/unittests/test_producer_request.cpp
rename to producer/api/cpp/unittests/test_producer_request.cpp
diff --git a/producer/api/unittests/test_receiver_discovery_service.cpp b/producer/api/cpp/unittests/test_receiver_discovery_service.cpp
similarity index 100%
rename from producer/api/unittests/test_receiver_discovery_service.cpp
rename to producer/api/cpp/unittests/test_receiver_discovery_service.cpp
diff --git a/producer/api/unittests/test_request_handler_factory.cpp b/producer/api/cpp/unittests/test_request_handler_factory.cpp
similarity index 100%
rename from producer/api/unittests/test_request_handler_factory.cpp
rename to producer/api/cpp/unittests/test_request_handler_factory.cpp
diff --git a/producer/api/unittests/test_request_handler_filesystem.cpp b/producer/api/cpp/unittests/test_request_handler_filesystem.cpp
similarity index 100%
rename from producer/api/unittests/test_request_handler_filesystem.cpp
rename to producer/api/cpp/unittests/test_request_handler_filesystem.cpp
diff --git a/producer/api/unittests/test_request_handler_tcp.cpp b/producer/api/cpp/unittests/test_request_handler_tcp.cpp
similarity index 100%
rename from producer/api/unittests/test_request_handler_tcp.cpp
rename to producer/api/cpp/unittests/test_request_handler_tcp.cpp
diff --git a/producer/api/python/CMakeLists.txt b/producer/api/python/CMakeLists.txt
new file mode 100644
index 000000000..1d8e59157
--- /dev/null
+++ b/producer/api/python/CMakeLists.txt
@@ -0,0 +1,17 @@
+
+if (UNIX)
+    include(CMakeLists_Linux.cmake)
+    set (suf "so")
+ELSEIF(CMAKE_BUILD_TYPE STREQUAL "Release")
+    set (suf "pyd")
+    include(CMakeLists_Windows.cmake)
+ENDIF()
+
+install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/ DESTINATION lib/python/
+        FILES_MATCHING PATTERN "*.${suf}"
+        PATTERN "build" EXCLUDE
+        PATTERN "source_dist_linux" EXCLUDE
+        PATTERN "binary_dist_windows" EXCLUDE
+        PATTERN "CMakeFiles" EXCLUDE
+        )
+
diff --git a/producer/api/python/CMakeLists_Linux.cmake b/producer/api/python/CMakeLists_Linux.cmake
new file mode 100644
index 000000000..f01baa6ec
--- /dev/null
+++ b/producer/api/python/CMakeLists_Linux.cmake
@@ -0,0 +1,27 @@
+if ((CMAKE_BUILD_TYPE STREQUAL "Debug") AND (CMAKE_C_COMPILER_ID STREQUAL "GNU"))
+    set (EXTRA_COMPILE_ARGS "['--std=c++11']")
+    set (EXTRA_LINK_ARGS "['--coverage','-fprofile-arcs','-ftest-coverage','-static-libgcc','-static-libstdc++']")
+ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+    set (EXTRA_COMPILE_ARGS "['--std=c++11']")
+    set (EXTRA_LINK_ARGS "['-static-libgcc','-static-libstdc++']")
+else()
+    set (EXTRA_COMPILE_ARGS "['-std=c++11']")
+    set (EXTRA_LINK_ARGS "[]")
+ENDIF()
+
+get_property(ASAPO_PRODUCER_LIB TARGET asapo-producer PROPERTY LOCATION)
+
+set (ASAPO_PRODUCER_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../cpp/include)
+
+configure_files(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} @ONLY)
+
+ADD_CUSTOM_TARGET(python-lib2-producer ALL
+        COMMAND python setup.py build_ext --inplace)
+
+ADD_CUSTOM_TARGET(python-lib3-producer ALL
+        COMMAND python3 setup.py build_ext --inplace)
+
+ADD_DEPENDENCIES(python-lib2-producer asapo-producer)
+ADD_DEPENDENCIES(python-lib3-producer asapo-producer)
+
+add_subdirectory(source_dist_linux)
diff --git a/producer/api/python/CMakeLists_Windows.cmake b/producer/api/python/CMakeLists_Windows.cmake
new file mode 100644
index 000000000..95dd07a0d
--- /dev/null
+++ b/producer/api/python/CMakeLists_Windows.cmake
@@ -0,0 +1,30 @@
+configure_files(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} @ONLY)
+
+find_package (Python3 REQUIRED COMPONENTS Development)
+find_package (Numpy REQUIRED)
+message ("   Python libaries:" ${Python3_LIBRARIES})
+message ("   Python includes:" ${Python3_INCLUDE_DIRS})
+message ("   Numpy:" ${PYTHON_NUMPY_INCLUDE_DIR})
+
+
+add_custom_command(OUTPUT asapo_worker.cpp
+        COMMAND ${Python3_EXECUTABLE} cythonize.py
+        DEPENDS asapo-producer)
+
+
+set(TARGET_NAME asapo_worker)
+
+set(SOURCE_FILES
+        asapo_worker.cpp)
+
+add_library(${TARGET_NAME} SHARED ${SOURCE_FILES})
+set_target_properties(${TARGET_NAME} PROPERTIES SUFFIX ".pyd")
+set_target_properties(${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY
+        ${CMAKE_CURRENT_BINARY_DIR}$<$<CONFIG:Debug>:>
+        )
+
+target_link_libraries(${TARGET_NAME}  asapo-producer ${Python3_LIBRARIES})
+target_include_directories(${TARGET_NAME} PUBLIC include  ${Python3_INCLUDE_DIRS} ${PYTHON_NUMPY_INCLUDE_DIR})
+
+
+add_subdirectory(binary_dist_windows)
diff --git a/producer/api/python/asapo_producer.pxd b/producer/api/python/asapo_producer.pxd
new file mode 100644
index 000000000..a35d824a1
--- /dev/null
+++ b/producer/api/python/asapo_producer.pxd
@@ -0,0 +1,39 @@
+from libcpp.memory cimport unique_ptr
+from libcpp.string cimport string
+from libcpp.vector cimport vector
+from libcpp cimport bool
+
+ctypedef unsigned char uint8_t
+ctypedef unsigned long uint64_t
+
+cdef extern from "asapo_producer.h" namespace "asapo":
+  cppclass Error:
+    pass
+
+
+cdef extern from "asapo_wrappers.h" namespace "asapo":
+  cdef string GetErrorString(Error* err)
+
+
+cdef extern from "asapo_producer.h" namespace "asapo":
+  cppclass FileData:
+    unique_ptr[uint8_t[]] release()
+
+
+cdef extern from "asapo_producer.h" namespace "asapo":
+  cppclass RequestHandlerType:
+    pass
+  cdef RequestHandlerType RequestHandlerType_Tcp "asapo::RequestHandlerType::kTcp"
+
+
+
+cdef extern from "asapo_producer.h" namespace "asapo":
+  struct  SourceCredentials:
+    string beamtime_id
+    string stream
+    string user_token
+
+cdef extern from "asapo_producer.h" namespace "asapo":
+    cdef cppclass Producer:
+        @staticmethod
+        unique_ptr[Producer] Create(string endpoint,uint8_t nthreads,RequestHandlerType type, SourceCredentials source,Error* error)
diff --git a/producer/api/python/asapo_producer.pyx.in b/producer/api/python/asapo_producer.pyx.in
new file mode 100644
index 000000000..ca839ce12
--- /dev/null
+++ b/producer/api/python/asapo_producer.pyx.in
@@ -0,0 +1,51 @@
+#distutils: language=c++
+
+cimport asapo_producer
+import numpy as np
+cimport numpy as np
+import json
+from cpython.version cimport PY_MAJOR_VERSION
+from libcpp.memory cimport unique_ptr
+
+np.import_array()
+
+cdef extern from "numpy/ndarraytypes.h":
+    void PyArray_ENABLEFLAGS(np.ndarray arr, int flags)
+
+cdef str _str(b):
+    if PY_MAJOR_VERSION < 3:
+        return b
+    return b.decode("utf-8")
+
+cdef bytes _bytes(s):
+    if type(s) is bytes:
+        return s
+
+    elif isinstance(s, unicode):
+        return (<unicode>s).encode('utf-8')
+
+    else:
+        raise TypeError("Could not convert to unicode.")
+
+cdef class PyProducer:
+    cdef unique_ptr[Producer] c_producer
+    @staticmethod
+    def create_producer(endpoint,beamtime_id,stream,token,nthreads):
+        pyProd = PyProducer()
+        cdef Error err
+        cdef SourceCredentials source
+        source.beamtime_id = beamtime_id
+        source.user_token = token
+        source.stream = stream
+        pyProd.c_producer = Producer.Create(endpoint,nthreads,RequestHandlerType_Tcp,source,&err)
+        cdef err_str = GetErrorString(&err)
+        if err_str.strip():
+            return None,err_str
+        else:
+            return pyProd,None
+
+def create_producer(endpoint,beamtime_id,stream,token,nthreads):
+    return PyProducer.create_producer(_bytes(endpoint),_bytes(beamtime_id),_bytes(stream),_bytes(token),nthreads)
+
+
+__version__ = "@ASAPO_VERSION_PYTHON@"
diff --git a/producer/api/python/asapo_wrappers.h b/producer/api/python/asapo_wrappers.h
new file mode 100644
index 000000000..c59b8d8c7
--- /dev/null
+++ b/producer/api/python/asapo_wrappers.h
@@ -0,0 +1,16 @@
+#ifndef ASAPO_ASAPO_WRAPPERS_H
+#define ASAPO_ASAPO_WRAPPERS_H
+
+namespace asapo {
+
+inline std::string GetErrorString(asapo::Error* err) {
+    if (*err) {
+        return (*err)->Explain();
+    }
+    return "";
+}
+
+}
+
+
+#endif //ASAPO_ASAPO_WRAPPERS_H
diff --git a/producer/api/python/binary_dist_windows/CMakeLists.txt b/producer/api/python/binary_dist_windows/CMakeLists.txt
new file mode 100644
index 000000000..ac46814f2
--- /dev/null
+++ b/producer/api/python/binary_dist_windows/CMakeLists.txt
@@ -0,0 +1,16 @@
+configure_file(setup.py.in setup.py @ONLY)
+
+ADD_CUSTOM_TARGET(windows-bdist ALL
+        COMMAND ${Python3_EXECUTABLE} setup.py bdist_wheel
+        )
+
+
+ADD_CUSTOM_TARGET(copy_python_bdist ALL
+        COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/asapo_worker
+        COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:asapo_worker> ${CMAKE_CURRENT_BINARY_DIR}/asapo_worker/
+        )
+
+
+ADD_DEPENDENCIES(copy_python_bdist asapo_worker)
+
+ADD_DEPENDENCIES(windows-bdist copy_python_bdist)
diff --git a/producer/api/python/binary_dist_windows/setup.py.in b/producer/api/python/binary_dist_windows/setup.py.in
new file mode 100644
index 000000000..cc896317e
--- /dev/null
+++ b/producer/api/python/binary_dist_windows/setup.py.in
@@ -0,0 +1,12 @@
+import setuptools
+
+setuptools.setup(
+      name ="asapo_worker",
+      version = "@ASAPO_VERSION_PYTHON@",
+      install_requires=['numpy'],
+      include_package_data=True,
+      packages=['asapo_worker'],
+      package_data={
+        'asapo_worker': ['asapo_worker.pyd'],
+      },
+)
diff --git a/producer/api/python/cythonize.py b/producer/api/python/cythonize.py
new file mode 100644
index 000000000..0e517258f
--- /dev/null
+++ b/producer/api/python/cythonize.py
@@ -0,0 +1,3 @@
+from Cython.Build import cythonize
+
+cythonize(["asapo_producer.pyx"])
diff --git a/producer/api/python/setup.py.in b/producer/api/python/setup.py.in
new file mode 100644
index 000000000..b4ae7777e
--- /dev/null
+++ b/producer/api/python/setup.py.in
@@ -0,0 +1,19 @@
+from distutils.core import setup
+from distutils.core import Extension
+
+from Cython.Build import cythonize
+
+import numpy
+
+module = Extension("asapo_producer", ["asapo_producer.pyx"],
+                       extra_objects=['@ASAPO_PRODUCER_LIB@',
+                                      '@CURL_LIBRARIES@'],
+                       include_dirs=["@ASAPO_CXX_COMMON_INCLUDE_DIR@","@ASAPO_PRODUCER_INCLUDE_DIR@",numpy.get_include()],
+                       extra_compile_args=@EXTRA_COMPILE_ARGS@,
+                       extra_link_args=@EXTRA_LINK_ARGS@,
+                       language="c++",
+         )
+
+ext_modules = cythonize([module])
+
+setup(ext_modules = ext_modules)
diff --git a/producer/api/python/source_dist_linux/CMakeLists.txt b/producer/api/python/source_dist_linux/CMakeLists.txt
new file mode 100644
index 000000000..48fe09828
--- /dev/null
+++ b/producer/api/python/source_dist_linux/CMakeLists.txt
@@ -0,0 +1,26 @@
+configure_file(setup.py.in setup.py @ONLY)
+configure_file(MANIFEST.in MANIFEST.in @ONLY)
+
+
+ADD_CUSTOM_TARGET(python-dist ALL
+        COMMAND python setup.py sdist
+        )
+
+#get_property(ASAPO_WORKER_LIB TARGET asapo-worker PROPERTY LOCATION)
+
+ADD_CUSTOM_TARGET(copy_python_dist ALL
+        COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/../asapo_wrappers.h ${CMAKE_CURRENT_BINARY_DIR}/.
+        COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/../asapo_worker.cpp ${CMAKE_CURRENT_BINARY_DIR}/.
+        COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/worker/api/cpp/include ${CMAKE_CURRENT_BINARY_DIR}/include
+        COMMAND ${CMAKE_COMMAND} -E copy_directory ${ASAPO_CXX_COMMON_INCLUDE_DIR}/common ${CMAKE_CURRENT_BINARY_DIR}/include/common
+        COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_CURRENT_BINARY_DIR}/include/common/version.h.in
+        COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/lib
+        COMMAND ${CMAKE_COMMAND} -E copy ${CURL_LIBRARIES} ${CMAKE_CURRENT_BINARY_DIR}/lib
+        COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:asapo-worker> ${CMAKE_CURRENT_BINARY_DIR}/lib
+
+        )
+
+
+ADD_DEPENDENCIES(copy_python_dist python-lib3)
+
+ADD_DEPENDENCIES(python-dist copy_python_dist)
diff --git a/producer/api/python/source_dist_linux/MANIFEST.in b/producer/api/python/source_dist_linux/MANIFEST.in
new file mode 100644
index 000000000..89f5fc054
--- /dev/null
+++ b/producer/api/python/source_dist_linux/MANIFEST.in
@@ -0,0 +1,3 @@
+include asapo_wrappers.h
+recursive-include include *
+recursive-include lib *
\ No newline at end of file
diff --git a/producer/api/python/source_dist_linux/setup.py.in b/producer/api/python/source_dist_linux/setup.py.in
new file mode 100644
index 000000000..9fc10832c
--- /dev/null
+++ b/producer/api/python/source_dist_linux/setup.py.in
@@ -0,0 +1,22 @@
+from distutils.core import setup
+from distutils.core import Extension
+import numpy
+
+ext_modules = [
+    Extension("asapo_worker", ["asapo_worker.cpp"],
+              extra_objects=['lib/libasapo-worker.a'],
+					   libraries = ['curl'],
+                       include_dirs=["include/common","include",numpy.get_include()],
+                       extra_compile_args=@EXTRA_COMPILE_ARGS@,
+                       extra_link_args=@EXTRA_LINK_ARGS@,
+                       language="c++")
+]
+
+setup(
+      name ="asapo_worker",
+      ext_modules = ext_modules,
+      version = "@ASAPO_VERSION_PYTHON@",
+      setup_requires=["numpy"],
+      install_requires=["numpy"],
+      platforms=["aaa"]
+      )
diff --git a/producer/event_monitor_producer/CMakeLists.txt b/producer/event_monitor_producer/CMakeLists.txt
index cebdbdb98..9eea80923 100644
--- a/producer/event_monitor_producer/CMakeLists.txt
+++ b/producer/event_monitor_producer/CMakeLists.txt
@@ -31,7 +31,7 @@ target_include_directories(${TARGET_NAME} PUBLIC include ${CMAKE_SOURCE_DIR}/com
 GET_PROPERTY(ASAPO_COMMON_IO_LIBRARIES GLOBAL PROPERTY ASAPO_COMMON_IO_LIBRARIES)
 target_link_libraries(${TARGET_NAME} ${ASAPO_COMMON_IO_LIBRARIES})
 
-target_link_libraries(${TARGET_NAME} producer-api)
+target_link_libraries(${TARGET_NAME} asapo-producer)
 
 ################################
 # Executable
diff --git a/tests/automatic/producer/beamtime_metadata/CMakeLists.txt b/tests/automatic/producer/beamtime_metadata/CMakeLists.txt
index fd4455816..a8733d4ce 100644
--- a/tests/automatic/producer/beamtime_metadata/CMakeLists.txt
+++ b/tests/automatic/producer/beamtime_metadata/CMakeLists.txt
@@ -8,7 +8,7 @@ target_include_directories(${TARGET_NAME} PUBLIC include ${CMAKE_SOURCE_DIR}/com
 
 #Add all necessary common libraries
 #GET_PROPERTY(ASAPO_COMMON_IO_LIBRARIES GLOBAL PROPERTY ASAPO_COMMON_IO_LIBRARIES)
-target_link_libraries(${TARGET_NAME} ${ASAPO_COMMON_IO_LIBRARIES} producer-api)
+target_link_libraries(${TARGET_NAME} ${ASAPO_COMMON_IO_LIBRARIES} asapo-producer)
 
 
 #set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
diff --git a/tests/manual/python_tests/producer/run.sh b/tests/manual/python_tests/producer/run.sh
new file mode 100755
index 000000000..52c6aec88
--- /dev/null
+++ b/tests/manual/python_tests/producer/run.sh
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+export PYTHONPATH=/home/yakubov/projects/asapo/cmake-build-debug/producer/api/python:${PYTHONPATH}
+
+python test.py
diff --git a/tests/manual/python_tests/producer/test.py b/tests/manual/python_tests/producer/test.py
new file mode 100644
index 000000000..a1c1abd58
--- /dev/null
+++ b/tests/manual/python_tests/producer/test.py
@@ -0,0 +1,20 @@
+from __future__ import print_function
+
+import asapo_producer
+import sys
+import json
+import time
+
+endpoint = "psana002:8400"
+beamtime = "asapo_test1"
+stream = "stream"
+token = ""
+nthreads = 1
+
+producer, err = asapo_producer.create_producer(endpoint,beamtime, stream, token, nthreads)
+
+if err is not None:
+    print(err)
+else:
+    print(producer)
+
diff --git a/worker/api/python/binary_dist_windows/CMakeLists.txt b/worker/api/python/binary_dist_windows/CMakeLists.txt
index ac46814f2..de6a95e2c 100644
--- a/worker/api/python/binary_dist_windows/CMakeLists.txt
+++ b/worker/api/python/binary_dist_windows/CMakeLists.txt
@@ -1,16 +1,16 @@
 configure_file(setup.py.in setup.py @ONLY)
 
-ADD_CUSTOM_TARGET(windows-bdist ALL
+ADD_CUSTOM_TARGET(windows-bdist-producer ALL
         COMMAND ${Python3_EXECUTABLE} setup.py bdist_wheel
         )
 
 
-ADD_CUSTOM_TARGET(copy_python_bdist ALL
-        COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/asapo_worker
-        COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:asapo_worker> ${CMAKE_CURRENT_BINARY_DIR}/asapo_worker/
+ADD_CUSTOM_TARGET(copy_python_bdist_producer ALL
+        COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/asapo_producer
+        COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:asapo_producer> ${CMAKE_CURRENT_BINARY_DIR}/asapo_producer/
         )
 
 
-ADD_DEPENDENCIES(copy_python_bdist asapo_worker)
+ADD_DEPENDENCIES(copy_python_bdist_producer asapo_producer)
 
-ADD_DEPENDENCIES(windows-bdist copy_python_bdist)
+ADD_DEPENDENCIES(windows-bdist-producer copy_python_bdist_producer)
diff --git a/worker/api/python/source_dist_linux/CMakeLists.txt b/worker/api/python/source_dist_linux/CMakeLists.txt
index 48fe09828..83b420eee 100644
--- a/worker/api/python/source_dist_linux/CMakeLists.txt
+++ b/worker/api/python/source_dist_linux/CMakeLists.txt
@@ -2,13 +2,13 @@ configure_file(setup.py.in setup.py @ONLY)
 configure_file(MANIFEST.in MANIFEST.in @ONLY)
 
 
-ADD_CUSTOM_TARGET(python-dist ALL
+ADD_CUSTOM_TARGET(python-dist-producer ALL
         COMMAND python setup.py sdist
         )
 
 #get_property(ASAPO_WORKER_LIB TARGET asapo-worker PROPERTY LOCATION)
 
-ADD_CUSTOM_TARGET(copy_python_dist ALL
+ADD_CUSTOM_TARGET(copy_python_dist_producer ALL
         COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/../asapo_wrappers.h ${CMAKE_CURRENT_BINARY_DIR}/.
         COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/../asapo_worker.cpp ${CMAKE_CURRENT_BINARY_DIR}/.
         COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/worker/api/cpp/include ${CMAKE_CURRENT_BINARY_DIR}/include
@@ -21,6 +21,6 @@ ADD_CUSTOM_TARGET(copy_python_dist ALL
         )
 
 
-ADD_DEPENDENCIES(copy_python_dist python-lib3)
+ADD_DEPENDENCIES(copy_python_dist_producer python-lib3-producer)
 
-ADD_DEPENDENCIES(python-dist copy_python_dist)
+ADD_DEPENDENCIES(python-dist-producer copy_python_dist_producer)
-- 
GitLab