From b277b898c22e930206e2c78eca926826de65e1a1 Mon Sep 17 00:00:00 2001 From: Miguel Garcia Rubin Date: Wed, 20 Nov 2019 15:33:49 +0100 Subject: [PATCH 1/8] Memoize ConfFile per service --- pyms/config/conf.py | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/pyms/config/conf.py b/pyms/config/conf.py index 26ca191..fc5541d 100644 --- a/pyms/config/conf.py +++ b/pyms/config/conf.py @@ -2,28 +2,13 @@ from pyms.exceptions import ServiceDoesNotExistException -class Config: - service = None - _config = False +__service_configs = {} - def __init__(self): - pass - def config(self, *args, **kwargs): - """Set the configuration, if our yaml file is like: - myservice: - myservice1: - myvar1 - and we want to get the configuration of service1, our self.service will be "myservice.myservice1" - """ - if not self._config: - self._config = ConfFile(*args, **kwargs) - if not self.service: - raise ServiceDoesNotExistException("Service not defined") - return getattr(self._config, self.service) - - -def get_conf(service=None, *args, **kwargs): - config = Config() - config.service = service - return config.config(*args, **kwargs) +def get_conf(*args, **kwargs): + service = kwargs.pop('service', None) + if not service: + raise ServiceDoesNotExistException("Service not defined") + if service not in __service_configs: + __service_configs[service] = ConfFile(*args, **kwargs) + return getattr(__service_configs[service], service) From 5658dd5544fa31326fe0d55b64b7d923a2f62fb8 Mon Sep 17 00:00:00 2001 From: Miguel Garcia Rubin Date: Wed, 20 Nov 2019 15:34:32 +0100 Subject: [PATCH 2/8] WIP: fix tests --- tests/test_config.py | 24 ++++++++++++------------ tests/test_flask.py | 25 ++++++++++++++++--------- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/tests/test_config.py b/tests/test_config.py index d014ee3..e32c173 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -2,7 +2,7 @@ import os import unittest -from pyms.config.conf import Config +# from pyms.config.conf import Config from pyms.config.confile import ConfFile from pyms.constants import CONFIGMAP_FILE_ENVIRONMENT, LOGGER_NAME from pyms.exceptions import AttrDoesNotExistException, ConfigDoesNotFoundException, ServiceDoesNotExistException @@ -89,20 +89,20 @@ def test_example_test_json_file(self): self.assertEqual(config.my_ms.test_var, "general") -class ConfServiceTests(unittest.TestCase): +# class ConfServiceTests(unittest.TestCase): - def test_config_with_service(self): - class MyService(Config): - service = "service" +# def test_config_with_service(self): +# class MyService(Config): +# service = "service" - config = MyService() - configuration = config.config(config={"service": {"service1": "a", "service2": "b"}}) - self.assertEqual(configuration.service1, "a") +# config = MyService() +# configuration = config.config(config={"service": {"service1": "a", "service2": "b"}}) +# self.assertEqual(configuration.service1, "a") - def test_config_with_service_not_exist(self): - config = Config() - with self.assertRaises(ServiceDoesNotExistException): - configuration = config.config(config={"service": {"service1": "a", "service2": "b"}}) +# def test_config_with_service_not_exist(self): +# config = Config() +# with self.assertRaises(ServiceDoesNotExistException): +# configuration = config.config(config={"service": {"service1": "a", "service2": "b"}}) class ConfNotExistTests(unittest.TestCase): diff --git a/tests/test_flask.py b/tests/test_flask.py index 14da4d6..2f1bb10 100644 --- a/tests/test_flask.py +++ b/tests/test_flask.py @@ -1,5 +1,6 @@ import os import unittest +from unittest import mock import pytest from flask import current_app @@ -68,22 +69,28 @@ def test_import_config_without_create_app(self): ms1 = MyMicroservice(service="my-ms", path=__file__, override_instance=True) self.assertEqual(ms1.config.subservice1, config().subservice1) + def test_config_singleton(self): + conf_one = config().subservice1 + conf_two = config().subservice1 + + assert conf_one is conf_two + @pytest.mark.parametrize("payload, configfile, status_code", [ ( - "Python Microservice", - "config-tests.yml", - 200 + "Python Microservice", + "config-tests.yml", + 200 ), ( - "Python Microservice With Flask", - "config-tests-flask.yml", - 404 + "Python Microservice With Flask", + "config-tests-flask.yml", + 404 ), ( - "Python Microservice With Flask and Lightstep", - "config-tests-flask-trace-lightstep.yml", - 200 + "Python Microservice With Flask and Lightstep", + "config-tests-flask-trace-lightstep.yml", + 200 ) ]) def test_configfiles(payload, configfile, status_code): From 656b498772babc85293caf4a677a5c6990548a42 Mon Sep 17 00:00:00 2001 From: Miguel Garcia Rubin Date: Thu, 28 Nov 2019 13:51:20 +0100 Subject: [PATCH 3/8] Update Connexion Framework, parametrize memoizing --- Pipfile | 2 +- Pipfile.lock | 274 +++++++++++++++++++++++------------ pyms/config/conf.py | 3 +- pyms/flask/app/create_app.py | 2 +- 4 files changed, 186 insertions(+), 95 deletions(-) diff --git a/Pipfile b/Pipfile index 663f689..22b9fe6 100644 --- a/Pipfile +++ b/Pipfile @@ -9,7 +9,7 @@ python-json-logger = ">=0.1.10" pyyaml = ">=5.1.2" anyconfig = ">=0.9.8" swagger-ui-bundle = ">=0.0.2" -connexion = {extras = ["swagger-ui"],version = ">=2.2.0"} +connexion = {extras = ["swagger-ui"],version = "==2.4.0"} jaeger-client = "==4.1.0" flask-opentracing = "*" opentracing = ">=2.1" diff --git a/Pipfile.lock b/Pipfile.lock index 7b1f45c..75c7c79 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "1388af3b70241985d77207fcf801afa2cc9ce5b2ec2363b282b88e405fb5fef4" + "sha256": "46717e53a0a7b838196e1d835cd574369f0cccc9a4ecb42c2e96577663ff8ee1" }, "pipfile-spec": 6, "requires": { @@ -23,12 +23,19 @@ "index": "pypi", "version": "==0.9.10" }, + "attrs": { + "hashes": [ + "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", + "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72" + ], + "version": "==19.3.0" + }, "certifi": { "hashes": [ - "sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50", - "sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef" + "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3", + "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f" ], - "version": "==2019.9.11" + "version": "==2019.11.28" }, "chardet": { "hashes": [ @@ -56,10 +63,11 @@ "swagger-ui" ], "hashes": [ - "sha256:e74544e382f732f97ec1c7d05a9d79e2c101e135f606a776e5f8dd1c478ff7e0" + "sha256:6e0569b646f2e6229923dc4e4c6e0325e223978bd19105779fd81e16bcb22fdf", + "sha256:7b4268e9ea837241e530738b35040345b78c8748d05d2c22805350aca0cd5b1c" ], "index": "pypi", - "version": "==2018.0.dev1" + "version": "==2.4.0" }, "contextlib2": { "hashes": [ @@ -96,6 +104,14 @@ ], "version": "==2.8" }, + "importlib-metadata": { + "hashes": [ + "sha256:aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26", + "sha256:d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af" + ], + "markers": "python_version < '3.8'", + "version": "==0.23" + }, "inflection": { "hashes": [ "sha256:18ea7fb7a7d152853386523def08736aa8c32636b047ade55f7578c4edeb16ca" @@ -125,10 +141,10 @@ }, "jsonschema": { "hashes": [ - "sha256:000e68abd33c972a5248544925a0cae7d1125f9bf6c58280d37546b946769a08", - "sha256:6ff5f3180870836cae40f06fa10419f557208175f13ad7bc26caa77beb1f6e02" + "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163", + "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a" ], - "version": "==2.6.0" + "version": "==3.2.0" }, "markupsafe": { "hashes": [ @@ -163,6 +179,13 @@ ], "version": "==1.1.1" }, + "more-itertools": { + "hashes": [ + "sha256:409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832", + "sha256:92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4" + ], + "version": "==7.2.0" + }, "openapi-spec-validator": { "hashes": [ "sha256:0caacd9829e9e3051e830165367bf58d436d9487b29a09220fa7edb9f47ff81b", @@ -186,6 +209,12 @@ "index": "pypi", "version": "==3.2.1" }, + "pyrsistent": { + "hashes": [ + "sha256:f3b280d030afb652f79d67c5586157c5c1355c9a58dfc7940566e28d28f3df1b" + ], + "version": "==0.15.6" + }, "python-json-logger": { "hashes": [ "sha256:b7a31162f2a01965a5efb94453ce69230ed208468b0bbc7fdfc56e6d8df2e281" @@ -195,22 +224,22 @@ }, "pyyaml": { "hashes": [ - "sha256:0113bc0ec2ad727182326b61326afa3d1d8280ae1122493553fd6f4397f33df9", - "sha256:01adf0b6c6f61bd11af6e10ca52b7d4057dd0be0343eb9283c878cf3af56aee4", - "sha256:5124373960b0b3f4aa7df1707e63e9f109b5263eca5976c66e08b1c552d4eaf8", - "sha256:5ca4f10adbddae56d824b2c09668e91219bb178a1eee1faa56af6f99f11bf696", - "sha256:7907be34ffa3c5a32b60b95f4d95ea25361c951383a894fec31be7252b2b6f34", - "sha256:7ec9b2a4ed5cad025c2278a1e6a19c011c80a3caaac804fd2d329e9cc2c287c9", - "sha256:87ae4c829bb25b9fe99cf71fbb2140c448f534e24c998cc60f39ae4f94396a73", - "sha256:9de9919becc9cc2ff03637872a440195ac4241c80536632fffeb6a1e25a74299", - "sha256:a5a85b10e450c66b49f98846937e8cfca1db3127a9d5d1e31ca45c3d0bef4c5b", - "sha256:b0997827b4f6a7c286c01c5f60384d218dca4ed7d9efa945c3e1aa623d5709ae", - "sha256:b631ef96d3222e62861443cc89d6563ba3eeb816eeb96b2629345ab795e53681", - "sha256:bf47c0607522fdbca6c9e817a6e81b08491de50f3766a7a0e6a5be7905961b41", - "sha256:f81025eddd0327c7d4cfe9b62cf33190e1e736cc6e97502b3ec425f574b3e7a8" + "sha256:05418379e70ae2e986d31cfb51b50bd0f93bf5ab9d9b40dabdb4616727c4c26e", + "sha256:37c31e6087df09321539c18b5b02382538354c350dc76f3b458a6c93745a545c", + "sha256:3fd57916529381a46619e1cbfe1d372c7e008d5945fb1953da4a03b195630c33", + "sha256:52559ed9a06e2775d5c7ec5d86932371a439d6594a21991589475894a399939b", + "sha256:79288cdd596f9b77687f9e363fabf74a71f0399034b2742a74b1ca1f0ba5285f", + "sha256:7f737a46c65635898a1cb19b2ddf4e0c906d3f2e422c995f828fb621f8fa856b", + "sha256:93c09bcfe50adc03bbfb74f665e680d984b1023e83d0b48c93f7e2a8e70ac4be", + "sha256:94641ee1659be00239882b74e824ca6bc6b0c42f3f63b772f8f42cfaacfc83ab", + "sha256:9af87170b8a6c8e3219139a7146835bde3f5532cc47553701829a111cb2a9313", + "sha256:b6bd554afb21407f503d7821b9b8a4c3e36d3eb3e8fee329aa138cb5bc4f4809", + "sha256:c41a87796b705a473db39d06c220b1f25616b8c92fb5ea5c7fe327d2dcd63eb3", + "sha256:f00cd88db394bab373bcdcc58ab2eb5c3c3e75a520c6fab084a66d0ecd8cf90c", + "sha256:f65ea27155c5401e493935abdb10929b6df66256f202b91d00e967e54411f3a0" ], "index": "pypi", - "version": "==5.1.2" + "version": "==5.2b1" }, "requests": { "hashes": [ @@ -221,19 +250,19 @@ }, "six": { "hashes": [ - "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", - "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + "sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd", + "sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66" ], - "version": "==1.12.0" + "version": "==1.13.0" }, "swagger-ui-bundle": { "hashes": [ - "sha256:01ae8fdb1fa4e034933e0874afdda0d433dcb94476fccb231b66fd5f49dac96c", - "sha256:802f160dd6fe1d6b8fa92c6a40f593ef52f87ad0f507b1170ad2067f03de4c01", - "sha256:e88bd0d8334d685440a85210ff1e1083a0caabd4c36fa061843067ff4c2ac680" + "sha256:49d2e12d60a6499e9d37ea37953b5d700f4e114edc7520fe918bae5eb693a20e", + "sha256:c5373b683487b1b914dccd23bcd9a3016afa2c2d1cda10f8713c0a9af0f91dd3", + "sha256:f776811855092c086dbb08216c8810a84accef8c76c796a135caa13645c5cc68" ], "index": "pypi", - "version": "==0.0.5" + "version": "==0.0.6" }, "threadloop": { "hashes": [ @@ -244,9 +273,9 @@ }, "thrift": { "hashes": [ - "sha256:7d59ac4fdcb2c58037ebd4a9da5f9a49e3e034bf75b3f26d9fe48ba3d8806e6b" + "sha256:9af1c86bf73433afc6010ed376a6c6aca2b54099cc0d61895f640870a9ae7d89" ], - "version": "==0.11.0" + "version": "==0.13.0" }, "tornado": { "hashes": [ @@ -262,10 +291,10 @@ }, "urllib3": { "hashes": [ - "sha256:3de946ffbed6e6746608990594d08faac602528ac7015ac28d33cee6a45b7398", - "sha256:9a107b99a5393caf59c7aa3c1249c16e6879447533d0887f4336dde834c7be86" + "sha256:a8a318824cc77d1fd4b2bec2ded92646630d7fe8619497b142c84a9e6f5a7293", + "sha256:f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745" ], - "version": "==1.25.6" + "version": "==1.25.7" }, "werkzeug": { "hashes": [ @@ -279,22 +308,22 @@ "sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1" ], "version": "==1.11.2" + }, + "zipp": { + "hashes": [ + "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", + "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335" + ], + "version": "==0.6.0" } }, "develop": { "astroid": { "hashes": [ - "sha256:09a3fba616519311f1af8a461f804b68f0370e100c9264a035aa7846d7852e33", - "sha256:5a79c9b4bd6c4be777424593f957c996e20beb5f74e0bc332f47713c6f675efe" + "sha256:71ea07f44df9568a75d0f354c49143a4575d90645e9fead6dfb52c26a85ed13a", + "sha256:840947ebfa8b58f318d42301cf8c0a20fd794a33b61cc4638e28e9e61ba32f42" ], - "version": "==2.3.2" - }, - "atomicwrites": { - "hashes": [ - "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4", - "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6" - ], - "version": "==1.3.0" + "version": "==2.3.3" }, "attrs": { "hashes": [ @@ -311,12 +340,18 @@ "index": "pypi", "version": "==1.6.2" }, + "basictracer": { + "hashes": [ + "sha256:00871fba2a3f5f1bad185ea28f5d4b70d337cba0807a5399043789b48fd6be99" + ], + "version": "==3.0.0" + }, "certifi": { "hashes": [ - "sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50", - "sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef" + "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3", + "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f" ], - "version": "==2019.9.11" + "version": "==2019.11.28" }, "chardet": { "hashes": [ @@ -391,10 +426,16 @@ }, "gitpython": { "hashes": [ - "sha256:3237caca1139d0a7aa072f6735f5fd2520de52195e0fa1d8b83a9b212a2498b2", - "sha256:a7d6bef0775f66ba47f25911d285bcd692ce9053837ff48a120c2b8cf3a71389" + "sha256:9c2398ffc3dcb3c40b27324b316f08a4f93ad646d5a6328cafbb871aa79f5e42", + "sha256:c155c6a2653593ccb300462f6ef533583a913e17857cfef8fc617c246b6dc245" ], - "version": "==3.0.4" + "version": "==3.0.5" + }, + "googleapis-common-protos": { + "hashes": [ + "sha256:e61b8ed5e36b976b487c6e7b15f31bb10c7a0ca7bd5c0e837f4afab64b53a0c6" + ], + "version": "==1.6.0" }, "idna": { "hashes": [ @@ -425,6 +466,13 @@ ], "version": "==2.10.3" }, + "jsonpickle": { + "hashes": [ + "sha256:d0c5a4e6cb4e58f6d5406bdded44365c2bcf9c836c4f52910cc9ba7245a59dc2", + "sha256:d3e922d781b1d0096df2dad89a2e1f47177d7969b596aea806a9d91b4626b29b" + ], + "version": "==1.2" + }, "lazy-object-proxy": { "hashes": [ "sha256:0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d", @@ -451,6 +499,14 @@ ], "version": "==1.4.3" }, + "lightstep": { + "hashes": [ + "sha256:149ffc031498405950e4c1ef972c58f1a6e641c9ca3961347ed4e1948b9c8bff", + "sha256:f565d8731c3a583c8e5ca4ba3be124d83103bf54cac2aa2952a5d194900dda79" + ], + "index": "pypi", + "version": "==4.1.0" + }, "livereload": { "hashes": [ "sha256:78d55f2c268a8823ba499305dcac64e28ddeb9a92571e12d543cd304faf5817b", @@ -520,6 +576,13 @@ ], "version": "==7.2.0" }, + "opentracing": { + "hashes": [ + "sha256:cfd231ba5c58f90bc277787e62861eb0c6e4af76e42957bec240bbdf71fb7e0e" + ], + "index": "pypi", + "version": "==2.2.0" + }, "packaging": { "hashes": [ "sha256:28b924174df7a2fa32c1953825ff29c61e2f5e082343165438812f00d3a7fc47", @@ -529,17 +592,38 @@ }, "pbr": { "hashes": [ - "sha256:2c8e420cd4ed4cec4e7999ee47409e876af575d4c35a45840d59e8b5f3155ab8", - "sha256:b32c8ccaac7b1a20c0ce00ce317642e6cf231cf038f9875e0280e28af5bf7ac9" + "sha256:139d2625547dbfa5fb0b81daebb39601c478c21956dc57e2e07b74450a8c506b", + "sha256:61aa52a0f18b71c5cc58232d2cf8f8d09cd67fcad60b742a60124cb8d6951488" ], - "version": "==5.4.3" + "version": "==5.4.4" }, "pluggy": { "hashes": [ - "sha256:0db4b7601aae1d35b4a033282da476845aa19185c1e6964b25cf324b5e4ec3e6", - "sha256:fa5fa1622fa6dd5c030e9cad086fa19ef6a0cf6d7a2d12318e10cb49d6d68f34" + "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", + "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" ], - "version": "==0.13.0" + "version": "==0.13.1" + }, + "protobuf": { + "hashes": [ + "sha256:0ba5d7626dbc4ce78971c3e62ec37f84c8139ea7008c008660d3312cf11e0db8", + "sha256:189b706f72e8b7ddc965168a79ff296ca5b7bdd95b5b05208afb9818a681c712", + "sha256:340965444aafc7aac7e3586e930f5b3f8347ca9b350afab60bac84dcc0b94437", + "sha256:44fbc7b1786ab975ec9eba9da765398d58ec705d1c8e856b0523b8f9c1c53cf7", + "sha256:48d96b559fab3063feaebd316352e3418424629d59b77dbcb96ecc4c594d7f5f", + "sha256:5e32923c7896c49b1d3a327fe25a76363d200acdfa97844f5647f1bf9f298da8", + "sha256:6662442fbf22796dbd942bb15b664d70dcc25ae28d371b7e4ca6261e9bc495b7", + "sha256:6bb5d999faceee281bc4a2fc77866c61af7be4b7e5efadc930c42f234a99cafd", + "sha256:83b38b7b61b7c60af0fa03a71c27c4232117453a62ccf69a511284793a400751", + "sha256:90c22f4fd4e01279efc4e4911dafe308f35fcc4310bcb89bcee4d3ca20210d20", + "sha256:97b08853b9bb71512ed52381f05cf2d4179f4234825b505d8f8d2bb9d9429939", + "sha256:aef47082114428b47db73876ecb7751802548830ce5c95dba7ebe24d5e196d7c", + "sha256:b89ed3ba88ea5ec8b2c704a5ae747c9038ee1faff277fcddac75f850e645f7e1", + "sha256:be5afc2e1f5c320bd4a38e73d8b02c67d72dbee370a004732c923c7c8a472f72", + "sha256:d1c18853c7ad3c8e34edfafc6488fc24f4221c15b516c14796032cc53f8cde94", + "sha256:f4370d0e3d6e1ac2f80911651691ac540901f661b372036ea72637546ba98202" + ], + "version": "==3.11.0" }, "py": { "hashes": [ @@ -550,26 +634,26 @@ }, "pylint": { "hashes": [ - "sha256:7b76045426c650d2b0f02fc47c14d7934d17898779da95288a74c2a7ec440702", - "sha256:856476331f3e26598017290fd65bebe81c960e806776f324093a46b76fb2d1c0" + "sha256:3db5468ad013380e987410a8d6956226963aed94ecb5f9d3a28acca6d9ac36cd", + "sha256:886e6afc935ea2590b462664b161ca9a5e40168ea99e5300935f6591ad467df4" ], "index": "pypi", - "version": "==2.4.3" + "version": "==2.4.4" }, "pyparsing": { "hashes": [ - "sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", - "sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4" + "sha256:20f995ecd72f2a1f4bf6b072b63b22e2eb457836601e76d6e5dfcd75436acc1f", + "sha256:4ca62001be367f01bd3e92ecbb79070272a9d4964dce6a48a82ff0b8bc7e683a" ], - "version": "==2.4.2" + "version": "==2.4.5" }, "pytest": { "hashes": [ - "sha256:27abc3fef618a01bebb1f0d6d303d2816a99aa87a5968ebc32fe971be91eb1e6", - "sha256:58cee9e09242937e136dbb3dab466116ba20d6b7828c7620f23947f37eb4dae4" + "sha256:63344a2e3bce2e4d522fd62b4fdebb647c019f1f9e4ca075debbd13219db4418", + "sha256:f67403f33b2b1d25a6756184077394167fe5e2f9d8bdaab30707d19ccec35427" ], "index": "pypi", - "version": "==5.2.2" + "version": "==5.3.1" }, "pytest-cov": { "hashes": [ @@ -581,22 +665,22 @@ }, "pyyaml": { "hashes": [ - "sha256:0113bc0ec2ad727182326b61326afa3d1d8280ae1122493553fd6f4397f33df9", - "sha256:01adf0b6c6f61bd11af6e10ca52b7d4057dd0be0343eb9283c878cf3af56aee4", - "sha256:5124373960b0b3f4aa7df1707e63e9f109b5263eca5976c66e08b1c552d4eaf8", - "sha256:5ca4f10adbddae56d824b2c09668e91219bb178a1eee1faa56af6f99f11bf696", - "sha256:7907be34ffa3c5a32b60b95f4d95ea25361c951383a894fec31be7252b2b6f34", - "sha256:7ec9b2a4ed5cad025c2278a1e6a19c011c80a3caaac804fd2d329e9cc2c287c9", - "sha256:87ae4c829bb25b9fe99cf71fbb2140c448f534e24c998cc60f39ae4f94396a73", - "sha256:9de9919becc9cc2ff03637872a440195ac4241c80536632fffeb6a1e25a74299", - "sha256:a5a85b10e450c66b49f98846937e8cfca1db3127a9d5d1e31ca45c3d0bef4c5b", - "sha256:b0997827b4f6a7c286c01c5f60384d218dca4ed7d9efa945c3e1aa623d5709ae", - "sha256:b631ef96d3222e62861443cc89d6563ba3eeb816eeb96b2629345ab795e53681", - "sha256:bf47c0607522fdbca6c9e817a6e81b08491de50f3766a7a0e6a5be7905961b41", - "sha256:f81025eddd0327c7d4cfe9b62cf33190e1e736cc6e97502b3ec425f574b3e7a8" + "sha256:05418379e70ae2e986d31cfb51b50bd0f93bf5ab9d9b40dabdb4616727c4c26e", + "sha256:37c31e6087df09321539c18b5b02382538354c350dc76f3b458a6c93745a545c", + "sha256:3fd57916529381a46619e1cbfe1d372c7e008d5945fb1953da4a03b195630c33", + "sha256:52559ed9a06e2775d5c7ec5d86932371a439d6594a21991589475894a399939b", + "sha256:79288cdd596f9b77687f9e363fabf74a71f0399034b2742a74b1ca1f0ba5285f", + "sha256:7f737a46c65635898a1cb19b2ddf4e0c906d3f2e422c995f828fb621f8fa856b", + "sha256:93c09bcfe50adc03bbfb74f665e680d984b1023e83d0b48c93f7e2a8e70ac4be", + "sha256:94641ee1659be00239882b74e824ca6bc6b0c42f3f63b772f8f42cfaacfc83ab", + "sha256:9af87170b8a6c8e3219139a7146835bde3f5532cc47553701829a111cb2a9313", + "sha256:b6bd554afb21407f503d7821b9b8a4c3e36d3eb3e8fee329aa138cb5bc4f4809", + "sha256:c41a87796b705a473db39d06c220b1f25616b8c92fb5ea5c7fe327d2dcd63eb3", + "sha256:f00cd88db394bab373bcdcc58ab2eb5c3c3e75a520c6fab084a66d0ecd8cf90c", + "sha256:f65ea27155c5401e493935abdb10929b6df66256f202b91d00e967e54411f3a0" ], "index": "pypi", - "version": "==5.1.2" + "version": "==5.2b1" }, "requests": { "hashes": [ @@ -623,10 +707,10 @@ }, "six": { "hashes": [ - "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", - "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + "sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd", + "sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66" ], - "version": "==1.12.0" + "version": "==1.13.0" }, "smmap2": { "hashes": [ @@ -642,6 +726,12 @@ ], "version": "==1.31.0" }, + "thrift": { + "hashes": [ + "sha256:9af1c86bf73433afc6010ed376a6c6aca2b54099cc0d61895f640870a9ae7d89" + ], + "version": "==0.13.0" + }, "toml": { "hashes": [ "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", @@ -663,11 +753,11 @@ }, "tox": { "hashes": [ - "sha256:0bc216b6a2e6afe764476b4a07edf2c1dab99ed82bb146a1130b2e828f5bff5e", - "sha256:c4f6b319c20ba4913dbfe71ebfd14ff95d1853c4231493608182f66e566ecfe1" + "sha256:1d1368ac86e8332f79e2bcef9fefe2b077469f08449eadf0183759b34f3b2070", + "sha256:bcfa3e40abc1e9b70607b56adfd976fe7dc8286ad56aab44e3151daca7d2d0d0" ], "index": "pypi", - "version": "==3.14.0" + "version": "==3.14.1" }, "typed-ast": { "hashes": [ @@ -697,17 +787,17 @@ }, "urllib3": { "hashes": [ - "sha256:3de946ffbed6e6746608990594d08faac602528ac7015ac28d33cee6a45b7398", - "sha256:9a107b99a5393caf59c7aa3c1249c16e6879447533d0887f4336dde834c7be86" + "sha256:a8a318824cc77d1fd4b2bec2ded92646630d7fe8619497b142c84a9e6f5a7293", + "sha256:f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745" ], - "version": "==1.25.6" + "version": "==1.25.7" }, "virtualenv": { "hashes": [ - "sha256:11cb4608930d5fd3afb545ecf8db83fa50e1f96fc4fca80c94b07d2c83146589", - "sha256:d257bb3773e48cac60e475a19b608996c73f4d333b3ba2e4e57d5ac6134e0136" + "sha256:116655188441670978117d0ebb6451eb6a7526f9ae0796cc0dee6bd7356909b0", + "sha256:b57776b44f91511866594e477dd10e76a6eb44439cdd7f06dcd30ba4c5bd854f" ], - "version": "==16.7.7" + "version": "==16.7.8" }, "wcwidth": { "hashes": [ diff --git a/pyms/config/conf.py b/pyms/config/conf.py index fc5541d..993ded2 100644 --- a/pyms/config/conf.py +++ b/pyms/config/conf.py @@ -7,8 +7,9 @@ def get_conf(*args, **kwargs): service = kwargs.pop('service', None) + memoize = kwargs.pop('memoize', True) if not service: raise ServiceDoesNotExistException("Service not defined") - if service not in __service_configs: + if not memoize or service not in __service_configs: __service_configs[service] = ConfFile(*args, **kwargs) return getattr(__service_configs[service], service) diff --git a/pyms/flask/app/create_app.py b/pyms/flask/app/create_app.py index 293974e..33f1af4 100644 --- a/pyms/flask/app/create_app.py +++ b/pyms/flask/app/create_app.py @@ -44,7 +44,7 @@ class Microservice(metaclass=SingletonMeta): def __init__(self, *args, **kwargs): self.service = kwargs.get("service", os.environ.get(SERVICE_ENVIRONMENT, "ms")) self.path = os.path.dirname(kwargs.get("path", __file__)) - self.config = get_conf(service=self.service) + self.config = get_conf(service=self.service, memoize=self._singleton) self.init_services() def init_services(self): From 903878f3977579aad2c24ca85f4bf76a8b018c55 Mon Sep 17 00:00:00 2001 From: Miguel Date: Thu, 28 Nov 2019 21:03:56 +0100 Subject: [PATCH 4/8] Makefile for testing --- Makefile | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1be9444 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +test: clean-pyc + pytest + +coverage: clean-pyc + coverage run -m pytest + coverage report + coverage html + +clean-pyc: + find . -name '*.pyc' -exec rm -f {} + + find . -name '*.pyo' -exec rm -f {} + + find . -name '*~' -exec rm -f {} + + find . -name '__pycache__' -exec rm -d {} + \ No newline at end of file From b991a3e71830737eb9ce2372eb2c6726749ee794 Mon Sep 17 00:00:00 2001 From: Miguel Date: Thu, 28 Nov 2019 21:04:55 +0100 Subject: [PATCH 5/8] Fix ServicesManager config --- pyms/flask/services/driver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyms/flask/services/driver.py b/pyms/flask/services/driver.py index 26a2cef..de60fe9 100644 --- a/pyms/flask/services/driver.py +++ b/pyms/flask/services/driver.py @@ -25,7 +25,7 @@ class ServicesManager: def __init__(self, service=None): self.service = (service if service else SERVICE_BASE) - self.config = get_conf(service=self.service, empty_init=True) + self.config = get_conf(service=self.service, empty_init=True, memoize=False) def get_services(self): return ((k, self.get_service(k)) for k in self.config.__dict__.keys() if k not in ['empty_init', ]) From 4bbb8108a9cc87f98c792db578406784636eac23 Mon Sep 17 00:00:00 2001 From: Miguel Date: Thu, 28 Nov 2019 21:05:25 +0100 Subject: [PATCH 6/8] Testing get_config memoized --- tests/test_config.py | 57 +++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/tests/test_config.py b/tests/test_config.py index e32c173..6a984ae 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,8 +1,9 @@ import logging import os import unittest +from unittest import mock -# from pyms.config.conf import Config +from pyms.config.conf import get_conf from pyms.config.confile import ConfFile from pyms.constants import CONFIGMAP_FILE_ENVIRONMENT, LOGGER_NAME from pyms.exceptions import AttrDoesNotExistException, ConfigDoesNotFoundException, ServiceDoesNotExistException @@ -89,22 +90,6 @@ def test_example_test_json_file(self): self.assertEqual(config.my_ms.test_var, "general") -# class ConfServiceTests(unittest.TestCase): - -# def test_config_with_service(self): -# class MyService(Config): -# service = "service" - -# config = MyService() -# configuration = config.config(config={"service": {"service1": "a", "service2": "b"}}) -# self.assertEqual(configuration.service1, "a") - -# def test_config_with_service_not_exist(self): -# config = Config() -# with self.assertRaises(ServiceDoesNotExistException): -# configuration = config.config(config={"service": {"service1": "a", "service2": "b"}}) - - class ConfNotExistTests(unittest.TestCase): def test_empty_conf(self): config = ConfFile(empty_init=True) @@ -119,5 +104,43 @@ def test_empty_conf_three_levels(self): self.assertEqual(config.my_ms.level_two.level_three, {}) + +class GetConfig(unittest.TestCase): + BASE_DIR = os.path.dirname(os.path.abspath(__file__)) + + def setUp(self): + os.environ[CONFIGMAP_FILE_ENVIRONMENT] = os.path.join(self.BASE_DIR, "config-tests.yml") + + def tearDown(self): + del os.environ[CONFIGMAP_FILE_ENVIRONMENT] + + def test_default(self): + config = get_conf(service="my-ms") + + assert config.APP_NAME == "Python Microservice" + assert config.subservice1.test == "input" + + @mock.patch('pyms.config.conf.ConfFile') + def test_memoized(self, mock_confile): + mock_confile.pyms = {} + get_conf(service="pyms") + get_conf(service="pyms") + + mock_confile.assert_called_once() + + @mock.patch('pyms.config.conf.ConfFile') + def test_without_memoize(self, mock_confile): + mock_confile.pyms = {} + get_conf(service="pyms", memoize=False) + get_conf(service="pyms", memoize=False) + + assert mock_confile.call_count == 2 + + @mock.patch('pyms.config.conf.ConfFile') + def test_without_params(self, mock_confile): + with self.assertRaises(ServiceDoesNotExistException): + get_conf() + + if __name__ == '__main__': unittest.main() From 9fa43db87e238b8951feb1741f7d0c1826d0f974 Mon Sep 17 00:00:00 2001 From: Miguel Date: Thu, 28 Nov 2019 21:49:06 +0100 Subject: [PATCH 7/8] Increase test coverage --- tests/test_config.py | 12 ++++++++---- tests/test_flask.py | 6 ++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/test_config.py b/tests/test_config.py index 6a984ae..7b00697 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -68,6 +68,14 @@ def test_equal_instances_ok2(self): config2 = {"test_1": {"test_1_1": "a", "test_1_2": "b"}} self.assertEqual(config1, config2) + def test_equal_instances_ko(self): + config = ConfFile(config={"test-1": {"test-1-1": "a"}}) + no_valid_type = ConfigDoesNotFoundException + + result = config == no_valid_type + + self.assertEqual(result, False) + def test_dictionary_attribute_not_exists(self): config = ConfFile(config={"test-1": "a"}) with self.assertRaises(AttrDoesNotExistException): @@ -140,7 +148,3 @@ def test_without_memoize(self, mock_confile): def test_without_params(self, mock_confile): with self.assertRaises(ServiceDoesNotExistException): get_conf() - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_flask.py b/tests/test_flask.py index 2f1bb10..e2548c9 100644 --- a/tests/test_flask.py +++ b/tests/test_flask.py @@ -39,6 +39,12 @@ def test_home(self): response = self.client.get('/') self.assertEqual(404, response.status_code) + def test_healthcheck(self): + response = self.client.get('/healthcheck') + self.assertEqual(b"OK", response.data) + self.assertEqual(200, response.status_code) + + class MicroserviceTest(unittest.TestCase): """ From c5f5e0576907c9650e94cfb633b02bf86b8286c6 Mon Sep 17 00:00:00 2001 From: Miguel Date: Sat, 30 Nov 2019 12:17:14 +0100 Subject: [PATCH 8/8] Remove Makefile, more requests tests --- Makefile | 13 ------------- tests/test_requests.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 13 deletions(-) delete mode 100644 Makefile diff --git a/Makefile b/Makefile deleted file mode 100644 index 1be9444..0000000 --- a/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -test: clean-pyc - pytest - -coverage: clean-pyc - coverage run -m pytest - coverage report - coverage html - -clean-pyc: - find . -name '*.pyc' -exec rm -f {} + - find . -name '*.pyo' -exec rm -f {} + - find . -name '*~' -exec rm -f {} + - find . -name '__pycache__' -exec rm -d {} + \ No newline at end of file diff --git a/tests/test_requests.py b/tests/test_requests.py index d8529e1..bf27c2a 100644 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -268,6 +268,35 @@ def test_propagate_headers_propagate_no_override(self): self.assertEqual(expected_headers, headers) + def test_propagate_headers_on_get(self): + url = "http://www.my-site.com/users" + mock_headers = { + 'A': 'b', + } + self.request.propagate_headers = unittest.mock.Mock() + self.request.propagate_headers.return_value = mock_headers + with self.app.test_request_context( + '/tests/', data={'format': 'short'}, headers=mock_headers): + self.request.get(url, propagate_headers=True) + + self.request.propagate_headers.assert_called_once_with({}) + + def test_propagate_headers_on_get_with_headers(self): + url = "http://www.my-site.com/users" + mock_headers = { + 'A': 'b', + } + get_headers = { + 'C': 'd', + } + self.request.propagate_headers = unittest.mock.Mock() + self.request.propagate_headers.return_value = mock_headers + with self.app.test_request_context( + '/tests/', data={'format': 'short'}, headers=mock_headers): + self.request.get(url, headers=get_headers, propagate_headers=True) + + self.request.propagate_headers.assert_called_once_with(get_headers) + @requests_mock.Mocker() def test_retries_with_500(self, mock_request): url = 'http://localhost:9999'