You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by wi...@apache.org on 2020/07/19 13:10:13 UTC

[incubator-streampipes] branch dev updated: [STREAMPIPES-174] Port current POC to core repository

This is an automated email from the ASF dual-hosted git repository.

wiener pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git


The following commit(s) were added to refs/heads/dev by this push:
     new 3b9ed0c  [STREAMPIPES-174] Port current POC to core repository
3b9ed0c is described below

commit 3b9ed0c5675f39db88d5d0477c6304a8701d0944
Author: Patrick Wiener <wi...@fzi.de>
AuthorDate: Sun Jul 19 15:09:50 2020 +0200

    [STREAMPIPES-174] Port current POC to core repository
---
 .gitignore                                         |   7 +
 pom.xml                                            |   1 +
 streampipes-wrapper-python/LICENSE                 | 201 +++++++++++++++++++++
 streampipes-wrapper-python/NOTICE                  |   7 +
 streampipes-wrapper-python/README.md               |  44 +++++
 .../apache_streampipes_python.egg-info/PKG-INFO    |  60 ++++++
 .../apache_streampipes_python.egg-info/SOURCES.txt |  15 ++
 .../dependency_links.txt                           |   1 +
 .../requires.txt                                   |   3 +
 .../top_level.txt                                  |   1 +
 streampipes-wrapper-python/build-distribution.sh   |  38 ++++
 streampipes-wrapper-python/pom.xml                 |  15 ++
 streampipes-wrapper-python/requirements.txt        |   8 +
 streampipes-wrapper-python/setup.py                |  52 ++++++
 streampipes-wrapper-python/streampipes/__init__.py |  23 +++
 streampipes-wrapper-python/streampipes/api.py      |  70 +++++++
 .../streampipes/configuration.py                   |  31 ++++
 streampipes-wrapper-python/streampipes/core.py     | 182 +++++++++++++++++++
 streampipes-wrapper-python/streampipes/helper.py   |  28 +++
 streampipes-wrapper-python/streampipes/manager.py  |  72 ++++++++
 20 files changed, 859 insertions(+)

diff --git a/.gitignore b/.gitignore
index 1e0981e..c3c60ab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -143,3 +143,10 @@ logs/
 
 # Explicit includes
 !.idea/runConfigurations
+
+# Python
+venv
+*pyc
+dist/
+*whl
+__pycache__
diff --git a/pom.xml b/pom.xml
index a602ffe..4cdfcab 100644
--- a/pom.xml
+++ b/pom.xml
@@ -859,6 +859,7 @@
         <module>streampipes-wrapper-distributed</module>
         <module>streampipes-wrapper-flink</module>
         <module>streampipes-wrapper-kafka-streams</module>
+        <module>streampipes-wrapper-python</module>
         <module>streampipes-wrapper-siddhi</module>
         <module>streampipes-wrapper-spark</module>
         <module>streampipes-wrapper-standalone</module>
diff --git a/streampipes-wrapper-python/LICENSE b/streampipes-wrapper-python/LICENSE
new file mode 100644
index 0000000..56ee3c8
--- /dev/null
+++ b/streampipes-wrapper-python/LICENSE
@@ -0,0 +1,201 @@
+                                Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
\ No newline at end of file
diff --git a/streampipes-wrapper-python/NOTICE b/streampipes-wrapper-python/NOTICE
new file mode 100644
index 0000000..17b697e
--- /dev/null
+++ b/streampipes-wrapper-python/NOTICE
@@ -0,0 +1,7 @@
+Apache StreamPipes (incubating)
+Copyright 2020 The Apache Software Foundation.
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+============================================================================
\ No newline at end of file
diff --git a/streampipes-wrapper-python/README.md b/streampipes-wrapper-python/README.md
new file mode 100644
index 0000000..c5dccd8
--- /dev/null
+++ b/streampipes-wrapper-python/README.md
@@ -0,0 +1,44 @@
+# Apache StreamPipes Wrapper for Python
+
+**NOTE**: 
+
+THIS IS WIP. IT CURRENTLY ONLY WORKS IN INTERPLAY WITH A JAVA PROCESSOR IMPLEMENTING THE MODEL.
+
+### A minimal example
+#### Define a processor
+```
+from streampipes.core import EventProcessor
+
+
+class HelloWorldProcessor(EventProcessor):
+
+    def on_invocation(self):
+        pass
+
+    def on_event(self, event):
+        event['greeting'] = 'hello world'
+        return event
+
+    def on_detach(self):
+        pass
+```
+This processor received an event `dict` and adds a new `greeting` field including the message `hello world` to it.
+#### Add to processor dict
+````
+from streampipes.core import StandaloneSubmitter
+from streampipes.manager import Declarer
+
+
+def main():
+    processors = {
+        'org.apache.streampipes.processors.python.helloworld': HelloWorldProcessor,
+    }
+
+    Declarer.add(processors=processors)
+    StandaloneSubmitter.init()
+
+
+if __name__ == '__main__':
+    main()
+````
+Add the newly defined `HelloWorldProcessor` to the processors dictionary including a unique id `org.apache.streampipes.processors.python.helloworld`.
diff --git a/streampipes-wrapper-python/apache_streampipes_python.egg-info/PKG-INFO b/streampipes-wrapper-python/apache_streampipes_python.egg-info/PKG-INFO
new file mode 100644
index 0000000..a34a2c1
--- /dev/null
+++ b/streampipes-wrapper-python/apache_streampipes_python.egg-info/PKG-INFO
@@ -0,0 +1,60 @@
+Metadata-Version: 2.1
+Name: apache-streampipes-python
+Version: 0.67.0-SNAPSHOT
+Summary: Apache StreamPipes Python Wrapper
+Home-page: https://github.com/apache/incubator-streampipes
+Author: Apache Software Foundation
+Author-email: dev@streampipes.apache.org
+License: https://www.apache.org/licenses/LICENSE-2.0
+Description: # Apache StreamPipes Wrapper for Python
+        
+        **NOTE**: 
+        
+        THIS IS WIP. IT CURRENTLY ONLY WORKS IN INTERPLAY WITH A JAVA PROCESSOR IMPLEMENTING THE MODEL.
+        
+        ### A minimal example
+        #### Define a processor
+        ```
+        from streampipes.core import EventProcessor
+        
+        
+        class HelloWorldProcessor(EventProcessor):
+        
+            def on_invocation(self):
+                pass
+        
+            def on_event(self, event):
+                event['greeting'] = 'hello world'
+                return event
+        
+            def on_detach(self):
+                pass
+        ```
+        This processor received an event `dict` and adds a new `greeting` field including the message `hello world` to it.
+        #### Add to processor dict
+        ````
+        from streampipes.core import StandaloneSubmitter
+        from streampipes.manager import Declarer
+        
+        
+        def main():
+            processors = {
+                'org.apache.streampipes.processors.python.helloworld': HelloWorldProcessor,
+            }
+        
+            Declarer.add(processors=processors)
+            StandaloneSubmitter.init()
+        
+        
+        if __name__ == '__main__':
+            main()
+        ````
+        Add the newly defined `HelloWorldProcessor` to the processors dictionary including a unique id `org.apache.streampipes.processors.python.helloworld`.
+        
+Platform: UNKNOWN
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Requires-Python: >=3.5
+Description-Content-Type: text/markdown
diff --git a/streampipes-wrapper-python/apache_streampipes_python.egg-info/SOURCES.txt b/streampipes-wrapper-python/apache_streampipes_python.egg-info/SOURCES.txt
new file mode 100644
index 0000000..fe3801e
--- /dev/null
+++ b/streampipes-wrapper-python/apache_streampipes_python.egg-info/SOURCES.txt
@@ -0,0 +1,15 @@
+LICENSE
+NOTICE
+README.md
+setup.py
+apache_streampipes_python.egg-info/PKG-INFO
+apache_streampipes_python.egg-info/SOURCES.txt
+apache_streampipes_python.egg-info/dependency_links.txt
+apache_streampipes_python.egg-info/requires.txt
+apache_streampipes_python.egg-info/top_level.txt
+streampipes/__init__.py
+streampipes/api.py
+streampipes/configuration.py
+streampipes/core.py
+streampipes/helper.py
+streampipes/manager.py
\ No newline at end of file
diff --git a/streampipes-wrapper-python/apache_streampipes_python.egg-info/dependency_links.txt b/streampipes-wrapper-python/apache_streampipes_python.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/streampipes-wrapper-python/apache_streampipes_python.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/streampipes-wrapper-python/apache_streampipes_python.egg-info/requires.txt b/streampipes-wrapper-python/apache_streampipes_python.egg-info/requires.txt
new file mode 100644
index 0000000..cb526af
--- /dev/null
+++ b/streampipes-wrapper-python/apache_streampipes_python.egg-info/requires.txt
@@ -0,0 +1,3 @@
+confluent-kafka==1.4.2
+Flask==1.1.2
+waitress==1.4.4
diff --git a/streampipes-wrapper-python/apache_streampipes_python.egg-info/top_level.txt b/streampipes-wrapper-python/apache_streampipes_python.egg-info/top_level.txt
new file mode 100644
index 0000000..d919eee
--- /dev/null
+++ b/streampipes-wrapper-python/apache_streampipes_python.egg-info/top_level.txt
@@ -0,0 +1 @@
+streampipes
diff --git a/streampipes-wrapper-python/build-distribution.sh b/streampipes-wrapper-python/build-distribution.sh
new file mode 100755
index 0000000..32075a7
--- /dev/null
+++ b/streampipes-wrapper-python/build-distribution.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+CURR_DIR=`pwd`
+BASE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
+
+###########################
+
+cd ${BASE_DIR}
+
+rm -fr dist
+
+docker run \
+	-v "$BASE_DIR:/app" \
+	--workdir /app \
+	-i  python:3.7-alpine \
+	python3 setup.py sdist bdist_wheel
+
+rm -fr streampipes_python.egg-info
+rm -fr build
+
+echo "Built Python SDK wheels and packages at ${BASE_DIR}/dist."
+
+cd ${CURR_DIR}
\ No newline at end of file
diff --git a/streampipes-wrapper-python/pom.xml b/streampipes-wrapper-python/pom.xml
new file mode 100644
index 0000000..608813f
--- /dev/null
+++ b/streampipes-wrapper-python/pom.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>streampipes-parent</artifactId>
+        <groupId>org.apache.streampipes</groupId>
+        <version>0.67.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>streampipes-wrapper-python</artifactId>
+
+
+</project>
\ No newline at end of file
diff --git a/streampipes-wrapper-python/requirements.txt b/streampipes-wrapper-python/requirements.txt
new file mode 100644
index 0000000..1008c86
--- /dev/null
+++ b/streampipes-wrapper-python/requirements.txt
@@ -0,0 +1,8 @@
+click==7.1.2
+confluent-kafka==1.4.2
+Flask==1.1.2
+itsdangerous==1.1.0
+Jinja2==2.11.2
+MarkupSafe==1.1.1
+waitress==1.4.4
+Werkzeug==1.0.1
diff --git a/streampipes-wrapper-python/setup.py b/streampipes-wrapper-python/setup.py
new file mode 100644
index 0000000..dcef38c
--- /dev/null
+++ b/streampipes-wrapper-python/setup.py
@@ -0,0 +1,52 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+""""""
+
+from setuptools import setup
+
+import io
+import os
+
+this_directory = os.path.abspath(os.path.dirname(__file__))
+with io.open(os.path.join(this_directory, 'README.md'), 'r', encoding='utf-8') as f:
+    long_description = f.read()
+
+setup(
+    name='apache-streampipes-python',
+    version='0.67.0-SNAPSHOT',
+    packages=["streampipes"],
+    url='https://github.com/apache/incubator-streampipes',
+    license='https://www.apache.org/licenses/LICENSE-2.0',
+    license_files=["LICENSE", "NOTICE"],
+    author='Apache Software Foundation',
+    author_email='dev@streampipes.apache.org',
+    description='Apache StreamPipes Python Wrapper',
+    long_description=long_description,
+    long_description_content_type='text/markdown',
+    install_requires=[
+        'confluent-kafka==1.4.2',
+        'Flask==1.1.2',
+        'waitress==1.4.4',
+    ],
+    tests_require=[],
+    python_requires='>=3.5',
+    classifiers=[
+        'License :: OSI Approved :: Apache Software License',
+        'Programming Language :: Python :: 3.5',
+        'Programming Language :: Python :: 3.6',
+        'Programming Language :: Python :: 3.7']
+)
\ No newline at end of file
diff --git a/streampipes-wrapper-python/streampipes/__init__.py b/streampipes-wrapper-python/streampipes/__init__.py
new file mode 100644
index 0000000..5cb9710
--- /dev/null
+++ b/streampipes-wrapper-python/streampipes/__init__.py
@@ -0,0 +1,23 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+"""global logging"""
+
+import logging
+
+LOGGING_FORMAT = "%(asctime)s [%(levelname)s] %(name)s — [%(filename)s:%(lineno)s - %(funcName)s()] — %(message)s"
+logging.basicConfig(level=logging.INFO, format=LOGGING_FORMAT)
+logging.getLogger(__name__).addHandler(logging.NullHandler())
\ No newline at end of file
diff --git a/streampipes-wrapper-python/streampipes/api.py b/streampipes-wrapper-python/streampipes/api.py
new file mode 100644
index 0000000..39dbe6e
--- /dev/null
+++ b/streampipes-wrapper-python/streampipes/api.py
@@ -0,0 +1,70 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+""" API endpoints """
+from flask import request, jsonify, Flask
+from waitress import serve
+
+from streampipes.configuration import flask_host, port
+from streampipes.manager import ProcessorDispatcher
+
+
+class EndpointAction(object):
+    def __init__(self, action):
+        self.action = action
+
+    def __call__(self, *args, **kwargs):
+        """ call corresponding handler method """
+        response = self.action(**request.get_json())
+        return jsonify(response)
+
+
+class API(object):
+    """ EventProcessorAPI contains relevant RESTful endpoints to start and stop """
+    app = None
+
+    def __init__(self, name='python-processor'):
+        self.app = Flask(name)
+        self.add_endpoints()
+
+    def run(self):
+        serve(self.app, host=flask_host, port=port)
+
+    def add_endpoints(self):
+        """ define and add event processor API endpoints """
+        self.add_endpoint(endpoint='/invoke', endpoint_name='/invoke', methods=['POST'], handler=self.invoke)
+        self.add_endpoint(endpoint='/detach', endpoint_name='/detach', methods=['POST'], handler=self.detach)
+
+    def add_endpoint(self, endpoint=None, endpoint_name=None, handler=None, methods=None):
+        self.app.add_url_rule(endpoint, endpoint_name, EndpointAction(handler), methods=methods)
+
+    @staticmethod
+    def invoke(**kwargs):
+        """ Receives invocation graph from pipeline management in the backend
+
+        :param json: contains invocation graph.
+        :return: None.
+        """
+        return ProcessorDispatcher.start(app_id=kwargs.get('processor_id'), **kwargs)
+
+    @staticmethod
+    def detach(**kwargs):
+        """ Receives elementId to be terminated from pipeline management in the backend
+
+        :param json: contains elementId to be terminated
+        :return: None.
+        """
+        return ProcessorDispatcher.stop(invocation_id=kwargs.get('invocation_id'))
\ No newline at end of file
diff --git a/streampipes-wrapper-python/streampipes/configuration.py b/streampipes-wrapper-python/streampipes/configuration.py
new file mode 100644
index 0000000..1a6ae11
--- /dev/null
+++ b/streampipes-wrapper-python/streampipes/configuration.py
@@ -0,0 +1,31 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+"""config file"""
+import os
+
+flask_host = os.getenv('FLASK_HOST', '0.0.0.0')
+port = os.getenv('SP_PORT', 5000)
+kafka_thread = 'kafka_thread'
+
+banner="""\
+ _______ __                              ______ __
+|     __|  |_.----.-----.---.-.--------.|   __ \__|.-----.-----.-----.
+|__     |   _|   _|  -__|  _  |        ||    __/  ||  _  |  -__|__ --|
+|_______|____|__| |_____|___._|__|__|__||___|  |__||   __|_____|_____|
+                                                   |__|
+** StreamPipes Pipeline Element Container for Python **
+                            """
diff --git a/streampipes-wrapper-python/streampipes/core.py b/streampipes-wrapper-python/streampipes/core.py
new file mode 100644
index 0000000..346e04f
--- /dev/null
+++ b/streampipes-wrapper-python/streampipes/core.py
@@ -0,0 +1,182 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+"""contains relevant base classes"""
+import json
+import logging
+import queue
+import uuid
+from abc import ABC, abstractmethod
+from streampipes.api import API
+from streampipes.configuration import kafka_thread, banner
+from confluent_kafka import Producer, Consumer
+from streampipes.helper import threaded
+
+
+class StandaloneSubmitter(ABC):
+    @classmethod
+    def init(cls):
+        cls._load_banner()
+        cls.api = API()
+        cls.api.run()
+
+    @classmethod
+    def _load_banner(cls):
+        print(banner)
+
+
+class EventProcessor(ABC):
+    _DEFAULT_KAFKA_CONSUMER_CONFIG = {
+        'bootstrap.servers': 'kafka:9092',
+        'enable.auto.commit': True,
+        'auto.commit.interval.ms': 10000,
+        'session.timeout.ms': 30000,
+        'fetch.max.bytes': 5000012,
+        'auto.offset.reset': 'latest',
+        'group.id': 'streampipes_python_' + str(uuid.uuid4()),
+    }
+
+    _DEFAULT_KAFKA_PRODUCER_CONFIG = {
+        'bootstrap.servers': 'kafka:9092',
+        'acks': 'all',
+        'retries': 0,
+        'linger.ms': 20,
+    }
+
+    def __init__(self, **kwargs):
+        """initialize EventProcessor with Kafka Prodcuer and Consumer"""
+        self.logger = logging.getLogger(__name__)
+        self._input_topics = kwargs.get('input_topics')
+        self._output_topics = kwargs.get('output_topics')
+        self._invocation_id = kwargs.get('invocation_id')
+        self._bootstrap_servers = kwargs.get('bootstrap_servers')
+        self.static_properties = kwargs.get('static_properties')
+
+        # exchange events via queue - maybe register callback would be better
+        self.queue = queue.Queue(maxsize=0)
+        self._running = False
+        self._threads = {}
+
+        if self._bootstrap_servers is not None:
+            self._DEFAULT_KAFKA_CONSUMER_CONFIG['bootstrap.servers'] = self._bootstrap_servers
+            self._DEFAULT_KAFKA_PRODUCER_CONFIG['bootstrap.servers'] = self._bootstrap_servers
+
+        self._producer = Producer(**self._DEFAULT_KAFKA_PRODUCER_CONFIG)
+        self._consumer = Consumer(**self._DEFAULT_KAFKA_CONSUMER_CONFIG)
+        #self._create_topic(topic=self._output_topics, conf=self._DEFAULT_KAFKA_PRODUCER_CONFIG)
+
+        self.on_invocation()
+
+    def init(self):
+        self.logger.info('start processor {}'.format(self._invocation_id))
+        self._threads[kafka_thread] = self.kafka_thread_main()
+
+    def active_threads(self):
+        return self._threads
+
+    @property
+    def invoke_id(self):
+        return self._invocation_id
+
+    def __del__(self):
+        pass
+
+    @abstractmethod
+    def on_invocation(self):
+        """ on_invocation is called when processor is started """
+
+    @abstractmethod
+    def on_event(self, event):
+        """ on_event receives kafka consumer messages """
+        pass
+
+    @abstractmethod
+    def on_detach(self):
+        """ on_detach is called when processor is stopped """
+        pass
+
+    def _on_event(self, event):
+        result = self.on_event(event)
+
+        if result is not None:
+            self._produce(result)
+
+    @threaded
+    def kafka_thread_main(self):
+        """ start threaded kafka consumer """
+        try:
+            self._consumer_run(self._input_topics)
+        except KeyboardInterrupt:
+            self.logger.info("consumer: aborted by user")
+            self._running = False
+        except Exception as ex:
+            self.logger.fatal("consumer: fatal exception: {}".format(ex))
+            self._running = False
+
+    def _consumer_run(self, topics):
+        """ retrieve events from kafka """
+        self._consumer.subscribe(topics=[topics])
+        self._running = True
+
+        while self._running:
+            # fetch records from kafka and send to
+            msg = self._consumer.poll(timeout=1.0)
+
+            if msg is None:
+                continue
+            elif msg.error():
+                if msg.error().str() != "Broker: No more messages":
+                    self.logger.error("Consumer error: {}".format(msg.error()))
+                    continue
+            else:
+                try:
+                    event = json.loads(msg.value().decode('utf-8'))
+                    if isinstance(event, int):
+                        self.logger.info("Integer not allowed {}".format(event))
+                        continue
+                except ValueError as e:
+                    self.logger.info("Not a valid json {}".format(e))
+                    continue
+
+                self._on_event(event)
+
+    def _produce(self, result):
+        """ send events to kafka """
+        event = json.dumps(result).encode('utf-8')
+        try:
+            self._producer.produce(self._output_topics, value=event)
+        except BufferError:
+            self._producer.poll(1)
+
+    # def _create_topic(self, topic=None, conf=None):
+    #     """ Create the topic if it doesn't exist """
+    #     admin = AdminClient(conf)
+    #     fs = admin.create_topics([NewTopic(topic, num_partitions=1, replication_factor=1)])
+    #     f = fs[topic]
+    #     try:
+    #         f.result()
+    #     except KafkaException as ex:
+    #         if ex.args[0].code() == KafkaError.TOPIC_ALREADY_EXISTS:
+    #             self.logger.warning("Topic {} already exists: continue".format(topic))
+    #         else:
+    #             raise
+
+    def stop(self):
+        self.logger.info('stop processor {}'.format(self._invocation_id))
+        self._running = False
+        self._consumer.close()
+        self._producer.flush()
+        self.on_detach()
diff --git a/streampipes-wrapper-python/streampipes/helper.py b/streampipes-wrapper-python/streampipes/helper.py
new file mode 100644
index 0000000..44a6b44
--- /dev/null
+++ b/streampipes-wrapper-python/streampipes/helper.py
@@ -0,0 +1,28 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+"""some helper methods"""
+import threading
+
+
+def threaded(func):
+    def wrapper(*args, **kwargs):
+        thread_name = args[0]._invocation_id
+        thread = threading.Thread(target=func, args=args, kwargs=kwargs, name=thread_name)
+        thread.start()
+        return thread
+
+    return wrapper
\ No newline at end of file
diff --git a/streampipes-wrapper-python/streampipes/manager.py b/streampipes-wrapper-python/streampipes/manager.py
new file mode 100644
index 0000000..d7a2d50
--- /dev/null
+++ b/streampipes-wrapper-python/streampipes/manager.py
@@ -0,0 +1,72 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+"""Manages processor life cycle"""
+import logging
+from abc import ABC
+from streampipes.configuration import kafka_thread
+
+
+class Declarer(ABC):
+    """ EventProcessorManager holds running processor instances """
+    _processors = {}
+
+    @classmethod
+    def add(cls, processors=None):
+        """ holds dict with <app_id, processor class>"""
+        cls._processors = processors
+
+    @classmethod
+    def get_processor(cls, key):
+        return cls._processors[key]
+
+    @classmethod
+    def get(cls):
+        return cls._processors
+
+
+class ProcessorDispatcher(ABC):
+    _running_instances = {}
+    logger = logging.getLogger(__name__)
+
+    @classmethod
+    def start(cls, processor_id=None, **kwargs):
+        try:
+            processor = Declarer.get_processor(processor_id)(**kwargs)
+            processor.init()
+            cls._running_instances[processor.invoke_id] = processor
+            return {'status': 'success'}
+
+        except KeyError:
+            err = "KeyError. processor_id not found"
+            cls.logger.info('{}: {}'.format(err,processor_id))
+            return {'status': err}
+
+    @classmethod
+    def stop(cls, invocation_id=None):
+        try:
+            processor = cls._running_instances[invocation_id]
+            active_threads = processor.active_threads()
+            processor.stop()
+            active_threads[kafka_thread].join()
+            del processor
+            cls._running_instances.pop(invocation_id)
+            return {'status': 'success'}
+
+        except KeyError:
+            err = "KeyError. invocation_id not found"
+            cls.logger.info('{}: {}'.format(err,invocation_id))
+            return {'status': err}
\ No newline at end of file