Skip to content

Commit 8d25eaa

Browse files
authored
Acces to config out of Flask context (#55)
* Create Microservice class with singleton to import config in any file * Updated doc and examples * Updated dependencies * Updated tests dependencies * increment version
1 parent 1d42abe commit 8d25eaa

20 files changed

+488
-333
lines changed

.gitignore

+4-1
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,7 @@ pylintReport.txt
2222

2323
# Deploy
2424
build/
25-
dist/
25+
dist/
26+
27+
# other
28+
site/*

Pipfile

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ verify_ssl = true
44
name = "pypi"
55

66
[packages]
7-
flask = "*"
7+
flask = ">=1.1.1"
88
python-json-logger = ">=0.1.10"
9-
pyyaml = ">=4.2b4"
9+
pyyaml = ">=5.1.2"
1010
anyconfig = ">=0.9.8"
1111
swagger-ui-bundle = ">=0.0.2"
1212
connexion = {extras = ["swagger-ui"],version = ">=2.2.0"}
13-
lightstep = "*"
13+
lightstep = "==4.1.0"
1414
flask-opentracing = "*"
15+
opentracing = ">=2.0.0"
1516

1617
[dev-packages]
1718
requests-mock = "*"

Pipfile.lock

+120-115
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/configuration.md

+53-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
# Configuration
22

3+
## Create configuration
34
Each microservice needs a config file in yaml or json format to work with it. This configuration contains
4-
the Flask settings of your project and the [Services](services.md).
5+
the Flask settings of your project and the [Services](services.md). With this way to create configuration files, we
6+
solve two problems of the [12 Factor apps](https://12factor.net/):
7+
- Store config out of the code
8+
- Dev/prod parity: the configuration could be injected and not depends of our code, for example, Kubernetes config maps
59

610
a simple configuration file could be a config.yaml:
711

@@ -91,3 +95,51 @@ ms1-api:
9195
DEBUG: true
9296
TESTING: false
9397
```
98+
99+
## Import Configuration
100+
With pyms, all configuration is stored as flask configuration and it can be acceded from:
101+
102+
```python
103+
from flask import current_app;
104+
105+
def my_endpoint():
106+
print(current_app.config["DEBUG"])
107+
```
108+
109+
But, what happend if you need the configuration BEFORE Flask class is instanced? Imagine this case:
110+
111+
```python
112+
from flask import Blueprint, current_app
113+
from flask_restplus import Api
114+
115+
my_api_blueprint = Blueprint('api', __name__)
116+
117+
API = Api(
118+
my_api_blueprint,
119+
title='My Microservice',
120+
version=current_app.config["APP_VERSION"],
121+
description='Microservice to manage hierarchies',
122+
add_specs=True,
123+
)
124+
```
125+
126+
This raise a `'working outside of application context` error. Who can solve this problem?
127+
128+
```python
129+
from flask import Blueprint, current_app
130+
from flask_restplus import Api
131+
from pyms.flask.app import config
132+
133+
my_api_blueprint = Blueprint('api', __name__)
134+
135+
API = Api(
136+
my_api_blueprint,
137+
title='My Microservice',
138+
version=config().APP_VERSION,
139+
description='Microservice to manage hierarchies',
140+
add_specs=True,
141+
)
142+
```
143+
144+
**IMPORTANT:** If you use this method to get configuration out of context, you must set the `CONFIGMAP_SERVICE` or set
145+
the default key `ms` for your configuration block in your config.yml

examples/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from pyms.flask.app import Microservice
2+
3+
ms = Microservice(path=__file__)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
pyms:
2+
requests:
3+
data: ""
4+
swagger:
5+
path: ""
6+
file: "swagger.yaml"
7+
my-configure-microservice:
8+
DEBUG: true
9+
TESTING: false
10+
APP_NAME: "Python Microservice"
11+
APPLICATION_ROOT: ""
12+
request_variable_test: "this is a test"
13+
MyVar: "this is MyVar"
14+
test1: "ttest1"
15+
test2: "ttest2"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from examples.microservice_configuration import ms
2+
app = ms.create_app()
3+
4+
if __name__ == '__main__':
5+
"""
6+
run first:
7+
export CONFIGMAP_SERVICE=my-configure-microservice
8+
"""
9+
app.run()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
swagger: "2.0"
3+
info:
4+
description: "This is a sample server Test server"
5+
version: "1.0.0"
6+
title: "Swagger Test list"
7+
termsOfService: "http://swagger.io/terms/"
8+
contact:
9+
10+
license:
11+
name: "Apache 2.0"
12+
url: "http://www.apache.org/licenses/LICENSE-2.0.html"
13+
tags:
14+
- name: "colors"
15+
description: "Everything about your colors"
16+
externalDocs:
17+
description: "Find out more"
18+
url: "http://swagger.io"
19+
- name: "store"
20+
description: "Example endpoint list of colors"
21+
- name: "user"
22+
description: "Operations about user"
23+
externalDocs:
24+
description: "Find out more about our store"
25+
url: "http://swagger.io"
26+
schemes:
27+
- "http"
28+
paths:
29+
/:
30+
get:
31+
tags:
32+
- "test"
33+
summary: "Example endpoint"
34+
description: ""
35+
operationId: "examples.microservice_configuration.views.example"
36+
consumes:
37+
- "application/json"
38+
produces:
39+
- "application/json"
40+
responses:
41+
200:
42+
description: "A list of colors (may be filtered by palette)"
43+
schema:
44+
$ref: '#/definitions/Example'
45+
405:
46+
description: "Invalid input"
47+
definitions:
48+
Example:
49+
type: "object"
50+
properties:
51+
main:
52+
type: "string"
53+
externalDocs:
54+
description: "Find out more about Swagger"
55+
url: "http://swagger.io"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from pyms.flask.app import config
2+
3+
GLOBAL_VARIABLE = config().request_variable_test
4+
GLOBAL_VARIABLE2 = config().MyVar
5+
6+
7+
def example():
8+
return {
9+
"GLOBAL_VARIABLE": GLOBAL_VARIABLE,
10+
"GLOBAL_VARIABLE2": GLOBAL_VARIABLE2,
11+
"test1": config().test1,
12+
"test2": config().test2
13+
}

examples/microservice_requests/views.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
from examples.microservice_requests import ms
21
from flask import current_app
32

3+
from examples.microservice_requests import ms
4+
5+
46
def example():
57
current_app.logger.info("start request")
68
result = ms.requests.get_for_object("https://ghibliapi.herokuapp.com/films/2baf70d1-42bb-4437-b551-e5fed5a87abe")

pylintrc

+1-73
Original file line numberDiff line numberDiff line change
@@ -54,79 +54,7 @@ confidence=
5454
# --enable=similarities". If you want to run only the classes checker, but have
5555
# no Warning level messages displayed, use"--disable=all --enable=classes
5656
# --disable=W"
57-
disable=print-statement,
58-
parameter-unpacking,
59-
unpacking-in-except,
60-
old-raise-syntax,
61-
backtick,
62-
long-suffix,
63-
old-ne-operator,
64-
old-octal-literal,
65-
import-star-module-level,
66-
non-ascii-bytes-literal,
67-
raw-checker-failed,
68-
bad-inline-option,
69-
locally-disabled,
70-
locally-enabled,
71-
file-ignored,
72-
suppressed-message,
73-
useless-suppression,
74-
deprecated-pragma,
75-
apply-builtin,
76-
basestring-builtin,
77-
buffer-builtin,
78-
cmp-builtin,
79-
coerce-builtin,
80-
execfile-builtin,
81-
file-builtin,
82-
long-builtin,
83-
raw_input-builtin,
84-
reduce-builtin,
85-
standarderror-builtin,
86-
unicode-builtin,
87-
xrange-builtin,
88-
coerce-method,
89-
delslice-method,
90-
getslice-method,
91-
setslice-method,
92-
no-absolute-import,
93-
old-division,
94-
dict-iter-method,
95-
dict-view-method,
96-
next-method-called,
97-
metaclass-assignment,
98-
indexing-exception,
99-
raising-string,
100-
reload-builtin,
101-
oct-method,
102-
hex-method,
103-
nonzero-method,
104-
cmp-method,
105-
input-builtin,
106-
round-builtin,
107-
intern-builtin,
108-
unichr-builtin,
109-
map-builtin-not-iterating,
110-
zip-builtin-not-iterating,
111-
range-builtin-not-iterating,
112-
filter-builtin-not-iterating,
113-
using-cmp-argument,
114-
eq-without-hash,
115-
div-method,
116-
idiv-method,
117-
rdiv-method,
118-
exception-message-attribute,
119-
invalid-str-codec,
120-
sys-max-int,
121-
bad-python3-import,
122-
deprecated-string-function,
123-
deprecated-str-translate-call,
124-
deprecated-itertools-function,
125-
deprecated-types-field,
126-
next-method-defined,
127-
dict-items-not-iterating,
128-
dict-keys-not-iterating,
129-
dict-values-not-iterating
57+
disable=C0301
13058

13159
# Enable the message, report, category or checker with the given id(s). You can
13260
# either give multiple identifier separated by comma (,) or put this option

pyms/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
__email__ = "[email protected]"
44

5-
__version__ = "1.0.3"
5+
__version__ = "1.1.0"

pyms/constants.py

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
CONFIGMAP_FILE_ENVIRONMENT = "CONFIGMAP_FILE"
2+
SERVICE_ENVIRONMENT = "CONFIGMAP_SERVICE"
23

34
LOGGER_NAME = "pyms"
45

0 commit comments

Comments
 (0)