Skip to content

Commit def6155

Browse files
committed
Updated docstrings
1 parent f04c7de commit def6155

File tree

7 files changed

+159
-8
lines changed

7 files changed

+159
-8
lines changed

pyms/config/conf.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,35 @@
66

77

88
def get_conf(*args, **kwargs):
9+
"""
10+
Returns an object with a set of attributes retrieved from the configuration file. Each subblock is a append of the
11+
parent and this name, in example of the next yaml, tracer will be `pyms.tracer`. If we have got his config file:
12+
```
13+
pyms:
14+
metrics: true
15+
requests:
16+
data: data
17+
swagger:
18+
path: ""
19+
file: "swagger.yaml"
20+
tracer:
21+
client: "jaeger"
22+
host: "localhost"
23+
component_name: "Python Microservice"
24+
my-ms:
25+
DEBUG: true
26+
TESTING: true
27+
```
28+
* `pyms` block is the default key to load in the pyms.flask.app.create_app.Microservice class.
29+
* `metrics`: is set as the service `pyms.metrics`
30+
* `swagger`: is set as the service `pyms.swagger`
31+
* `tracer`: is set as the service `pyms.tracer`
32+
* `my-ms` block is defined by the env var `CONFIGMAP_SERVICE`. By default is `ms`. This block is the default flask
33+
block config
34+
:param args:
35+
:param kwargs:
36+
:return:
37+
"""
938
service = kwargs.pop('service', None)
1039
memoize = kwargs.pop('memoize', True)
1140
if not service:

pyms/config/confile.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,19 @@
1212

1313

1414
class ConfFile(dict):
15+
"""Recursive get configuration from dictionary, a config file in JSON or YAML format from a path or
16+
`CONFIGMAP_FILE` environment variable.
17+
**Atributes:**
18+
* empty_init: Allow blank variables
19+
* default_file: search for config.yml file
20+
"""
1521
empty_init = False
1622
default_file = "config.yml"
1723

1824
def __init__(self, *args, **kwargs):
1925
"""
2026
Get configuration from a dictionary(variable `config`), from path (variable `path`) or from
21-
environment with the constant `CONFIGMAP_FILE_ENVIRONMENT`
27+
environment with the constant `CONFIGMAP_FILE`
2228
"""
2329
self.empty_init = kwargs.get("empty_init", False)
2430
config = kwargs.get("config")

pyms/flask/app/create_app.py

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,60 @@ def __call__(cls, *args, **kwargs):
3434

3535

3636
class Microservice(metaclass=SingletonMeta):
37+
"""The class Microservice is the core of all microservices built with PyMS.
38+
You can create a simple microservice such as:
39+
```python
40+
from flask import jsonify
41+
42+
from pyms.flask.app import Microservice
43+
44+
ms = Microservice(service="my-minimal-microservice", path=__file__)
45+
app = ms.create_app()
46+
47+
48+
@app.route("/")
49+
def example():
50+
return jsonify({"main": "hello world"})
51+
52+
53+
if __name__ == '__main__':
54+
app.run()
55+
```
56+
Environments variables of PyMS:
57+
**CONFIGMAP_FILE**: The path to the configuration file. By default, PyMS search the configuration file in your
58+
actual folder with the name "config.yml"
59+
**CONFIGMAP_SERVICE**: the name of the keyword that define the block of key-value of [Flask Configuration Handling](http://flask.pocoo.org/docs/1.0/config/)
60+
and your own configuration (see the next section to more info)
61+
62+
## Create configuration
63+
Each microservice needs a config file in yaml or json format to work with it. This configuration contains
64+
the Flask settings of your project and the [Services](services.md). With this way to create configuration files, we
65+
solve two problems of the [12 Factor apps](https://12factor.net/):
66+
- Store config out of the code
67+
- Dev/prod parity: the configuration could be injected and not depends of our code, for example, Kubernetes config maps
68+
69+
a simple configuration file could be a config.yaml:
70+
71+
```yaml
72+
pyms:
73+
requests: true
74+
swagger:
75+
path: ""
76+
file: "swagger.yaml"
77+
my-ms:
78+
DEBUG: true
79+
TESTING: false
80+
APP_NAME: "Python Microservice"
81+
APPLICATION_ROOT: ""
82+
```
83+
84+
Services are libraries, resources and extensions added to the Microservice in the configuration file.
85+
This services are created as an attribute of the [Microservice class](ms_class.md) to use in the code.
86+
87+
To add a service check the [configuration section](configuration.md).
88+
89+
Current services are swagger, request, tracer, metrics
90+
"""
3791
service = None
3892
application = None
3993
swagger = False
@@ -47,20 +101,35 @@ def __init__(self, *args, **kwargs):
47101
self.config = get_conf(service=self.service, memoize=self._singleton)
48102
self.init_services()
49103

50-
def init_services(self):
104+
def init_services(self) -> None:
105+
"""
106+
Set the Attributes of all service defined in config.yml and exists in `pyms.flask.service`
107+
:return: None
108+
"""
51109
service_manager = ServicesManager()
52110
for service_name, service in service_manager.get_services(memoize=self._singleton):
53111
setattr(self, service_name, service)
54112

55-
def init_libs(self):
113+
def init_libs(self) -> Flask:
114+
"""This function exists to override if you need to set more libs such as SQLAlchemy, CORs, and any else
115+
library needs to be init over flask, like the usual pattern [MYLIB].init_app(app)
116+
:return:
117+
"""
56118
return self.application
57119

58-
def init_tracer(self):
120+
def init_tracer(self) -> None:
121+
"""Set attribute in flask `tracer`. See in `pyms.flask.services.tracer` how it works
122+
:return: None
123+
"""
59124
if self._exists_service("tracer"):
60125
client = self.tracer.get_client()
61126
self.application.tracer = FlaskTracing(client, True, self.application)
62127

63-
def init_logger(self):
128+
def init_logger(self) -> None:
129+
"""
130+
Set a logger and return in JSON format.
131+
:return:
132+
"""
64133
self.application.logger = logger
65134
os.environ['WERKZEUG_RUN_MAIN'] = "true"
66135

@@ -79,6 +148,10 @@ def init_logger(self):
79148
self.application.logger.setLevel(logging.INFO)
80149

81150
def init_app(self) -> Flask:
151+
"""Set attribute in flask `swagger`. See in `pyms.flask.services.swagger` how it works. If not set,
152+
run a "normal" Flask app.
153+
:return: None
154+
"""
82155
if self._exists_service("swagger"):
83156
application = self.swagger.init_app(config=self.config, path=self.path)
84157
else:
@@ -91,6 +164,9 @@ def init_app(self) -> Flask:
91164
return application
92165

93166
def init_metrics(self):
167+
"""Set attribute in flask `metrics`. See in `pyms.flask.services.metrics` how it works
168+
:return: None
169+
"""
94170
if getattr(self, "metrics", False) and self.metrics:
95171
self.application.register_blueprint(self.metrics.metrics_blueprint)
96172
self.metrics.add_logger_handler(
@@ -126,6 +202,10 @@ def create_app(self):
126202
return self.application
127203

128204
def _exists_service(self, service_name: Text) -> bool:
205+
"""Check if service exists in the config.yml file
206+
:param service_name:
207+
:return: bool
208+
"""
129209
service = getattr(self, service_name, False)
130210
return service and service is not None
131211

pyms/flask/app/create_config.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,11 @@
22

33

44
def config():
5+
"""The behavior of this function is to access to the configuration outer the scope of flask context, to prevent to
6+
raise a `'working outside of application context`
7+
**IMPORTANT:** If you use this method to get configuration out of context, you must set the `CONFIGMAP_SERVICE` or
8+
set the default key `ms` for your configuration block in your config.yml
9+
:return:
10+
"""
511
ms = Microservice()
612
return ms.config

pyms/flask/healthcheck/healthcheck.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,7 @@
77

88
@healthcheck_blueprint.route('/healthcheck', methods=['GET'])
99
def healthcheck():
10+
"""Set a healtcheck to help other service to discover this microservice, like Kubernetes, AWS ELB, etc.
11+
:return:
12+
"""
1013
return "OK"

pyms/flask/services/driver.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,28 @@
88

99

1010
class DriverService:
11+
"""All services must inherit from this class. This set the configuration. If we have got his config file:
12+
```
13+
pyms:
14+
metrics: true
15+
requests:
16+
data: data
17+
swagger:
18+
path: ""
19+
file: "swagger.yaml"
20+
tracer:
21+
client: "jaeger"
22+
host: "localhost"
23+
component_name: "Python Microservice"
24+
my-ms:
25+
DEBUG: true
26+
TESTING: true
27+
```
28+
* `pyms` block is the default key to load in the pyms.flask.app.create_app.Microservice class.
29+
* `metrics`: is set as the service `pyms.metrics`
30+
* `swagger`: is set as the service `pyms.swagger`
31+
* `tracer`: is set as the service `pyms.tracer`
32+
"""
1133
service = ""
1234
config = None
1335

@@ -25,6 +47,9 @@ def exists_config(self):
2547

2648

2749
class ServicesManager:
50+
"""This class works between `pyms.flask.create_app.Microservice` and `pyms.flask.services.[THESERVICE]`. Search
51+
for a file with the name you want to load, set the configuration and return a instance of the class you want
52+
"""
2853
service = SERVICE_BASE
2954

3055
def __init__(self, service=None):

pyms/utils/utils.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
import importlib
22
import importlib.util
3+
from typing import Union, Text
34

45
from pyms.exceptions import PackageNotExists
56

67

7-
def import_from(module, name):
8+
def import_from(module: Text, name: Text):
9+
810
module = __import__(module, fromlist=[name])
911
return getattr(module, name)
1012

1113

12-
def import_package(package):
14+
def import_package(package: Text):
1315
return importlib.import_module(package)
1416

1517

16-
def check_package_exists(package_name):
18+
def check_package_exists(package_name: Text) -> Union[Exception, bool]:
1719
spec = importlib.util.find_spec(package_name)
1820
if spec is None:
1921
raise PackageNotExists("{package} is not installed. try with pip install -U {package}".format(package=package_name))

0 commit comments

Comments
 (0)