encadre 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
encadre-0.1.1/PKG-INFO ADDED
@@ -0,0 +1,19 @@
1
+ Metadata-Version: 2.2
2
+ Name: encadre
3
+ Version: 0.1.1
4
+ Summary: Encadre framework
5
+ Author: Jean Schurger
6
+ Author-email: jean@schurger.org
7
+ License: GPLv3
8
+ Requires-Dist: Flask
9
+ Requires-Dist: fastjsonschema
10
+ Requires-Dist: flask-cors
11
+ Requires-Dist: decorator
12
+ Requires-Dist: nose
13
+ Requires-Dist: coverage
14
+ Requires-Dist: flask_jwt_extended
15
+ Dynamic: author
16
+ Dynamic: author-email
17
+ Dynamic: license
18
+ Dynamic: requires-dist
19
+ Dynamic: summary
@@ -0,0 +1,80 @@
1
+ import sys
2
+ import configparser
3
+ import traceback
4
+ import logging
5
+ import logging.config
6
+ from encadre.controllers import Controller, load_controllers
7
+ from encadre.framework import Framework, DumpRoutes
8
+ from encadre.framework import framework_from_config, validate
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class NotReady:
14
+ def __init__(self, diagnostic):
15
+ self.diagnostic = diagnostic
16
+
17
+ def __getattr__(self, attribute):
18
+ raise AttributeError("Cannot access %r: %s" %
19
+ (attribute, self.diagnostic))
20
+
21
+ def __getitem__(self, item):
22
+ raise AttributeError("Cannot find %r: %s" % (item, self.diagnostic))
23
+
24
+ def __bool__(self):
25
+ return False
26
+
27
+
28
+ request = cookies = NotReady("Encadre is not setup yet.")
29
+
30
+
31
+ class Encadre():
32
+
33
+ config = {}
34
+
35
+ def __init__(self, config_filename):
36
+ self.application = getattr(self, 'application',
37
+ self.__class__.__name__.lower())
38
+ logger.debug("Starting encadre application '%s'." % self.application)
39
+ self.config_filename = config_filename
40
+ if self.config_filename:
41
+ self.config.update(self.read_config(self.config_filename))
42
+ try:
43
+ logging.config.fileConfig(self.config_filename)
44
+ except Exception:
45
+ print("You'd better configure logging in '%s':\n%s" %
46
+ (self.config_filename, traceback.format_exc()))
47
+ setattr(sys.modules['encadre'], 'config', self.config)
48
+
49
+ def read_config(self, filename):
50
+ config = {self.__class__.__name__.lower(): {}}
51
+ p = configparser.ConfigParser()
52
+ p.read(filename)
53
+ for n, s in p.items():
54
+ if s:
55
+ config[n] = dict(s)
56
+ return config
57
+
58
+ def serve(self):
59
+ assert self.config, "Missing config."
60
+ f = framework_from_config(self.__class__.__name__.lower(), self.config)
61
+ f.setup_application(self)
62
+ load_controllers(f, self.application)
63
+ f.serve()
64
+
65
+ def dump_routes(self):
66
+ assert self.config, "Missing config."
67
+ f = DumpRoutes(self.__class__.__name__.lower(), self.config)
68
+ load_controllers(f, self.application)
69
+ print(f)
70
+
71
+ def get_wsgi_app(self):
72
+ config = self.read_config(self.config_filename)
73
+ assert config, "Missing config."
74
+ f = framework_from_config(self.__class__.__name__.lower(), config)
75
+ f.setup_application(self)
76
+ load_controllers(f, self.application)
77
+ return f.get_wsgi_app()
78
+
79
+
80
+ __all__ = ['Encadre', 'Framework', 'Controller', 'validate']
@@ -0,0 +1,135 @@
1
+ import traceback
2
+ import types
3
+ import logging
4
+ import unittest
5
+ import pkg_resources
6
+ from encadre.framework import Framework
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ class Controller():
12
+
13
+ version = 0
14
+
15
+ @classmethod
16
+ def setup(cls, framework, root):
17
+ methods = []
18
+ cls.framework = framework
19
+ ctrl_name = cls.__name__.lower()
20
+ version = ctrl_name.split('_')[-1]
21
+ if version.isdigit():
22
+ ctrl_name = ctrl_name[:-(len(version) + 1)]
23
+ version = int(version)
24
+ else:
25
+ version = framework.first_version
26
+
27
+ for name in [a for a in dir(cls) if a[0] != '_']:
28
+ attr = getattr(cls, name)
29
+ if isinstance(attr, types.FunctionType) and \
30
+ not name.startswith('test_'):
31
+ verbs = ''.join([c for c in name if c.isupper() or c == '_'
32
+ ]).lstrip('_').split('_')
33
+ if verbs != ['']:
34
+ name = name[:name.find("_%s" % verbs[0])]
35
+ if name == 'index__':
36
+ if root:
37
+ if name == 'index__':
38
+ framework.root_id = id(attr)
39
+ else:
40
+ root_id = getattr(framework, 'root_id', None)
41
+ # Prevent inheritance of index__
42
+ if root_id == id(attr):
43
+ continue
44
+ methods.append(
45
+ (name, attr,
46
+ attr.__code__.co_varnames[1:attr.__code__.co_argcount],
47
+ verbs if verbs != [''] else ['GET']))
48
+ framework.add_controller((cls, '__root__' if root else ctrl_name,
49
+ version), methods)
50
+
51
+
52
+ def setup_controllers(cls, f, level=0):
53
+ if cls.__name__ != 'Controller': # exclude abstract
54
+ cls.setup(f, root=level < 2)
55
+ for sub in cls.__subclasses__():
56
+ setup_controllers(sub, f, level + 1)
57
+
58
+
59
+ def load_controllers(f, application):
60
+ for ep in pkg_resources.iter_entry_points('%s.controllers' % application):
61
+ try:
62
+ ep.load()
63
+ except ModuleNotFoundError:
64
+ logger.error("Error importing '%s': %s" % (
65
+ ep, traceback.format_exc()))
66
+ for ep in pkg_resources.iter_entry_points('encadre.controllers'):
67
+ try:
68
+ ep.load()
69
+ except ModuleNotFoundError:
70
+ logger.error("Error importing '%s': %s" % (
71
+ ep, traceback.format_exc()))
72
+ setup_controllers(Controller, f)
73
+
74
+
75
+ class EncadreTestCase(unittest.TestCase):
76
+ def setUp(self):
77
+ self.framework._json = {}
78
+ self.framework._environ = {}
79
+ self.framework._headers = {}
80
+ self.framework._args = {}
81
+ self.framework._cookies = {}
82
+
83
+ def tearDown(self):
84
+ pass
85
+
86
+
87
+ class TestFramework(Framework):
88
+ def request_json(self):
89
+ return self._json
90
+
91
+ def request_environ(self):
92
+
93
+ return self._environ
94
+
95
+ def request_headers(self):
96
+ return self._headers
97
+
98
+ def request_args(self):
99
+ return self._args
100
+
101
+ def get_cookie(self, key):
102
+ return self._cookies.get(key)
103
+
104
+ def set_cookie(self, key, value): # pylint: disable=W0221
105
+ self._cookies[key] = value
106
+
107
+ def send_bytes(self, bytes_like, **kwargs): # pylint: disable=W0613
108
+ return bytes_like.read()
109
+
110
+
111
+ def get_controllers_tsts(app):
112
+ f = TestFramework(app.application, None)
113
+ load_controllers(f, app.application)
114
+
115
+ def missing_test(self):
116
+ raise Exception("Missing test")
117
+
118
+ for c in f.controllers:
119
+ for v in f.controllers[c]:
120
+ cls = f.controllers[c][v]['cls']
121
+ attributes = {}
122
+ for name in [a for a in dir(cls) if a[0] != '_']:
123
+ attr = getattr(cls, name)
124
+ if not name.startswith('test_'):
125
+ attributes[name] = attr
126
+ if isinstance(attr, types.FunctionType) and \
127
+ not name.startswith('test_'):
128
+ test_name = 'test_%s' % name
129
+ test_long_name = 'test_%s_%s' % (cls.__name__, name)
130
+ test_fct = getattr(cls, test_name, missing_test)
131
+ attributes[test_long_name] = test_fct
132
+ test_cls = type("Test%s" % cls.__name__,
133
+ (getattr(cls, 'testcase_cls', EncadreTestCase), ),
134
+ attributes)
135
+ yield (test_cls.__name__, test_cls)
@@ -0,0 +1,186 @@
1
+ import sys
2
+ import logging
3
+ import pkg_resources
4
+ import traceback
5
+ from decorator import decorator
6
+
7
+ logger = logging.getLogger(__name__)
8
+ ENI = Exception("Not implemented.")
9
+
10
+
11
+ class Cookies():
12
+ def __init__(self, framework):
13
+ self.f = framework
14
+
15
+ def get(self, key):
16
+ return self.f.get_cookie(key)
17
+
18
+ def set(self, *args, **kwargs):
19
+ return self.f.set_cookie(*args, **kwargs)
20
+
21
+
22
+ class Request():
23
+ def __init__(self, framework):
24
+ self.f = framework
25
+ self._json = None
26
+ self._environ = None
27
+ self._headers = None
28
+ self._args = None
29
+
30
+ def _get_json(self):
31
+ return self._json or self.f.request_json()
32
+
33
+ # Let unit tests set some json
34
+ def _set_json(self, json):
35
+ self._json = json
36
+
37
+ json = property(_get_json, _set_json)
38
+
39
+ def _get_environ(self):
40
+ return self._environ or self.f.request_environ()
41
+
42
+ # Let unit tests set environ
43
+ def _set_environ(self, environ):
44
+ self._environ = environ
45
+
46
+ environ = property(_get_environ, _set_environ)
47
+
48
+ def _get_headers(self):
49
+ return self._headers or self.f.request_headers()
50
+
51
+ # Let unit tests set environ
52
+ def _set_headers(self, headers):
53
+ self._headers = headers
54
+
55
+ headers = property(_get_headers, _set_headers)
56
+
57
+ def _get_args(self):
58
+ return self._args or self.f.request_args()
59
+
60
+ # Let unit tests set environ
61
+ def _set_args(self, args):
62
+ self._args = args
63
+
64
+ args = property(_get_args, _set_args)
65
+
66
+
67
+ def validate(vargs):
68
+ def helper(func, *args, **kwargs):
69
+ if hasattr(args[0].framework, 'validate_query'):
70
+ args[0].framework.validate_query(vargs)
71
+ return func(*args, **kwargs)
72
+ return decorator(helper)
73
+
74
+
75
+ class Framework():
76
+
77
+ request_class = Request
78
+ cookies_class = Cookies
79
+
80
+ def __init__(self, application, config):
81
+ self.application = application
82
+ self.config = config
83
+ self.first_version = int((self.config or {}).get(application, {}).get(
84
+ 'first_version', '0'))
85
+ if self.first_version:
86
+ logger.debug("Config set 'first_version' to %s." %
87
+ self.first_version)
88
+ self.versioning_use_prefix = (self.config or {}).get(
89
+ application, {}).get('versioning', 'headers').lower() == 'prefix'
90
+ if self.versioning_use_prefix:
91
+ logger.debug("Config set versioning to 'prefix' mode.")
92
+ self.routes = {}
93
+ self.controllers = {}
94
+ self.request = self.request_class(self)
95
+ setattr(sys.modules['encadre'], 'request', self.request)
96
+ self.cookies = self.cookies_class(self)
97
+ setattr(sys.modules['encadre'], 'cookies', self.cookies)
98
+
99
+ def add_controller(self, ctrl, methods):
100
+ ctrl_cls, ctrl_name, ctrl_version = ctrl
101
+ self.controllers.setdefault(ctrl_name, {})
102
+ self.controllers[ctrl_name][ctrl_version] = {
103
+ 'doc': (ctrl_cls.__doc__ or '').strip(),
104
+ 'cls': ctrl_cls,
105
+ 'methods': {}}
106
+ for method_name, method, args, verbs in methods:
107
+ self.controllers[ctrl_name][ctrl_version]['methods'].setdefault(
108
+ method_name, {})
109
+ for verb in verbs:
110
+ self.controllers[ctrl_name][ctrl_version]['methods'][
111
+ method_name][verb] = {
112
+ 'fct': method,
113
+ 'doc': (method.__doc__ or '').strip(),
114
+ 'args': args}
115
+
116
+ def setup_application(self, instance):
117
+ self.instance = instance
118
+ self.before_call_chain = []
119
+ if hasattr(instance, 'before_call'):
120
+ self.before_call_chain.append(self.instance_before_call)
121
+ self.after_call_chain = []
122
+ if hasattr(instance, 'after_call'):
123
+ self.after_call_chain.append(self.instance_after_call)
124
+ if hasattr(instance, 'validate_query'):
125
+ self.validate_query = instance.validate_query
126
+
127
+ def instance_before_call(self):
128
+ getattr(self.instance, 'before_call')()
129
+
130
+ def instance_after_call(self, response):
131
+ getattr(self.instance, 'after_call')()
132
+ return response
133
+
134
+ def not_implemented(self):
135
+ raise ENI
136
+
137
+ request_json = request_environ = request_headers = \
138
+ request_args = get_cookie = set_cookie = send_bytes = not_implemented
139
+
140
+ def format_exception(self, e):
141
+ ret = None
142
+ code = 500
143
+ logger.exception(traceback.format_exc())
144
+ if hasattr(self.instance, "format_exception"):
145
+ ret, code = self.instance.format_exception(e)
146
+ else:
147
+ ha = (self.config or {}).get(self.application, {}).get(
148
+ 'on_exception', '').lower()
149
+ if ha == 'traceback':
150
+ ret = traceback.format_exc()
151
+ if ha == 'str':
152
+ ret = str(e)
153
+ if ret is None:
154
+ raise e
155
+ return ret, code
156
+
157
+
158
+ class DumpRoutes(Framework):
159
+
160
+ def __repr__(self):
161
+ ret = []
162
+ for c in sorted(self.controllers):
163
+ ret.append("* Controller: %s" % (c))
164
+ for v in self.controllers[c]:
165
+ ret.append("** Version: %s: %s" %
166
+ (v, self.controllers[c][v]['doc']))
167
+ for m in self.controllers[c][v]['methods']:
168
+ for _v in self.controllers[c][v]['methods'][m]:
169
+ ret.append(
170
+ "- [%s] %s%s: %s" %
171
+ (_v, m,
172
+ self.controllers[c][v]['methods'][m][_v]['args'],
173
+ self.controllers[c][v]['methods'][m][_v]['doc']))
174
+ return "\n".join(ret)
175
+
176
+
177
+ def framework_from_config(application, config):
178
+ fw_name = (config.get(application) or {}).get('framework')
179
+ assert fw_name, "No framework configured."
180
+ for ep in pkg_resources.iter_entry_points('%s.frameworks' % application):
181
+ if ep.name == fw_name:
182
+ return ep.load()(application, config)
183
+ for ep in pkg_resources.iter_entry_points('encadre.frameworks'):
184
+ if ep.name == fw_name:
185
+ return ep.load()(application, config)
186
+ raise Exception("No framework available")
@@ -0,0 +1,19 @@
1
+ Metadata-Version: 2.2
2
+ Name: encadre
3
+ Version: 0.1.1
4
+ Summary: Encadre framework
5
+ Author: Jean Schurger
6
+ Author-email: jean@schurger.org
7
+ License: GPLv3
8
+ Requires-Dist: Flask
9
+ Requires-Dist: fastjsonschema
10
+ Requires-Dist: flask-cors
11
+ Requires-Dist: decorator
12
+ Requires-Dist: nose
13
+ Requires-Dist: coverage
14
+ Requires-Dist: flask_jwt_extended
15
+ Dynamic: author
16
+ Dynamic: author-email
17
+ Dynamic: license
18
+ Dynamic: requires-dist
19
+ Dynamic: summary
@@ -0,0 +1,13 @@
1
+ setup.cfg
2
+ setup.py
3
+ encadre/__init__.py
4
+ encadre/controllers.py
5
+ encadre/framework.py
6
+ encadre.egg-info/PKG-INFO
7
+ encadre.egg-info/SOURCES.txt
8
+ encadre.egg-info/dependency_links.txt
9
+ encadre.egg-info/entry_points.txt
10
+ encadre.egg-info/requires.txt
11
+ encadre.egg-info/top_level.txt
12
+ encadre_flask/__init__.py
13
+ encadre_flask/test.py
@@ -0,0 +1,9 @@
1
+ [console_scripts]
2
+ encadre-test-app-dump-routes = encadre_test_app:dump_routes
3
+ encadre-test-app-serve = encadre_test_app:serve
4
+
5
+ [encadre.frameworks]
6
+ flask = encadre_flask:FlaskFramework
7
+
8
+ [encadre_test_app.controllers]
9
+ test_controllers = encadre_test_controllers
@@ -0,0 +1,7 @@
1
+ Flask
2
+ fastjsonschema
3
+ flask-cors
4
+ decorator
5
+ nose
6
+ coverage
7
+ flask_jwt_extended
@@ -0,0 +1,2 @@
1
+ encadre
2
+ encadre_flask
@@ -0,0 +1,168 @@
1
+ import sys
2
+ import re
3
+ import logging
4
+ from flask import Flask, request, send_file, abort
5
+ from flask_cors import CORS
6
+ from flask_jwt_extended import JWTManager
7
+ from encadre import Framework
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ class FlaskFramework(Framework):
13
+ def __init__(self, application, config):
14
+ Framework.__init__(self, application, config)
15
+ self.versions = {}
16
+ self._endpoints = set()
17
+ self.application = application
18
+ self.flask_app = Flask(application)
19
+ self.flask_app.url_map.strict_slashes = False
20
+ self.flask_app.register_error_handler(404, self.handle_exception)
21
+ for k, v in (self.config.get('flask') or {}).items():
22
+ _v = v
23
+ if v.lower() == 'false':
24
+ _v = False
25
+ if v.lower() == 'true':
26
+ _v = True
27
+ if v.isdigit():
28
+ _v = int(v)
29
+ self.flask_app.config[k.upper()] = _v
30
+ if not (self.config.get('flask') or {}).get('external_cors'):
31
+ logger.debug("We handle CORS.")
32
+ CORS(self.flask_app)
33
+ else:
34
+ logger.debug("CORS must be handheld upstream.")
35
+ if (self.config.get('flask') or {}).get('JWT_SECRET_KEY'.lower()):
36
+ self.jwt_manager = JWTManager(self.flask_app)
37
+
38
+ def setup_application(self, instance):
39
+ Framework.setup_application(self, instance)
40
+ for fct in self.before_call_chain:
41
+ self.flask_app.before_request(fct)
42
+ for fct in self.after_call_chain:
43
+ self.flask_app.after_request(fct)
44
+ self.flask_app.after_request(self._set_cookies)
45
+
46
+ def _add_method(self, ctrl_name, method_name):
47
+ def accessor(**args):
48
+ import flask
49
+ v = None
50
+ if self.versioning_use_prefix:
51
+ v = flask.request.environ.get('PATH_INFO').lstrip('/').split(
52
+ '/')[0]
53
+ logger.debug("Got version '%s' from URL." % v)
54
+ else:
55
+ # flask handle case and underscores
56
+ h = 'X-%s-Version' % self.application
57
+ v = flask.request.headers.get(h)
58
+ logger.debug("Got version '%s' from header '%s'." % (v, h))
59
+ if v and not v.isdigit():
60
+ flask.abort(405)
61
+ v = int(v) if v else sys.maxsize
62
+ v = v if v in self.controllers[ctrl_name] else max(
63
+ self.controllers[ctrl_name].keys())
64
+ verb = flask.request.environ['REQUEST_METHOD']
65
+ cls = self.controllers[ctrl_name][v]['cls']
66
+ try:
67
+ m = self.controllers[ctrl_name][v]['methods'][method_name][
68
+ verb]['fct'].__name__
69
+ except KeyError:
70
+ logger.error("Cannot found method for: controller: '%s', "
71
+ "method: '%s', version: '%s', verb: '%s'" %
72
+ (ctrl_name, method_name, v, verb))
73
+ flask.abort(405)
74
+ self._cookies = []
75
+ try:
76
+ ret = getattr(cls(), m)(**args)
77
+ except Exception as e:
78
+ ret = self.handle_exception(e)
79
+ return ret
80
+
81
+ setattr(self, '_m_%s_%s' % (ctrl_name, method_name), accessor)
82
+
83
+ def handle_exception(self, e):
84
+ message, code = self.format_exception(e)
85
+ if not message:
86
+ abort(code)
87
+ return message, code
88
+
89
+ def _mk_endpoint(self, ctrl_name, method_name, args, version):
90
+ ep = "/%s/%s%s" % (ctrl_name.lower(),
91
+ method_name if method_name != 'index__' else '',
92
+ ('/' + '/'.join(['<%s>' % a
93
+ for a in args]) if args else ''))
94
+ return '/%s%s' % (version, ep) if version else ep
95
+
96
+ def _setup_routes(self):
97
+ """ Add routes to flask """
98
+ endpoints = {}
99
+ methods = {}
100
+ for c in sorted(self.controllers):
101
+ for v in self.controllers[c]:
102
+ for m in self.controllers[c][v]['methods']:
103
+ for _v in self.controllers[c][v]['methods'][m]:
104
+ fct = self.controllers[c][v]['methods'][m][_v]['fct']
105
+ args = self.controllers[c][v]['methods'][m][_v]['args']
106
+ e = self._mk_endpoint(
107
+ c,
108
+ m,
109
+ args,
110
+ version=v if self.versioning_use_prefix else None)
111
+ endpoints.setdefault(e, set())
112
+ if isinstance(fct.__defaults__, tuple):
113
+ url = re.search(r'^(.*[\\\/])', e).group()
114
+ endpoints.setdefault(url, set())
115
+ endpoints[url].add(_v)
116
+ methods[url] = (c, m)
117
+ endpoints[e].add(_v)
118
+ methods[e] = (c, m)
119
+ for e, verbs in endpoints.items():
120
+ self._add_method(*methods[e])
121
+ logger.debug("Adding endpoint: '%s' allowing with verbs: '%s'." %
122
+ (e, verbs))
123
+ route = e
124
+ if route.startswith('/__root__'):
125
+ route = e.replace('/__root__', '', 1)
126
+ self.flask_app.add_url_rule(route,
127
+ route,
128
+ getattr(self, '_m_%s_%s' % methods[e]),
129
+ methods=verbs)
130
+
131
+ def serve(self):
132
+ self._setup_routes()
133
+ self.flask_app.run(
134
+ host=self.flask_app.config.get('HOST', '0.0.0.0'),
135
+ port=self.flask_app.config.get('PORT', 5001),
136
+ debug=self.flask_app.config.get('DEBUG', True),
137
+ threaded=self.flask_app.config.get('THREADED', False),
138
+ )
139
+
140
+ def get_wsgi_app(self):
141
+ self._setup_routes()
142
+ return self.flask_app
143
+
144
+ def _set_cookies(self, response):
145
+ for args, kwargs in getattr(self, '_cookies', {}):
146
+ response.set_cookie(*args, **kwargs)
147
+ return response
148
+
149
+ def request_json(self):
150
+ return request.json
151
+
152
+ def request_environ(self):
153
+ return request.environ
154
+
155
+ def request_headers(self):
156
+ return request.headers
157
+
158
+ def request_args(self):
159
+ return request.args
160
+
161
+ def get_cookie(self, key):
162
+ return request.cookies.get(key)
163
+
164
+ def set_cookie(self, *args, **kwargs):
165
+ self._cookies.append((args, kwargs))
166
+
167
+ def send_bytes(self, bytes_like, **kwargs):
168
+ return send_file(bytes_like, **kwargs)
@@ -0,0 +1,25 @@
1
+ import unittest
2
+ from encadre import Encadre
3
+ from encadre.framework import framework_from_config
4
+ from encadre.controllers import load_controllers
5
+
6
+
7
+ class EncadreFlask(Encadre):
8
+
9
+ application = 'encadre_test_app'
10
+
11
+ def __init__(self):
12
+ Encadre.__init__(self, None)
13
+ self.framework = framework_from_config(self.application,
14
+ {self.application:
15
+ {'framework': 'flask'}})
16
+ load_controllers(self.framework, self.application)
17
+
18
+
19
+ class TestEncadreFlask(unittest.TestCase):
20
+
21
+ def setUp(self):
22
+ self.encadre = EncadreFlask()
23
+
24
+ def test_setup_routes(self):
25
+ self.encadre.framework._setup_routes()
@@ -0,0 +1,8 @@
1
+ [nosetests]
2
+ verbosity = 3
3
+ with-doctest = 1
4
+
5
+ [egg_info]
6
+ tag_build =
7
+ tag_date = 0
8
+
encadre-0.1.1/setup.py ADDED
@@ -0,0 +1,23 @@
1
+ from setuptools import setup
2
+
3
+ console_scripts = """
4
+ encadre-test-app-serve = encadre_test_app:serve
5
+ encadre-test-app-dump-routes = encadre_test_app:dump_routes
6
+ """
7
+
8
+ setup(name='encadre',
9
+ version='0.1.1',
10
+ description="Encadre framework",
11
+ author="Jean Schurger",
12
+ author_email='jean@schurger.org',
13
+ packages=['encadre', 'encadre_flask'],
14
+ install_requires=['Flask', 'fastjsonschema', 'flask-cors',
15
+ 'decorator', 'nose', 'coverage', 'flask_jwt_extended'],
16
+ entry_points={
17
+ 'console_scripts': console_scripts,
18
+ 'encadre.frameworks':
19
+ ['flask = encadre_flask:FlaskFramework'],
20
+ 'encadre_test_app.controllers':
21
+ ['test_controllers = encadre_test_controllers']
22
+ },
23
+ license='GPLv3')