Steve Piercy
2016-12-25 c87565c5ff1a3422e651f369fe4b2f848a9010ed
quick_tour - "Logging" updates for cookiecutter
- fix line numbering
- add new src files that were never included
16 files added
1 files modified
508 ■■■■■ changed files
docs/quick_tour.rst 28 ●●●●● patch | view | raw | blame | history
docs/quick_tour/logging/.coveragerc 3 ●●●●● patch | view | raw | blame | history
docs/quick_tour/logging/CHANGES.txt 4 ●●●● patch | view | raw | blame | history
docs/quick_tour/logging/MANIFEST.in 2 ●●●●● patch | view | raw | blame | history
docs/quick_tour/logging/README.txt 29 ●●●●● patch | view | raw | blame | history
docs/quick_tour/logging/development.ini 59 ●●●●● patch | view | raw | blame | history
docs/quick_tour/logging/hello_world/__init__.py 12 ●●●●● patch | view | raw | blame | history
docs/quick_tour/logging/hello_world/static/pyramid-16x16.png patch | view | raw | blame | history
docs/quick_tour/logging/hello_world/static/pyramid.png patch | view | raw | blame | history
docs/quick_tour/logging/hello_world/static/theme.css 154 ●●●●● patch | view | raw | blame | history
docs/quick_tour/logging/hello_world/templates/layout.jinja2 64 ●●●●● patch | view | raw | blame | history
docs/quick_tour/logging/hello_world/templates/mytemplate.jinja2 8 ●●●●● patch | view | raw | blame | history
docs/quick_tour/logging/hello_world/tests.py 29 ●●●●● patch | view | raw | blame | history
docs/quick_tour/logging/hello_world/views.py 9 ●●●●● patch | view | raw | blame | history
docs/quick_tour/logging/production.ini 53 ●●●●● patch | view | raw | blame | history
docs/quick_tour/logging/pytest.ini 3 ●●●●● patch | view | raw | blame | history
docs/quick_tour/logging/setup.py 51 ●●●●● patch | view | raw | blame | history
docs/quick_tour.rst
@@ -749,38 +749,34 @@
development we might need to collect some output. In production we might need
to detect situations when other people use the site. We need *logging*.
Fortunately Pyramid uses the normal Python approach to logging. The scaffold
generated in your ``development.ini`` has a number of lines that configure the
Fortunately Pyramid uses the normal Python approach to logging. The ``development.ini`` file for your project has a number of lines that configure the
logging for you to some reasonable defaults. You then see messages sent by
Pyramid (for example, when a new request comes in).
Maybe you would like to log messages in your code? In your Python module,
import and set up the logging:
import and set up the logging in your ``views.py``:
.. literalinclude:: quick_tour/package/hello_world/views.py
.. literalinclude:: quick_tour/logging/hello_world/views.py
    :language: python
    :linenos:
    :lineno-start: 3
    :lineno-match:
    :lines: 3-4
You can now, in your code, log messages:
.. literalinclude:: quick_tour/package/hello_world/views.py
.. literalinclude:: quick_tour/logging/hello_world/views.py
    :language: python
    :linenos:
    :lineno-start: 9
    :lines: 9-10
    :lineno-match:
    :lines: 7-8
    :emphasize-lines: 2
This will log ``Some Message`` at a ``debug`` log level to the
This will log ``Some Message`` at a ``DEBUG`` log level to the
application-configured logger in your ``development.ini``. What controls that?
These emphasized sections in the configuration file:
.. literalinclude:: quick_tour/package/development.ini
.. literalinclude:: quick_tour/logging/development.ini
    :language: ini
    :linenos:
    :lineno-start: 36
    :lines: 36-52
    :lineno-match:
    :lines: 34-50
    :emphasize-lines: 1-2,14-17
Our application, a package named ``hello_world``, is set up as a logger and
@@ -789,7 +785,7 @@
.. code-block:: text
    2016-01-18 13:55:55,040 DEBUG [hello_world.views:10][waitress] Some Message
    2016-12-25 03:03:57,059 DEBUG [hello_world.views:8][waitress] Some Message
.. seealso:: See also:
    :ref:`Quick Tutorial Logging <qtut_logging>` and :ref:`logging_chapter`.
docs/quick_tour/logging/.coveragerc
New file
@@ -0,0 +1,3 @@
[run]
source = hello_world
omit = hello_world/test*
docs/quick_tour/logging/CHANGES.txt
New file
@@ -0,0 +1,4 @@
0.0
---
- Initial version.
docs/quick_tour/logging/MANIFEST.in
New file
@@ -0,0 +1,2 @@
include *.txt *.ini *.cfg *.rst
recursive-include hello_world *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml *.jinja2
docs/quick_tour/logging/README.txt
New file
@@ -0,0 +1,29 @@
hello_world
===============================
Getting Started
---------------
- Change directory into your newly created project.
    cd hello_world
- Create a Python virtual environment.
    python3 -m venv env
- Upgrade packaging tools.
    env/bin/pip install --upgrade pip setuptools
- Install the project in editable mode with its testing requirements.
    env/bin/pip install -e ".[testing]"
- Run your project's tests.
    env/bin/pytest
- Run your project.
    env/bin/pserve development.ini
docs/quick_tour/logging/development.ini
New file
@@ -0,0 +1,59 @@
###
# app configuration
# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
use = egg:hello_world
pyramid.reload_templates = true
pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.default_locale_name = en
pyramid.includes =
    pyramid_debugtoolbar
# By default, the toolbar only appears for clients from IP addresses
# '127.0.0.1' and '::1'.
# debugtoolbar.hosts = 127.0.0.1 ::1
###
# wsgi server configuration
###
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
###
# logging configuration
# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
keys = root, hello_world
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = INFO
handlers = console
[logger_hello_world]
level = DEBUG
handlers =
qualname = hello_world
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s
docs/quick_tour/logging/hello_world/__init__.py
New file
@@ -0,0 +1,12 @@
from pyramid.config import Configurator
def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    config = Configurator(settings=settings)
    config.include('pyramid_jinja2')
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.add_route('home', '/')
    config.scan()
    return config.make_wsgi_app()
docs/quick_tour/logging/hello_world/static/pyramid-16x16.png
docs/quick_tour/logging/hello_world/static/pyramid.png
docs/quick_tour/logging/hello_world/static/theme.css
New file
@@ -0,0 +1,154 @@
@import url(//fonts.googleapis.com/css?family=Open+Sans:300,400,600,700);
body {
  font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 300;
  color: #ffffff;
  background: #bc2131;
}
h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 300;
}
p {
  font-weight: 300;
}
.font-normal {
  font-weight: 400;
}
.font-semi-bold {
  font-weight: 600;
}
.font-bold {
  font-weight: 700;
}
.starter-template {
  margin-top: 250px;
}
.starter-template .content {
  margin-left: 10px;
}
.starter-template .content h1 {
  margin-top: 10px;
  font-size: 60px;
}
.starter-template .content h1 .smaller {
  font-size: 40px;
  color: #f2b7bd;
}
.starter-template .content .lead {
  font-size: 25px;
  color: #f2b7bd;
}
.starter-template .content .lead .font-normal {
  color: #ffffff;
}
.starter-template .links {
  float: right;
  right: 0;
  margin-top: 125px;
}
.starter-template .links ul {
  display: block;
  padding: 0;
  margin: 0;
}
.starter-template .links ul li {
  list-style: none;
  display: inline;
  margin: 0 10px;
}
.starter-template .links ul li:first-child {
  margin-left: 0;
}
.starter-template .links ul li:last-child {
  margin-right: 0;
}
.starter-template .links ul li.current-version {
  color: #f2b7bd;
  font-weight: 400;
}
.starter-template .links ul li a, a {
  color: #f2b7bd;
  text-decoration: underline;
}
.starter-template .links ul li a:hover, a:hover {
  color: #ffffff;
  text-decoration: underline;
}
.starter-template .links ul li .icon-muted {
  color: #eb8b95;
  margin-right: 5px;
}
.starter-template .links ul li:hover .icon-muted {
  color: #ffffff;
}
.starter-template .copyright {
  margin-top: 10px;
  font-size: 0.9em;
  color: #f2b7bd;
  text-transform: lowercase;
  float: right;
  right: 0;
}
@media (max-width: 1199px) {
  .starter-template .content h1 {
    font-size: 45px;
  }
  .starter-template .content h1 .smaller {
    font-size: 30px;
  }
  .starter-template .content .lead {
    font-size: 20px;
  }
}
@media (max-width: 991px) {
  .starter-template {
    margin-top: 0;
  }
  .starter-template .logo {
    margin: 40px auto;
  }
  .starter-template .content {
    margin-left: 0;
    text-align: center;
  }
  .starter-template .content h1 {
    margin-bottom: 20px;
  }
  .starter-template .links {
    float: none;
    text-align: center;
    margin-top: 60px;
  }
  .starter-template .copyright {
    float: none;
    text-align: center;
  }
}
@media (max-width: 767px) {
  .starter-template .content h1 .smaller {
    font-size: 25px;
    display: block;
  }
  .starter-template .content .lead {
    font-size: 16px;
  }
  .starter-template .links {
    margin-top: 40px;
  }
  .starter-template .links ul li {
    display: block;
    margin: 0;
  }
  .starter-template .links ul li .icon-muted {
    display: none;
  }
  .starter-template .copyright {
    margin-top: 20px;
  }
}
docs/quick_tour/logging/hello_world/templates/layout.jinja2
New file
@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="{{request.locale_name}}">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="pyramid web application">
    <meta name="author" content="Pylons Project">
    <link rel="shortcut icon" href="{{request.static_url('hello_world:static/pyramid-16x16.png')}}">
    <title>Cookiecutter Starter project for the Pyramid Web Framework</title>
    <!-- Bootstrap core CSS -->
    <link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
    <!-- Custom styles for this scaffold -->
    <link href="{{request.static_url('hello_world:static/theme.css')}}" rel="stylesheet">
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <div class="starter-template">
      <div class="container">
        <div class="row">
          <div class="col-md-2">
            <img class="logo img-responsive" src="{{request.static_url('hello_world:static/pyramid.png') }}" alt="pyramid web framework">
          </div>
          <div class="col-md-10">
            {% block content %}
                <p>No content</p>
            {% endblock content %}
          </div>
        </div>
        <div class="row">
          <div class="links">
            <ul>
              <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
              <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
            </ul>
          </div>
        </div>
        <div class="row">
          <div class="copyright">
            Copyright &copy; Pylons Project
          </div>
        </div>
      </div>
    </div>
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
  </body>
</html>
docs/quick_tour/logging/hello_world/templates/mytemplate.jinja2
New file
@@ -0,0 +1,8 @@
{% extends "layout.jinja2" %}
{% block content %}
<div class="content">
  <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Starter project</span></h1>
  <p class="lead">Welcome to <span class="font-normal">hello_world</span>, a&nbsp;Pyramid application generated&nbsp;by<br><span class="font-normal">Cookiecutter</span>.</p>
</div>
{% endblock content %}
docs/quick_tour/logging/hello_world/tests.py
New file
@@ -0,0 +1,29 @@
import unittest
from pyramid import testing
class ViewTests(unittest.TestCase):
    def setUp(self):
        self.config = testing.setUp()
    def tearDown(self):
        testing.tearDown()
    def test_my_view(self):
        from .views import my_view
        request = testing.DummyRequest()
        info = my_view(request)
        self.assertEqual(info['project'], 'hello_world')
class FunctionalTests(unittest.TestCase):
    def setUp(self):
        from hello_world import main
        app = main({})
        from webtest import TestApp
        self.testapp = TestApp(app)
    def test_root(self):
        res = self.testapp.get('/', status=200)
        self.assertTrue(b'Pyramid' in res.body)
docs/quick_tour/logging/hello_world/views.py
New file
@@ -0,0 +1,9 @@
from pyramid.view import view_config
import logging
log = logging.getLogger(__name__)
@view_config(route_name='home', renderer='templates/mytemplate.jinja2')
def my_view(request):
    log.debug('Some Message')
    return {'project': 'hello_world'}
docs/quick_tour/logging/production.ini
New file
@@ -0,0 +1,53 @@
###
# app configuration
# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
use = egg:hello_world
pyramid.reload_templates = false
pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.default_locale_name = en
###
# wsgi server configuration
###
[server:main]
use = egg:waitress#main
listen = *:6543
###
# logging configuration
# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
keys = root, hello_world
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = WARN
handlers = console
[logger_hello_world]
level = WARN
handlers =
qualname = hello_world
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s
docs/quick_tour/logging/pytest.ini
New file
@@ -0,0 +1,3 @@
[pytest]
testpaths = hello_world
python_files = *.py
docs/quick_tour/logging/setup.py
New file
@@ -0,0 +1,51 @@
import os
from setuptools import setup, find_packages
here = os.path.abspath(os.path.dirname(__file__))
with open(os.path.join(here, 'README.txt')) as f:
    README = f.read()
with open(os.path.join(here, 'CHANGES.txt')) as f:
    CHANGES = f.read()
requires = [
    'pyramid',
    'pyramid_jinja2',
    'pyramid_debugtoolbar',
    'waitress',
]
tests_require = [
    'WebTest >= 1.3.1',  # py3 compat
    'pytest',
    'pytest-cov',
]
setup(
    name='hello_world',
    version='0.0',
    description='hello_world',
    long_description=README + '\n\n' + CHANGES,
    classifiers=[
        'Programming Language :: Python',
        'Framework :: Pyramid',
        'Topic :: Internet :: WWW/HTTP',
        'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
    ],
    author='',
    author_email='',
    url='',
    keywords='web pyramid pylons',
    packages=find_packages(),
    include_package_data=True,
    zip_safe=False,
    extras_require={
        'testing': tests_require,
    },
    install_requires=requires,
    entry_points={
        'paste.app_factory': [
            'main = hello_world:main',
        ],
    },
)