diff --git a/clients/python/.gitignore b/clients/python/.gitignore index ee3b4274..d2c614d5 100644 --- a/clients/python/.gitignore +++ b/clients/python/.gitignore @@ -1,141 +1,51 @@ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] -*$py.class # C extensions *.so # Distribution / packaging -.Python +bin/ 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 -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ # Translations *.mo -*.pot -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal +# Mr Developer +.mr.developer.cfg +.project +.pydevproject -# Flask stuff: -instance/ -.webassets-cache +# Rope +.ropeproject -# Scrapy stuff: -.scrapy +# Django stuff: +*.log +*.pot # Sphinx documentation docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# 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/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -#special -.desc +*.desc diff --git a/clients/python/README.md b/clients/python/README.md index 613593e0..c16b8edb 100644 --- a/clients/python/README.md +++ b/clients/python/README.md @@ -16,9 +16,9 @@ It has following features ## Installation -Use `pip` +Install it via git reference ``` -pip3 install stencil-python-client +stencil-python-client = { git = "git+https://github.com/raystack/stencil.git", subdirectory = "clients/python"} ``` Then import the stencil package into your own code as mentioned below diff --git a/clients/python/conftest.py b/clients/python/conftest.py index 02a545de..e946b0b7 100644 --- a/clients/python/conftest.py +++ b/clients/python/conftest.py @@ -3,11 +3,12 @@ import pytest import os + @pytest.fixture(scope="session") def protoc_setup(): - print('Do protoc') current_dir = os.path.dirname(os.path.realpath(__file__)) output_file = os.path.join(current_dir, 'test/data/one.desc') - + input_dir = os.path.join(current_dir, 'test/data') - run(['protoc',f'--descriptor_set_out={output_file}','--include_imports',f'--proto_path={input_dir}','one.proto'], cwd=current_dir) + run(['protoc', f'--descriptor_set_out={output_file}', '--include_imports', f'--proto_path={input_dir}', + 'one.proto'], cwd=current_dir) diff --git a/clients/python/requirements.txt b/clients/python/requirements.txt index 5db6db97..a26171a8 100644 --- a/clients/python/requirements.txt +++ b/clients/python/requirements.txt @@ -1,6 +1,5 @@ protobuf==3.17.3 -pytest==6.0.1 +pytest==6.2.5 pytest-cov==2.12.1 -mock==4.0.3 schedule==1.1.0 -requests==2.26.0 \ No newline at end of file +requests==2.26.0 diff --git a/clients/python/src/raystack/stencil.py b/clients/python/src/raystack/stencil.py index 595a849b..3712c127 100644 --- a/clients/python/src/raystack/stencil.py +++ b/clients/python/src/raystack/stencil.py @@ -1,7 +1,9 @@ -from .store import Store from schedule import Scheduler from google.protobuf.message import Message +from raystack.store import Store + + class MultiUrlClient: def __init__(self, urls:list, interval=3600, auto_refresh=False) -> None: self._store = Store() @@ -11,20 +13,20 @@ def __init__(self, urls:list, interval=3600, auto_refresh=False) -> None: self._scheduler = Scheduler() if self._auto_refresh: self._scheduler.every(self._interval).seconds.do(self.refresh) - #TODO: check whether scheduler executed immediatelly or not - self.refresh() + self.refresh() def refresh(self): for url in self._urls: self._store.load(url=url) - def get_descriptor(self, name:str) -> Message: + def get_descriptor(self, name: str) -> Message: return self._store.get(name) - - def parse(self, name:str, data:bytes): + + def parse(self, name: str, data: bytes): msg = self.get_descriptor(name) return msg.ParseFromString(data) - + + class Client(MultiUrlClient): def __init__(self, url: str) -> None: super().__init__([url]) diff --git a/clients/python/src/raystack/store.py b/clients/python/src/raystack/store.py index 36e74261..a254fb21 100644 --- a/clients/python/src/raystack/store.py +++ b/clients/python/src/raystack/store.py @@ -1,21 +1,21 @@ -from google.protobuf.message import Message import requests from google.protobuf.descriptor_pb2 import FileDescriptorSet from google.protobuf.message import Message from google.protobuf.message_factory import GetMessages + class Store: def __init__(self): self.data = {} - + def get(self, name) -> Message: return self.data.get(name) - + def _load_from_url(self, url): result = requests.get(url, stream=True) return result.raw.read() - - def load(self, url:str=None, data:bytes=None): + + def load(self, url: str = None, data: bytes = None): if url: data = self._load_from_url(url) fds = FileDescriptorSet.FromString(data) diff --git a/clients/python/test/test_client.py b/clients/python/test/test_client.py index 4c1ab138..22eccbf3 100644 --- a/clients/python/test/test_client.py +++ b/clients/python/test/test_client.py @@ -1,13 +1,19 @@ +from unittest.mock import patch + +from google.protobuf.reflection import GeneratedProtocolMessageType + from src.raystack.stencil import Client from src.raystack.store import Store -from mock import patch URL = 'http://stencil.test/proto-descriptors/test/latest' + + def get_file_desc(): - with open('test/data/one.desc', 'rb') as myfile: + with open('data/one.desc', 'rb') as myfile: desc = myfile.read() return desc + def test_store(protoc_setup): file_desc = get_file_desc() store = Store() @@ -15,12 +21,12 @@ def test_store(protoc_setup): assert 'test.One' in store.data assert isinstance(store.get('test.One'), store.get('test.One').__class__) -@patch.object(Store, '_load_from_url') + +@patch('raystack.store.Store._load_from_url') def test_client(test_desc_from_url, protoc_setup): file_desc = get_file_desc() test_desc_from_url.return_value = file_desc - + client = Client(URL) - - assert client.get_descriptor('test.One') - assert client.get_descriptor('test.faile') is None + + assert isinstance(client.get_descriptor('test.One'), GeneratedProtocolMessageType)