Browse Source

Created the pecan project for containers for API

Co-Authored-By: Digambar Patil <digambarpat@gmail.com>
Co-Authored-By: Steven Dake <sdake@redhat.com>

Change-Id: I886a26ded99708f39bba22d0ebd08ce99cd26020
changes/87/133787/3
digambar 4 years ago
parent
commit
3d15bd1ba8

+ 1
- 0
containers/MANIFEST.in View File

@@ -0,0 +1 @@
1
+recursive-include public *

+ 0
- 0
containers/api/__init__.py View File


+ 14
- 0
containers/api/app.py View File

@@ -0,0 +1,14 @@
1
+from pecan import make_app
2
+from api import model
3
+
4
+
5
+def setup_app(config):
6
+
7
+    model.init_model()
8
+    app_conf = dict(config.app)
9
+
10
+    return make_app(
11
+        app_conf.pop('root'),
12
+        logging=getattr(config, 'logging', {}),
13
+        **app_conf
14
+    )

+ 0
- 0
containers/api/controllers/__init__.py View File


+ 22
- 0
containers/api/controllers/root.py View File

@@ -0,0 +1,22 @@
1
+from pecan import expose, redirect
2
+from webob.exc import status_map
3
+
4
+
5
+class RootController(object):
6
+
7
+    @expose(generic=True, template='index.html')
8
+    def index(self):
9
+        return dict()
10
+
11
+    @index.when(method='POST')
12
+    def index_post(self, q):
13
+        redirect('http://pecan.readthedocs.org/en/latest/search.html?q=%s' % q)
14
+
15
+    @expose('error.html')
16
+    def error(self, status):
17
+        try:
18
+            status = int(status)
19
+        except ValueError:  # pragma: no cover
20
+            status = 500
21
+        message = getattr(status_map.get(status), 'explanation', '')
22
+        return dict(status=status, message=message)

+ 15
- 0
containers/api/model/__init__.py View File

@@ -0,0 +1,15 @@
1
+from pecan import conf  # noqa
2
+
3
+
4
+def init_model():
5
+    """
6
+    This is a stub method which is called at application startup time.
7
+
8
+    If you need to bind to a parsed database configuration, set up tables or
9
+    ORM classes, or perform any database initialization, this is the
10
+    recommended place to do it.
11
+
12
+    For more information working with databases, and some common recipes,
13
+    see http://pecan.readthedocs.org/en/latest/databases.html
14
+    """
15
+    pass

+ 12
- 0
containers/api/templates/error.html View File

@@ -0,0 +1,12 @@
1
+<%inherit file="layout.html" />
2
+
3
+## provide definitions for blocks we want to redefine
4
+<%def name="title()">
5
+    Server Error ${status}
6
+</%def>
7
+
8
+## now define the body of the template
9
+    <header>
10
+        <h1>Server Error ${status}</h1>
11
+    </header>
12
+    <p>${message}</p>

+ 34
- 0
containers/api/templates/index.html View File

@@ -0,0 +1,34 @@
1
+<%inherit file="layout.html" />
2
+
3
+## provide definitions for blocks we want to redefine
4
+<%def name="title()">
5
+    Welcome to Pecan!
6
+</%def>
7
+
8
+## now define the body of the template
9
+    <header>
10
+        <h1><img src="/images/logo.png" /></h1>
11
+    </header>
12
+
13
+    <div id="content">
14
+
15
+        <p>This is a sample Pecan project.</p>
16
+
17
+        <p>
18
+            Instructions for getting started can be found online at <a
19
+            href="http://pecanpy.org" target="window">pecanpy.org</a>
20
+        </p>
21
+
22
+        <p>
23
+            ...or you can search the documentation here:
24
+        </p>
25
+
26
+        <form method="POST" action="/">
27
+            <fieldset>
28
+                <input name="q" />
29
+                <input type="submit" value="Search" />
30
+            </fieldset>
31
+            <small>Enter search terms or a module, class or function name.</small>
32
+        </form>
33
+
34
+    </div>

+ 22
- 0
containers/api/templates/layout.html View File

@@ -0,0 +1,22 @@
1
+<html>
2
+    <head>
3
+        <title>${self.title()}</title>
4
+        ${self.style()}
5
+        ${self.javascript()}
6
+    </head>
7
+    <body>
8
+        ${self.body()}
9
+    </body>
10
+</html>
11
+
12
+<%def name="title()">
13
+    Default Title
14
+</%def>
15
+
16
+<%def name="style()">
17
+    <link rel="stylesheet" type="text/css" media="screen" href="/css/style.css" />
18
+</%def>
19
+
20
+<%def name="javascript()">
21
+    <script language="text/javascript" src="/javascript/shared.js"></script>
22
+</%def>

+ 22
- 0
containers/api/tests/__init__.py View File

@@ -0,0 +1,22 @@
1
+import os
2
+from unittest import TestCase
3
+from pecan import set_config
4
+from pecan.testing import load_test_app
5
+
6
+__all__ = ['FunctionalTest']
7
+
8
+
9
+class FunctionalTest(TestCase):
10
+    """
11
+    Used for functional tests where you need to test your
12
+    literal application and its integration with the framework.
13
+    """
14
+
15
+    def setUp(self):
16
+        self.app = load_test_app(os.path.join(
17
+            os.path.dirname(__file__),
18
+            'config.py'
19
+        ))
20
+
21
+    def tearDown(self):
22
+        set_config({}, overwrite=True)

+ 25
- 0
containers/api/tests/config.py View File

@@ -0,0 +1,25 @@
1
+# Server Specific Configurations
2
+server = {
3
+    'port': '8080',
4
+    'host': '0.0.0.0'
5
+}
6
+
7
+# Pecan Application Configurations
8
+app = {
9
+    'root': 'api.controllers.root.RootController',
10
+    'modules': ['api'],
11
+    'static_root': '%(confdir)s/../../public',
12
+    'template_path': '%(confdir)s/../templates',
13
+    'debug': True,
14
+    'errors': {
15
+        '404': '/error/404',
16
+        '__force_dict__': True
17
+    }
18
+}
19
+
20
+# Custom Configurations must be in Python dictionary format::
21
+#
22
+# foo = {'bar':'baz'}
23
+#
24
+# All configurations are accessible at::
25
+# pecan.conf

+ 22
- 0
containers/api/tests/test_functional.py View File

@@ -0,0 +1,22 @@
1
+from unittest import TestCase
2
+from webtest import TestApp
3
+from api.tests import FunctionalTest
4
+
5
+
6
+class TestRootController(FunctionalTest):
7
+
8
+    def test_get(self):
9
+        response = self.app.get('/')
10
+        assert response.status_int == 200
11
+
12
+    def test_search(self):
13
+        response = self.app.post('/', params={'q': 'RestController'})
14
+        assert response.status_int == 302
15
+        assert response.headers['Location'] == (
16
+            'http://pecan.readthedocs.org/en/latest/search.html'
17
+            '?q=RestController'
18
+        )
19
+
20
+    def test_get_not_found(self):
21
+        response = self.app.get('/a/bogus/url', expect_errors=True)
22
+        assert response.status_int == 404

+ 7
- 0
containers/api/tests/test_units.py View File

@@ -0,0 +1,7 @@
1
+from unittest import TestCase
2
+
3
+
4
+class TestUnits(TestCase):
5
+
6
+    def test_units(self):
7
+        assert 5 * 5 == 25

+ 54
- 0
containers/config.py View File

@@ -0,0 +1,54 @@
1
+# Server Specific Configurations
2
+server = {
3
+    'port': '8080',
4
+    'host': '0.0.0.0'
5
+}
6
+
7
+# Pecan Application Configurations
8
+app = {
9
+    'root': 'api.controllers.root.RootController',
10
+    'modules': ['api'],
11
+    'static_root': '%(confdir)s/public',
12
+    'template_path': '%(confdir)s/api/templates',
13
+    'debug': True,
14
+    'errors': {
15
+        404: '/error/404',
16
+        '__force_dict__': True
17
+    }
18
+}
19
+
20
+logging = {
21
+    'root': {'level': 'INFO', 'handlers': ['console']},
22
+    'loggers': {
23
+        'api': {'level': 'DEBUG', 'handlers': ['console']},
24
+        'pecan.commands.serve': {'level': 'DEBUG', 'handlers': ['console']},
25
+        'py.warnings': {'handlers': ['console']},
26
+        '__force_dict__': True
27
+    },
28
+    'handlers': {
29
+        'console': {
30
+            'level': 'DEBUG',
31
+            'class': 'logging.StreamHandler',
32
+            'formatter': 'color'
33
+        }
34
+    },
35
+    'formatters': {
36
+        'simple': {
37
+            'format': ('%(asctime)s %(levelname)-5.5s [%(name)s]'
38
+                       '[%(threadName)s] %(message)s')
39
+        },
40
+        'color': {
41
+            '()': 'pecan.log.ColorFormatter',
42
+            'format': ('%(asctime)s [%(padded_color_levelname)s] [%(name)s]'
43
+                       '[%(threadName)s] %(message)s'),
44
+        '__force_dict__': True
45
+        }
46
+    }
47
+}
48
+
49
+# Custom Configurations must be in Python dictionary format::
50
+#
51
+# foo = {'bar':'baz'}
52
+#
53
+# All configurations are accessible at::
54
+# pecan.conf

+ 43
- 0
containers/public/css/style.css View File

@@ -0,0 +1,43 @@
1
+body {
2
+  background: #311F00;
3
+  color: white;
4
+  font-family: 'Helvetica Neue', 'Helvetica', 'Verdana', sans-serif;
5
+  padding: 1em 2em;
6
+}
7
+
8
+a {
9
+  color: #FAFF78;
10
+  text-decoration: none;
11
+}
12
+
13
+a:hover {
14
+  text-decoration: underline;
15
+}
16
+
17
+div#content  {
18
+  width: 800px;
19
+  margin: 0 auto;
20
+}
21
+
22
+form {
23
+  margin: 0;
24
+  padding: 0;
25
+  border: 0;
26
+}
27
+
28
+fieldset {
29
+  border: 0;
30
+}
31
+
32
+input.error {
33
+  background: #FAFF78;
34
+}
35
+
36
+header {
37
+  text-align: center;
38
+}
39
+
40
+h1, h2, h3, h4, h5, h6 {
41
+  font-family: 'Futura-CondensedExtraBold', 'Futura', 'Helvetica', sans-serif;
42
+  text-transform: uppercase;
43
+}

BIN
containers/public/images/logo.png View File


+ 6
- 0
containers/setup.cfg View File

@@ -0,0 +1,6 @@
1
+[nosetests]
2
+match=^test
3
+where=api
4
+nocapture=1
5
+cover-package=api
6
+cover-erase=1

+ 22
- 0
containers/setup.py View File

@@ -0,0 +1,22 @@
1
+# -*- coding: utf-8 -*-
2
+try:
3
+    from setuptools import setup, find_packages
4
+except ImportError:
5
+    from ez_setup import use_setuptools
6
+    use_setuptools()
7
+    from setuptools import setup, find_packages
8
+
9
+setup(
10
+    name='api',
11
+    version='0.1',
12
+    description='',
13
+    author='',
14
+    author_email='',
15
+    install_requires=[
16
+        "pecan",
17
+    ],
18
+    test_suite='api',
19
+    zip_safe=False,
20
+    include_package_data=True,
21
+    packages=find_packages(exclude=['ez_setup'])
22
+)

Loading…
Cancel
Save