diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d5ef9f4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,124 @@ +# Local development +local-setup.sh +driver.py +ignore.py + +# OS trash +.DS_Store + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/build/ +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ diff --git a/DESCRIPTION.md b/DESCRIPTION.md new file mode 100644 index 0000000..d2e2631 --- /dev/null +++ b/DESCRIPTION.md @@ -0,0 +1,5 @@ +# btrdbextras + +This package contains additional enhancements and features to interact with the BTrDB database and Pingthings platform. + +Please see the full documentation at: [https://btrdbextras.readthedocs.io/en/latest/](https://btrdbextras.readthedocs.io/en/latest/). diff --git a/LICENSE.txt b/LICENSE.txt index e69de29..e07e178 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -0,0 +1,11 @@ +Copyright (c) 2020 PingThing Inc, All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..cd0cdb5 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,22 @@ +include *.md +include *.rst +include *.txt +include *.yml +include *.yaml +include *.cfg +include Makefile +include MANIFEST.in + +graft docs +prune docs/build + +graft tests + +graft btrdbextras + +global-exclude __pycache__ +global-exclude *.py[co] +global-exclude .ipynb_checkpoints +global-exclude .DS_Store +global-exclude .env +global-exclude .coverage.* \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..489fafa --- /dev/null +++ b/Makefile @@ -0,0 +1,62 @@ +# Shell to use with Make +SHELL := /bin/bash + +# Set important Paths +PROJECT := btrdbextras +LOCALPATH := $(CURDIR)/$(PROJECT) + +# Sphinx configuration +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXBUILDDIR = docs/build +SPHINXSOURCEDIR = docs/source + +# Export targets not associated with files +.PHONY: test grpc + +# Clean build files +clean: + find . -name "*.pyc" -print0 | xargs -0 rm -rf + find . -name "__pycache__" -print0 | xargs -0 rm -rf + find . -name ".DS_Store" -print0 | xargs -0 rm -rf + -rm -rf docs/build + -rm -rf htmlcov + -rm -rf .pytest_cache + -rm -rf .coverage + -rm -rf build + -rm -rf dist + -rm -rf $(PROJECT).egg-info + -rm -rf .eggs + -rm -rf site + -rm -rf docs/build + -rm -rf platform-builds meta.yaml + +# Generate new grpc code +grpc: + @echo Generating files: + python -m grpc_tools.protoc -I btrdbextras/eventproc/protobuff --python_out=btrdbextras/eventproc/protobuff --grpc_python_out=btrdbextras/eventproc/protobuff btrdbextras/eventproc/protobuff/api.proto + @echo + @echo Fixing import statements: + sed -i'.bak' 's/api_pb2 as api__pb2/btrdbextras.eventproc.protobuff.api_pb2 as api__pb2/' btrdbextras/eventproc/protobuff/api_pb2_grpc.py + + +# Targets for testing +test: + python setup.py test + +# Build the universal wheel and source distribution +build: + python setup.py sdist bdist_wheel + +# Install the package from source +install: + python setup.py install + +# Deploy to PyPI +deploy: + # python setup.py register + twine upload dist/* --verbose + +# Build html version of docs +html: + $(SPHINXBUILD) -b html $(SPHINXOPTS) $(SPHINXSOURCEDIR) $(SPHINXBUILDDIR) \ No newline at end of file diff --git a/btrdbextras/__init__.py b/btrdbextras/__init__.py new file mode 100644 index 0000000..fe56091 --- /dev/null +++ b/btrdbextras/__init__.py @@ -0,0 +1,3 @@ +from .conn import Connection + +__version__ = "v5.11.2" \ No newline at end of file diff --git a/btrdbextras/conn.py b/btrdbextras/conn.py new file mode 100644 index 0000000..9d8ea66 --- /dev/null +++ b/btrdbextras/conn.py @@ -0,0 +1,42 @@ +# eventproc.conn +# Connection related objects +# +# Author: PingThings +# Created: +# +# For license information, see LICENSE.txt +# ID: conn.py [] allen@pingthings.io $ + +""" +Connection related objects +""" + +########################################################################## +## Imports +########################################################################## + +import os + +########################################################################## +## Classes +########################################################################## + +class Connection(): + + def __init__(self, endpoint=os.environ.get("BTRDB_ENDPOINTS"), apikey=os.environ.get("BTRDB_API_KEY")): + if endpoint is None: + raise Exception("invalid endpoint or BTRDB_ENDPOINTS env variable not set") + + if apikey is None: + raise Exception("invalid api key or BTRDB_API_KEY env variable not set") + + self._endpoint = endpoint + self._apikey = apikey + + @property + def apikey(self): + return self._apikey + + @property + def endpoint(self): + return self._endpoint diff --git a/btrdbextras/eventproc/__init__.py b/btrdbextras/eventproc/__init__.py new file mode 100644 index 0000000..3e580d6 --- /dev/null +++ b/btrdbextras/eventproc/__init__.py @@ -0,0 +1,3 @@ +from .eventproc import hooks, list_handlers, register, deregister + +__all__ = ['hooks', 'list_handlers', 'register', 'deregister'] \ No newline at end of file diff --git a/btrdbextras/eventproc/eventproc.py b/btrdbextras/eventproc/eventproc.py new file mode 100644 index 0000000..f480b66 --- /dev/null +++ b/btrdbextras/eventproc/eventproc.py @@ -0,0 +1,212 @@ +# btrdbextras.eventproc +# Event processing related functions. +# +# Author: PingThings +# Created: Fri Dec 21 14:57:30 2018 -0500 +# +# For license information, see LICENSE.txt +# ID: conn.py [] allen@pingthings.io $ + +""" +Event processing related functions. +""" + +########################################################################## +## Imports +########################################################################## + +import io +from collections import namedtuple + +import dill +from btrdb.utils.timez import ns_to_datetime + +from btrdbextras.eventproc.protobuff import api_pb2 +from btrdbextras.eventproc.protobuff import api_pb2_grpc + + +__all__ = ['hooks', 'list_handlers', 'register', 'deregister'] + +import grpc + +PATH_PREFIX="/eventproc" + +########################################################################## +## Helper Functions +########################################################################## + +def connect(conn): + parts = conn.endpoint.split(":", 2) + endpoint = conn.endpoint + PATH_PREFIX + apikey = conn.apikey + + if len(parts) != 2: + raise ValueError("expecting address:port") + + if apikey is None or apikey == "": + raise ValueError("must supply an API key") + + return grpc.secure_channel( + endpoint, + grpc.composite_channel_credentials( + grpc.ssl_channel_credentials(None), + grpc.access_token_call_credentials(apikey) + ) + ) + + +########################################################################## +## Helper Classes +########################################################################## + +HandlerBase = namedtuple("HandlerBase", "id name hook version notify_on_success notify_on_failure flags created_at created_by updated_at updated_by") + +class Handler(HandlerBase): + """ + Class definition for an event handler object. Inherits from HandlerBase + to add methods to the namedtuple. + """ + + @classmethod + def from_grpc(cls, h): + return cls( + h.id, h.name, h.hook, h.version, h.notify_on_success, h.notify_on_failure, + h.flag, ns_to_datetime(h.created_at), h.created_by, + ns_to_datetime(h.updated_at), h.updated_by + ) + +class Service(object): + """ + Helper class to integrate with GRPC generated code. + """ + + def __init__(self, channel): + self.channel = channel + self.stub = api_pb2_grpc.EventProcessingServiceStub(channel) + + def ListHooks(self): + params = api_pb2.ListHooksRequest() + return [r.name for r in self.stub.ListHooks(params).hooks] + + def ListHandlers(self, hook): + params = api_pb2.ListHandlersRequest(hook=hook) + response = self.stub.ListHandlers(params) + + for result in response.handlers: + yield result + + def Register(self, name, hook, func, apikey, notify_on_success, notify_on_failure, dependencies, flags): + # convert decorated function to bytes + buff = io.BytesIO() + dill.dump(func, buff) + buff.seek(0) + + params = api_pb2.RegisterRequest( + registration=api_pb2.Registration( + name=name, + hook=hook, + blob=buff.read(), + api_key=apikey, + notify_on_success=notify_on_success, + notify_on_failure=notify_on_failure, + dependencies=dependencies, + flags=flags, + ) + ) + response = self.stub.Register(params) + if hasattr(response, "handler"): + return Handler.from_grpc(response.handler) + + def Deregister(self, handler_id): + params = api_pb2.DeregisterRequest(id=handler_id) + response = self.stub.Deregister(params) + return response + + +########################################################################## +## Public Functions +########################################################################## + +def hooks(conn): + """ + List registered hooks. + + Parameters + ---------- + conn: Connection + btrdbextras Connection object containing a valid address and api key. + """ + s = Service(connect(conn)) + return s.ListHooks() + +def list_handlers(conn, hook=""): + """ + List registered handlers. An optional hook name is allowed to filter + results. + + Parameters + ---------- + conn: Connection + btrdbextras Connection object containing a valid address and api key. + hook: str + Optional hook name to filter registered handlers. + + """ + s = Service(connect(conn)) + return [Handler.from_grpc(h) for h in s.ListHandlers(hook)] + + +def deregister(conn, handler_id): + """ + Removes an existing event handler by ID. + + Parameters + ---------- + conn: Connection + btrdbextras Connection object containing a valid address and api key. + handler_id: int + ID of the event handler to remove. + + """ + s = Service(connect(conn)) + h = s.Deregister(handler_id) + return h.id == handler_id + + +def register(conn, name, hook, notify_on_success, notify_on_failure, flags=None): + """ + decorator to submit (register) an event handler function + + Parameters + ---------- + conn: Connection + btrdbextras Connection object containing a valid address and api key. + name: str + Friendly name of this event handler for display purposes. + hook: str + Name of the hook that this event handler responds to. + notify_on_success: str + Email address of user to notify when event handler completes successfully. + notify_on_failure: str + Email address of user to notify when event handler does not complete + successfully. + flags: list of str + Filtering flags that users can choose when identifying handlers to + execute. An empty list will match all flags. + + """ + # placeholder for future dependency management feature + dependencies = "" + + # inner will actually receive the decorated func but we still have access + # to the args & kwargs due to closure/scope. + def inner(func): + + # call grpc service to register event handler + s = Service(connect(conn)) + _ = s.Register(name, hook, func, conn.apikey, notify_on_success, notify_on_failure, dependencies, flags) + + # return original func back to user + return func + + return inner diff --git a/eventproc/__init__.py b/btrdbextras/eventproc/protobuff/__init__.py similarity index 100% rename from eventproc/__init__.py rename to btrdbextras/eventproc/protobuff/__init__.py diff --git a/api.proto b/btrdbextras/eventproc/protobuff/api.proto similarity index 66% rename from api.proto rename to btrdbextras/eventproc/protobuff/api.proto index d911e7d..d8263ed 100644 --- a/api.proto +++ b/btrdbextras/eventproc/protobuff/api.proto @@ -17,12 +17,13 @@ message Handler { string name = 3; int32 version = 4; string callable = 5; - string notify_on_success = 6; - string notify_on_failure = 7; - string created_by = 8; - int64 created_at = 9; - string updated_by = 10; - int64 updated_at = 11; + repeated string flag = 6; + string notify_on_success = 7; + string notify_on_failure = 8; + string created_by = 9; + int64 created_at = 10; + string updated_by = 11; + int64 updated_at = 12; } message ListHooksRequest {} @@ -40,7 +41,7 @@ message Hook { message Registration { string name = 1; string hook = 2; - repeated string flag = 3; + repeated string flags = 3; bytes blob = 4; // limit is 4GB string notify_on_success = 5; string notify_on_failure = 6; @@ -67,11 +68,8 @@ message DeregisterResponse { service EventProcessingService { - rpc ListHooks(ListHooksRequest) returns (ListHooksResponse) {} - rpc ListHandlers(ListHandlersRequest) returns (ListHandlersResponse) {} - rpc Register(RegisterRequest) returns (RegisterResponse) {} + rpc ListHooks(ListHooksRequest) returns (ListHooksResponse) {} + rpc ListHandlers(ListHandlersRequest) returns (ListHandlersResponse) {} + rpc Register(RegisterRequest) returns (RegisterResponse) {} rpc Deregister(DeregisterRequest) returns (DeregisterResponse) {} } - -// regenerate the grpc code with the following command -// protoc -I/usr/local/include -I. --go_out=plugins=grpc:. api.proto diff --git a/btrdbextras/eventproc/protobuff/api_pb2.py b/btrdbextras/eventproc/protobuff/api_pb2.py new file mode 100644 index 0000000..250488d --- /dev/null +++ b/btrdbextras/eventproc/protobuff/api_pb2.py @@ -0,0 +1,656 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: api.proto +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='api.proto', + package='eventprocapi', + syntax='proto3', + serialized_options=None, + create_key=_descriptor._internal_create_key, + serialized_pb=b'\n\tapi.proto\x12\x0c\x65ventprocapi\"#\n\x13ListHandlersRequest\x12\x0c\n\x04hook\x18\x01 \x01(\t\"?\n\x14ListHandlersResponse\x12\'\n\x08handlers\x18\x01 \x03(\x0b\x32\x15.eventprocapi.Handler\"\xe8\x01\n\x07Handler\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0c\n\x04hook\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\x0f\n\x07version\x18\x04 \x01(\x05\x12\x10\n\x08\x63\x61llable\x18\x05 \x01(\t\x12\x0c\n\x04\x66lag\x18\x06 \x03(\t\x12\x19\n\x11notify_on_success\x18\x07 \x01(\t\x12\x19\n\x11notify_on_failure\x18\x08 \x01(\t\x12\x12\n\ncreated_by\x18\t \x01(\t\x12\x12\n\ncreated_at\x18\n \x01(\x03\x12\x12\n\nupdated_by\x18\x0b \x01(\t\x12\x12\n\nupdated_at\x18\x0c \x01(\x03\"\x12\n\x10ListHooksRequest\"6\n\x11ListHooksResponse\x12!\n\x05hooks\x18\x01 \x03(\x0b\x32\x12.eventprocapi.Hook\"\x14\n\x04Hook\x12\x0c\n\x04name\x18\x01 \x01(\t\"\xb2\x01\n\x0cRegistration\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04hook\x18\x02 \x01(\t\x12\r\n\x05\x66lags\x18\x03 \x03(\t\x12\x0c\n\x04\x62lob\x18\x04 \x01(\x0c\x12\x19\n\x11notify_on_success\x18\x05 \x01(\t\x12\x19\n\x11notify_on_failure\x18\x06 \x01(\t\x12\x14\n\x0c\x64\x65pendencies\x18\x07 \x01(\t\x12\x0c\n\x04user\x18\x08 \x01(\t\x12\x0f\n\x07\x61pi_key\x18\t \x01(\t\"C\n\x0fRegisterRequest\x12\x30\n\x0cregistration\x18\x01 \x01(\x0b\x32\x1a.eventprocapi.Registration\":\n\x10RegisterResponse\x12&\n\x07handler\x18\x01 \x01(\x0b\x32\x15.eventprocapi.Handler\"\x1f\n\x11\x44\x65registerRequest\x12\n\n\x02id\x18\x01 \x01(\x05\" \n\x12\x44\x65registerResponse\x12\n\n\x02id\x18\x01 \x01(\x05\x32\xe1\x02\n\x16\x45ventProcessingService\x12N\n\tListHooks\x12\x1e.eventprocapi.ListHooksRequest\x1a\x1f.eventprocapi.ListHooksResponse\"\x00\x12W\n\x0cListHandlers\x12!.eventprocapi.ListHandlersRequest\x1a\".eventprocapi.ListHandlersResponse\"\x00\x12K\n\x08Register\x12\x1d.eventprocapi.RegisterRequest\x1a\x1e.eventprocapi.RegisterResponse\"\x00\x12Q\n\nDeregister\x12\x1f.eventprocapi.DeregisterRequest\x1a .eventprocapi.DeregisterResponse\"\x00\x62\x06proto3' +) + + + + +_LISTHANDLERSREQUEST = _descriptor.Descriptor( + name='ListHandlersRequest', + full_name='eventprocapi.ListHandlersRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='hook', full_name='eventprocapi.ListHandlersRequest.hook', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=27, + serialized_end=62, +) + + +_LISTHANDLERSRESPONSE = _descriptor.Descriptor( + name='ListHandlersResponse', + full_name='eventprocapi.ListHandlersResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='handlers', full_name='eventprocapi.ListHandlersResponse.handlers', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=64, + serialized_end=127, +) + + +_HANDLER = _descriptor.Descriptor( + name='Handler', + full_name='eventprocapi.Handler', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='id', full_name='eventprocapi.Handler.id', index=0, + number=1, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='hook', full_name='eventprocapi.Handler.hook', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='name', full_name='eventprocapi.Handler.name', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='version', full_name='eventprocapi.Handler.version', index=3, + number=4, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='callable', full_name='eventprocapi.Handler.callable', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='flag', full_name='eventprocapi.Handler.flag', index=5, + number=6, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='notify_on_success', full_name='eventprocapi.Handler.notify_on_success', index=6, + number=7, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='notify_on_failure', full_name='eventprocapi.Handler.notify_on_failure', index=7, + number=8, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='created_by', full_name='eventprocapi.Handler.created_by', index=8, + number=9, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='created_at', full_name='eventprocapi.Handler.created_at', index=9, + number=10, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='updated_by', full_name='eventprocapi.Handler.updated_by', index=10, + number=11, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='updated_at', full_name='eventprocapi.Handler.updated_at', index=11, + number=12, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=130, + serialized_end=362, +) + + +_LISTHOOKSREQUEST = _descriptor.Descriptor( + name='ListHooksRequest', + full_name='eventprocapi.ListHooksRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=364, + serialized_end=382, +) + + +_LISTHOOKSRESPONSE = _descriptor.Descriptor( + name='ListHooksResponse', + full_name='eventprocapi.ListHooksResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='hooks', full_name='eventprocapi.ListHooksResponse.hooks', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=384, + serialized_end=438, +) + + +_HOOK = _descriptor.Descriptor( + name='Hook', + full_name='eventprocapi.Hook', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='name', full_name='eventprocapi.Hook.name', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=440, + serialized_end=460, +) + + +_REGISTRATION = _descriptor.Descriptor( + name='Registration', + full_name='eventprocapi.Registration', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='name', full_name='eventprocapi.Registration.name', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='hook', full_name='eventprocapi.Registration.hook', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='flags', full_name='eventprocapi.Registration.flags', index=2, + number=3, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='blob', full_name='eventprocapi.Registration.blob', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=b"", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='notify_on_success', full_name='eventprocapi.Registration.notify_on_success', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='notify_on_failure', full_name='eventprocapi.Registration.notify_on_failure', index=5, + number=6, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='dependencies', full_name='eventprocapi.Registration.dependencies', index=6, + number=7, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='user', full_name='eventprocapi.Registration.user', index=7, + number=8, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='api_key', full_name='eventprocapi.Registration.api_key', index=8, + number=9, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=463, + serialized_end=641, +) + + +_REGISTERREQUEST = _descriptor.Descriptor( + name='RegisterRequest', + full_name='eventprocapi.RegisterRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='registration', full_name='eventprocapi.RegisterRequest.registration', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=643, + serialized_end=710, +) + + +_REGISTERRESPONSE = _descriptor.Descriptor( + name='RegisterResponse', + full_name='eventprocapi.RegisterResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='handler', full_name='eventprocapi.RegisterResponse.handler', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=712, + serialized_end=770, +) + + +_DEREGISTERREQUEST = _descriptor.Descriptor( + name='DeregisterRequest', + full_name='eventprocapi.DeregisterRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='id', full_name='eventprocapi.DeregisterRequest.id', index=0, + number=1, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=772, + serialized_end=803, +) + + +_DEREGISTERRESPONSE = _descriptor.Descriptor( + name='DeregisterResponse', + full_name='eventprocapi.DeregisterResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='id', full_name='eventprocapi.DeregisterResponse.id', index=0, + number=1, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=805, + serialized_end=837, +) + +_LISTHANDLERSRESPONSE.fields_by_name['handlers'].message_type = _HANDLER +_LISTHOOKSRESPONSE.fields_by_name['hooks'].message_type = _HOOK +_REGISTERREQUEST.fields_by_name['registration'].message_type = _REGISTRATION +_REGISTERRESPONSE.fields_by_name['handler'].message_type = _HANDLER +DESCRIPTOR.message_types_by_name['ListHandlersRequest'] = _LISTHANDLERSREQUEST +DESCRIPTOR.message_types_by_name['ListHandlersResponse'] = _LISTHANDLERSRESPONSE +DESCRIPTOR.message_types_by_name['Handler'] = _HANDLER +DESCRIPTOR.message_types_by_name['ListHooksRequest'] = _LISTHOOKSREQUEST +DESCRIPTOR.message_types_by_name['ListHooksResponse'] = _LISTHOOKSRESPONSE +DESCRIPTOR.message_types_by_name['Hook'] = _HOOK +DESCRIPTOR.message_types_by_name['Registration'] = _REGISTRATION +DESCRIPTOR.message_types_by_name['RegisterRequest'] = _REGISTERREQUEST +DESCRIPTOR.message_types_by_name['RegisterResponse'] = _REGISTERRESPONSE +DESCRIPTOR.message_types_by_name['DeregisterRequest'] = _DEREGISTERREQUEST +DESCRIPTOR.message_types_by_name['DeregisterResponse'] = _DEREGISTERRESPONSE +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +ListHandlersRequest = _reflection.GeneratedProtocolMessageType('ListHandlersRequest', (_message.Message,), { + 'DESCRIPTOR' : _LISTHANDLERSREQUEST, + '__module__' : 'api_pb2' + # @@protoc_insertion_point(class_scope:eventprocapi.ListHandlersRequest) + }) +_sym_db.RegisterMessage(ListHandlersRequest) + +ListHandlersResponse = _reflection.GeneratedProtocolMessageType('ListHandlersResponse', (_message.Message,), { + 'DESCRIPTOR' : _LISTHANDLERSRESPONSE, + '__module__' : 'api_pb2' + # @@protoc_insertion_point(class_scope:eventprocapi.ListHandlersResponse) + }) +_sym_db.RegisterMessage(ListHandlersResponse) + +Handler = _reflection.GeneratedProtocolMessageType('Handler', (_message.Message,), { + 'DESCRIPTOR' : _HANDLER, + '__module__' : 'api_pb2' + # @@protoc_insertion_point(class_scope:eventprocapi.Handler) + }) +_sym_db.RegisterMessage(Handler) + +ListHooksRequest = _reflection.GeneratedProtocolMessageType('ListHooksRequest', (_message.Message,), { + 'DESCRIPTOR' : _LISTHOOKSREQUEST, + '__module__' : 'api_pb2' + # @@protoc_insertion_point(class_scope:eventprocapi.ListHooksRequest) + }) +_sym_db.RegisterMessage(ListHooksRequest) + +ListHooksResponse = _reflection.GeneratedProtocolMessageType('ListHooksResponse', (_message.Message,), { + 'DESCRIPTOR' : _LISTHOOKSRESPONSE, + '__module__' : 'api_pb2' + # @@protoc_insertion_point(class_scope:eventprocapi.ListHooksResponse) + }) +_sym_db.RegisterMessage(ListHooksResponse) + +Hook = _reflection.GeneratedProtocolMessageType('Hook', (_message.Message,), { + 'DESCRIPTOR' : _HOOK, + '__module__' : 'api_pb2' + # @@protoc_insertion_point(class_scope:eventprocapi.Hook) + }) +_sym_db.RegisterMessage(Hook) + +Registration = _reflection.GeneratedProtocolMessageType('Registration', (_message.Message,), { + 'DESCRIPTOR' : _REGISTRATION, + '__module__' : 'api_pb2' + # @@protoc_insertion_point(class_scope:eventprocapi.Registration) + }) +_sym_db.RegisterMessage(Registration) + +RegisterRequest = _reflection.GeneratedProtocolMessageType('RegisterRequest', (_message.Message,), { + 'DESCRIPTOR' : _REGISTERREQUEST, + '__module__' : 'api_pb2' + # @@protoc_insertion_point(class_scope:eventprocapi.RegisterRequest) + }) +_sym_db.RegisterMessage(RegisterRequest) + +RegisterResponse = _reflection.GeneratedProtocolMessageType('RegisterResponse', (_message.Message,), { + 'DESCRIPTOR' : _REGISTERRESPONSE, + '__module__' : 'api_pb2' + # @@protoc_insertion_point(class_scope:eventprocapi.RegisterResponse) + }) +_sym_db.RegisterMessage(RegisterResponse) + +DeregisterRequest = _reflection.GeneratedProtocolMessageType('DeregisterRequest', (_message.Message,), { + 'DESCRIPTOR' : _DEREGISTERREQUEST, + '__module__' : 'api_pb2' + # @@protoc_insertion_point(class_scope:eventprocapi.DeregisterRequest) + }) +_sym_db.RegisterMessage(DeregisterRequest) + +DeregisterResponse = _reflection.GeneratedProtocolMessageType('DeregisterResponse', (_message.Message,), { + 'DESCRIPTOR' : _DEREGISTERRESPONSE, + '__module__' : 'api_pb2' + # @@protoc_insertion_point(class_scope:eventprocapi.DeregisterResponse) + }) +_sym_db.RegisterMessage(DeregisterResponse) + + + +_EVENTPROCESSINGSERVICE = _descriptor.ServiceDescriptor( + name='EventProcessingService', + full_name='eventprocapi.EventProcessingService', + file=DESCRIPTOR, + index=0, + serialized_options=None, + create_key=_descriptor._internal_create_key, + serialized_start=840, + serialized_end=1193, + methods=[ + _descriptor.MethodDescriptor( + name='ListHooks', + full_name='eventprocapi.EventProcessingService.ListHooks', + index=0, + containing_service=None, + input_type=_LISTHOOKSREQUEST, + output_type=_LISTHOOKSRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='ListHandlers', + full_name='eventprocapi.EventProcessingService.ListHandlers', + index=1, + containing_service=None, + input_type=_LISTHANDLERSREQUEST, + output_type=_LISTHANDLERSRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='Register', + full_name='eventprocapi.EventProcessingService.Register', + index=2, + containing_service=None, + input_type=_REGISTERREQUEST, + output_type=_REGISTERRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='Deregister', + full_name='eventprocapi.EventProcessingService.Deregister', + index=3, + containing_service=None, + input_type=_DEREGISTERREQUEST, + output_type=_DEREGISTERRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), +]) +_sym_db.RegisterServiceDescriptor(_EVENTPROCESSINGSERVICE) + +DESCRIPTOR.services_by_name['EventProcessingService'] = _EVENTPROCESSINGSERVICE + +# @@protoc_insertion_point(module_scope) diff --git a/btrdbextras/eventproc/protobuff/api_pb2_grpc.py b/btrdbextras/eventproc/protobuff/api_pb2_grpc.py new file mode 100644 index 0000000..ec3abe4 --- /dev/null +++ b/btrdbextras/eventproc/protobuff/api_pb2_grpc.py @@ -0,0 +1,164 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + +import btrdbextras.eventproc.protobuff.api_pb2 as api__pb2 + +class EventProcessingServiceStub(object): + """Missing associated documentation comment in .proto file.""" + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.ListHooks = channel.unary_unary( + '/eventprocapi.EventProcessingService/ListHooks', + request_serializer=api__pb2.ListHooksRequest.SerializeToString, + response_deserializer=api__pb2.ListHooksResponse.FromString, + ) + self.ListHandlers = channel.unary_unary( + '/eventprocapi.EventProcessingService/ListHandlers', + request_serializer=api__pb2.ListHandlersRequest.SerializeToString, + response_deserializer=api__pb2.ListHandlersResponse.FromString, + ) + self.Register = channel.unary_unary( + '/eventprocapi.EventProcessingService/Register', + request_serializer=api__pb2.RegisterRequest.SerializeToString, + response_deserializer=api__pb2.RegisterResponse.FromString, + ) + self.Deregister = channel.unary_unary( + '/eventprocapi.EventProcessingService/Deregister', + request_serializer=api__pb2.DeregisterRequest.SerializeToString, + response_deserializer=api__pb2.DeregisterResponse.FromString, + ) + + +class EventProcessingServiceServicer(object): + """Missing associated documentation comment in .proto file.""" + + def ListHooks(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def ListHandlers(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def Register(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def Deregister(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_EventProcessingServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'ListHooks': grpc.unary_unary_rpc_method_handler( + servicer.ListHooks, + request_deserializer=api__pb2.ListHooksRequest.FromString, + response_serializer=api__pb2.ListHooksResponse.SerializeToString, + ), + 'ListHandlers': grpc.unary_unary_rpc_method_handler( + servicer.ListHandlers, + request_deserializer=api__pb2.ListHandlersRequest.FromString, + response_serializer=api__pb2.ListHandlersResponse.SerializeToString, + ), + 'Register': grpc.unary_unary_rpc_method_handler( + servicer.Register, + request_deserializer=api__pb2.RegisterRequest.FromString, + response_serializer=api__pb2.RegisterResponse.SerializeToString, + ), + 'Deregister': grpc.unary_unary_rpc_method_handler( + servicer.Deregister, + request_deserializer=api__pb2.DeregisterRequest.FromString, + response_serializer=api__pb2.DeregisterResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'eventprocapi.EventProcessingService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class EventProcessingService(object): + """Missing associated documentation comment in .proto file.""" + + @staticmethod + def ListHooks(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/eventprocapi.EventProcessingService/ListHooks', + api__pb2.ListHooksRequest.SerializeToString, + api__pb2.ListHooksResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def ListHandlers(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/eventprocapi.EventProcessingService/ListHandlers', + api__pb2.ListHandlersRequest.SerializeToString, + api__pb2.ListHandlersResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def Register(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/eventprocapi.EventProcessingService/Register', + api__pb2.RegisterRequest.SerializeToString, + api__pb2.RegisterResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def Deregister(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/eventprocapi.EventProcessingService/Deregister', + api__pb2.DeregisterRequest.SerializeToString, + api__pb2.DeregisterResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..6247f7e --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..d535bde --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,2 @@ +sphinx +sphinx_glpi_theme diff --git a/docs/source/api.rst b/docs/source/api.rst new file mode 100644 index 0000000..eba678b --- /dev/null +++ b/docs/source/api.rst @@ -0,0 +1,8 @@ +API +=== + +eventproc +--------- + +.. automodule:: btrdbextras.eventproc + :members: diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..3e27d73 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,60 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + +import os +import sys +sys.path.insert(0, os.path.abspath('../..')) + +import sphinx_glpi_theme + +# -- Project information ----------------------------------------------------- + +project = 'btrdbextras' +copyright = '2020, PingThings, Inc.' +author = 'PingThings, Inc.' + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.napoleon', + 'sphinx.ext.githubpages', + 'sphinx.ext.intersphinx', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['build', 'Thumbs.db', '.DS_Store'] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# + + +html_theme = "glpi" + +html_theme_path = sphinx_glpi_theme.get_html_themes_path() \ No newline at end of file diff --git a/docs/source/eventproc.rst b/docs/source/eventproc.rst new file mode 100644 index 0000000..f4b581d --- /dev/null +++ b/docs/source/eventproc.rst @@ -0,0 +1,196 @@ +Event Processing +========================= + +Overview +-------- + +The Event Processing library allows you to run arbitrary code (event handlers) at predefined events (also called hooks) within the PredictiveGrid platform. A sample use case might be if you would like to upload new COMTRADE files using the COMTRADE ingress and have a transform or analytical process run immediately after import. + +Notifications +~~~~~~~~~~~~~~~~~~~ + +After your event handler is executed, an email is sent to the success or failure email address supplied during registration. If successful, the email will contain any text that was returned by your Python function. If an exception is raised, then the handler code is regarded as unsuccesful and a notification is sent to the corresponding failure email address with exception details. + +Dependencies +~~~~~~~~~~~~~~~~~~~ + +Our platform will provide a base python 3.7.3 environment similar to our Jupyter servers. We provide some standard libraries such as: + +* btrdb +* matplotlib +* numpy +* pandas +* ray +* scikit-learn +* scipy +* statsmodels +* tensorflow +* torch +* torchvision + +Flags +~~~~~~~~~~~~~~~~~~~ + +Each event handler also includes a `flags` argument. This allows the user to choose which event handlers should run in any given scenarion. For instance, if submitting new COMTRADE files to the ingress, you can choose the "voltage-transform" flag to indicate that any event handlers registered with this flag will be executed. Multiple flags can be added to your event handler, and users can choose from multiple flags to determine which handlers should run. In the latter case, a logical OR is used such that any handler with at least one of the chosen flags will be scheduled for execution. + +Connections +----------- + +Each of the following calls require a `Connection` object (different from the btrdb library connection object) as the first argument. When registering a new event handler, the API key in the `Connection` object will be used as the execution time security context - meaning all code will be executed as the registering user. + +The Connection object requires the BTrDB address/port as well as an API key as follows. + +.. code-block:: python + + >>> from btrdbextras import Connection + >>> conn = Connection("api.example.com:4411", "C27489F2BFACE794A3") + + +However, the `Connection` object will also look for the `BTRDB_ENDPOINTS` and `BTRDB_API_KEY` environment variables if no arguments are supplied. + +.. code-block:: python + + >>> from btrdbextras import Connection + >>> conn = Connection() + + +Interactions +------------ + +The following calls can be made to platform to manage your event handling code. + +Listing Known Hooks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can think of hooks as just labels that represent a specific point during the execution of some process (such as importing data). In order to see the allowed hooks, you may invoke the `hooks` function. Over time, new `hooks` will be added to the platform allowing you to integrate your own code into different processes. + +.. code-block:: python + + >>> from btrdbextras import Connection + >>> from btrdbextras.eventproc import hooks + + >>> conn = Connection() + >>> hooks(conn) + ['ctingress.on_complete'] + + +Registering Event Handlers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The event handlers are supplied by you. This is code you would like executed when a specific hook/event has occurred within the larger platform. Your Python callable, typically just a function, will be pickled using the `dill` library for execution in the platform. As such there are certain Python code serialization topics to keep in mind such as: total size of the callable, libraries available in the execution environment, etc. + +To submit a new event handler, you can use the `register` decorator around your own Python callable. Like all objects in this library, you can use the `help` function to view the docstring. + +.. code-block:: python + + >>> from btrdbextras.eventproc import register + >>> help(register) + Help on function register in module btrdbextras.eventproc.eventproc: + + register(conn, name, hook, notify_on_success, notify_on_failure, flags=None) + decorator to submit (register) an event handler function + + Parameters + ---------- + conn: Connection + btrdbextras Connection object containing a valid address and api key. + name: str + Friendly name of this event handler for display purposes. + hook: str + Name of the hook that this event handler responds to. + notify_on_success: str + Email address of user to notify when event handler completes successfully. + notify_on_failure: str + Email address of user to notify when event handler does not complete + successfully. + flags: list of str + Filtering flags that users can choose when identifying handlers to + execute. An empty list will match all flags. + +As you can see, this decorator does have required arguments. A trivial example is shown below. + +.. code-block:: python + + >>> from btrdbextras import Connection + >>> from btrdbextras.eventproc import register + >>> conn = Connection() + >>> + >>> @register( + ... conn, + ... "trivial-handler", + ... "ctingress.on_complete", + ... "success@example.com", + ... "failure@example.com", + ... ["demo", "anomaly-detection"] + ... ) + ... def trivial(btrdb, *args, **kwargs): + ... print(args, kwargs) + ... return "completed successfully" + +The library will also allow you to update an existing event handler using the register decorator. No extra steps are needed, just register the new version with the same hook and name, and the old one will get replaced. + + +Listing Registered Handlers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To view the existing event handlers, call the `list_handlers` function and a list of `Handler` objects will be returned. You may also provide an optional `hooks` argument in order to filter the results to only the hook/event you are interested in. + + +.. code-block:: python + + >>> from btrdbextras import Connection + >>> from btrdbextras.eventproc import list_handlers + >>> conn = Connection() + >>> + >>> list_handlers(conn) + [Handler(id=3, name='sample-73', hook='ctingress.on_complete', version=0, notify_on_success='success@example.com', notify_on_failure='failure@example.com', flags=['red', 'blue'], created_at=datetime.datetime(2020, 10, 21, 21, 35, 20, 365664, tzinfo=), created_by='allen', updated_at=datetime.datetime(2020, 10, 21, 21, 35, 20, 365664, tzinfo=), updated_by='allen')] + +The `Handler` object is just a lightweight `namedtuple` and does not offer any functionality itself. + +Deleting Existing Handlers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The remove an existing event handler, a `deregister` function is available. It requires only the ID of your handler which was determined when you first registered. You can use `list_handlers` to find the ID for your handler if needed. + +.. code-block:: python + + >>> from btrdbextras import Connection + >>> from btrdbextras.eventproc import list_handlers, deregister + >>> conn = Connection() + >>> + >>> list_handlers(conn) + [Handler(id=5, name='trivial-handler', hook='ctingress.on_complete', version=0, notify_on_success='success@example.com', notify_on_failure='failure@example.com', flags=['demo', 'anomaly-detection'], created_at=datetime.datetime(2020, 10, 23, 15, 6, 48, 390720, tzinfo=), created_by='allen', updated_at=datetime.datetime(2020, 10, 23, 15, 6, 48, 390720, tzinfo=), updated_by='allen')] + >>> + >>> deregister(conn, 5) + True + + +Troubleshooting +-------------------------- + +At the moment there are only a few troubleshooting tips however we expect to add more content over time. + +Most importantly, ensure you are using Python 3.7.3. This is the version supplied by our Juupyter servers so you should be fine on this front unless you are making calls on your local machine. In the future we plan on providing support for all versions of Python greater than 3.6.0. + + +Hooks +-------------------------- + +The available hooks are listed below. Over time new hooks will be added to the platform. + +ctingress.on_complete +~~~~~~~~~~~~~~~~~~~~~ + +Event handlers for this hook will be executed after processing an entire archive of COMTRADE files. The signature for your event handler should match the following arguments: + +handler(btrdb, uuids): + A function that is executed after the COMTRADE ingress processes a new + archive containing COMTRADE data. + + Parameters + ---------- + btrdb + A Python btrdb connection object for querying the time series database. + uuids + A list of UUIDs (as string) representing streams that were involved in the + data import. diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..793eb5b --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,25 @@ +.. btrdbextras documentation master file, created by + sphinx-quickstart on Thu Oct 22 13:37:42 2020. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +btrdbextras: Add-ons for btrdb +======================================= + +This software library contains helpful utlities and new functionality when interacting with the BTrDB database or the PingThings PredictiveGrid platform. See the individual pages below for more information. + + +User Guide +---------- + +The remaining documentation can be found below. If there is anything you'd like +added or corrected, please feel free to submit a pull request or open an issue +in Github! + + +.. toctree:: + :maxdepth: 2 + + installing + eventproc + api diff --git a/docs/source/installing.rst b/docs/source/installing.rst new file mode 100644 index 0000000..50dfba4 --- /dev/null +++ b/docs/source/installing.rst @@ -0,0 +1,20 @@ +Installing +======================== + +The btrdbextras package has only a few requirements and is relatively easy to install. + +Installing with pip +------------------- + +We recommend using pip to install btrdb-python on all platforms: + +.. code-block:: bash + + $ pip install btrdbextras + +To upgrade using pip: + +.. code-block:: bash + + $ pip install -U btrdbextras + diff --git a/requirements.txt b/requirements.txt index e69de29..76ea18b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -0,0 +1,6 @@ +# GRPC / Protobuff related +grpcio>=1.16.1 +grpcio-tools>=1.16.1 + +# Serialization helpers +dill==0.3.2 \ No newline at end of file diff --git a/setup.py b/setup.py index e69de29..d5c5592 100644 --- a/setup.py +++ b/setup.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python +# setup +# Setup script for installing btrdb bindings +# +# Author: PingThings +# Created: Mon Jan 07 14:45:32 2019 -0500 +# +# For license information, see LICENSE.txt +# ID: setup.py [] allen@pingthings.io $ + +""" +Setup script for installing btrdb bindings. +""" + +########################################################################## +## Imports +########################################################################## + +import os +import codecs + +from setuptools import setup +from setuptools import find_packages + +from btrdbextras import __version__ + +########################################################################## +## Package Information +########################################################################## + +## Basic information +NAME = "btrdbextras" +DESCRIPTION = "Enhancements additional features to interact with the Berkeley Tree Database" +AUTHOR = "Allen Leis" +EMAIL = "allen@pingthings.io" +MAINTAINER = "Allen Leis" +LICENSE = "BSD-3-Clause" +REPOSITORY = "https://github.com/PingThingsIO/btrdbextras" +PACKAGE = "btrdb" +URL = "https://btrdbextras.readthedocs.io/en/latest/" +DOCS_URL = "https://btrdbextras.readthedocs.io/en/latest/" + +## Define the keywords +KEYWORDS = ('btrdb', 'timeseries', 'database') + +## Define the classifiers +## See https://pypi.python.org/pypi?%3Aaction=list_classifiers +CLASSIFIERS = ( + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: BSD License', + 'Natural Language :: English', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Topic :: Database', + 'Topic :: Software Development :: Libraries :: Python Modules', +) + +## Important Paths +PROJECT = os.path.abspath(os.path.dirname(__file__)) +REQUIRE_PATH = "requirements.txt" +VERSION_PATH = os.path.join(PACKAGE, "version.py") +PKG_DESCRIBE = "DESCRIPTION.md" + +## Directories to ignore in find_packages +EXCLUDES = ( + "tests", "docs", +) + +########################################################################## +## Helper Functions +########################################################################## + +def read(*parts): + """ + Assume UTF-8 encoding and return the contents of the file located at the + absolute path from the REPOSITORY joined with *parts. + """ + with codecs.open(os.path.join(PROJECT, *parts), 'rb', 'utf-8') as f: + return f.read() + + +def get_requires(path=REQUIRE_PATH): + """ + Yields a generator of requirements as defined by the REQUIRE_PATH which + should point to a requirements.txt output by `pip freeze`. + """ + for line in read(path).splitlines(): + line = line.strip() + if line and not line.startswith('#'): + yield line + + +def get_description_type(path=PKG_DESCRIBE): + """ + Returns the long_description_content_type based on the extension of the + package describe path (e.g. .txt, .rst, or .md). + """ + _, ext = os.path.splitext(path) + return { + ".rst": "text/x-rst", + ".txt": "text/plain", + ".md": "text/markdown", + }[ext] + + +########################################################################## +## Define the configuration +########################################################################## + +config = { + "name": NAME, + "version": __version__, + "description": DESCRIPTION, + "long_description": read(PKG_DESCRIBE), + "long_description_content_type": get_description_type(PKG_DESCRIBE), + "classifiers": list(CLASSIFIERS), + "keywords": list(KEYWORDS), + "license": LICENSE, + "author": AUTHOR, + "author_email": EMAIL, + "url": URL, + "maintainer": MAINTAINER, + "maintainer_email": EMAIL, + "project_urls": { + "Documentation": DOCS_URL, + "Download": "{}/tarball/v{}".format(REPOSITORY, __version__), + "Source": REPOSITORY, + "Tracker": "{}/issues".format(REPOSITORY), + }, + "download_url": "{}/tarball/v{}".format(REPOSITORY, __version__), + "packages": find_packages(where=PROJECT, exclude=EXCLUDES), + "package_data": { + "btrdb": ["grpcinterface/btrdb.proto"], + }, + "zip_safe": False, + "entry_points": { + "console_scripts": [], + }, + "install_requires": list(get_requires()), + "python_requires": ">=3.6, <4", + "setup_requires":["pytest-runner"], + "tests_require":["pytest"], +} + + +########################################################################## +## Run setup script +########################################################################## + +if __name__ == '__main__': + setup(**config) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/requirements.txt b/tests/requirements.txt new file mode 100644 index 0000000..94366ed --- /dev/null +++ b/tests/requirements.txt @@ -0,0 +1,3 @@ +pytest==6.1.1 +pytest-cov==2.10.1 +pytest-flakes==4.0.2 diff --git a/tests/test_base.py b/tests/test_base.py new file mode 100644 index 0000000..f1c5431 --- /dev/null +++ b/tests/test_base.py @@ -0,0 +1,37 @@ +# tests.test_base +# Testing package for the btrdbextras library. +# +# Author: PingThings +# Created: Tue Oct 20 14:23:25 2020 -0500 +# +# For license information, see LICENSE.txt +# ID: test_base.py [] allen@pingthings.io $ + +""" +Testing package for the btrdb database library. +""" + +########################################################################## +## Imports +########################################################################## + +from btrdbextras import __version__ + +########################################################################## +## Test Constants +########################################################################## + +EXPECTED_VERSION = "v5.11.2" + + +########################################################################## +## Initialization Tests +########################################################################## + +class TestPackage(object): + + def test_version(self): + """ + Assert that the test version matches the library version. + """ + assert __version__ == EXPECTED_VERSION \ No newline at end of file