Michael Merickel
2015-11-12 414b67b45bab156b9738105e180908c4eee8600a
Restore progress after backing changes out of master.

This reverts commit 049e670aef9ea5611561546fd5c0e2dd6152b9b7.
12 files deleted
1 files copied
13 files added
17 files modified
3 files renamed
1257 ■■■■■ changed files
CONTRIBUTORS.txt 2 ●●●●● patch | view | raw | blame | history
docs/quick_tour.rst 4 ●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/development.ini 4 ●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/production.ini 2 ●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/setup.py 11 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo.sqlite patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/__init__.py 11 ●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/models.py 29 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/models/__init__.py 7 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/models/meta.py 46 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/models/mymodel.py 19 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/scripts/initializedb.py 30 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/favicon.ico patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/footerbg.png patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/headerbg.png patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/ie6.css 8 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/middlebg.png patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/pylons.css 372 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/pyramid-16x16.png patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/pyramid-small.png patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/pyramid.png patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/theme.css 154 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/theme.min.css 1 ●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/transparent.gif patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2 19 ●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/templates/mytemplate.jinja2 8 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/templates/mytemplate.pt 76 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/tests.py 70 ●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/views/__init__.py patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/views/default.py 18 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/basiclayout.rst 98 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/basiclayout/development.ini 4 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/basiclayout/production.ini 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py 12 ●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/__init__.py 12 ●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/models.py 27 ●●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/models/__init__.py 7 ●●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/models/meta.py 46 ●●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/models/mymodel.py 17 ●●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/scripts/initializedb.py 21 ●●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/templates/layout.jinja2_tmpl 15 ●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/templates/mytemplate.jinja2_tmpl 8 ●●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/tests.py_tmpl 80 ●●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/views/__init__.py patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/views/default.py_tmpl 15 ●●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/setup.py_tmpl 2 ●●● patch | view | raw | blame | history
CONTRIBUTORS.txt
@@ -247,6 +247,8 @@
- Donald Stufft, 2015/03/15
- Randy Topliffe, 2015/04/14
- Karen Dalton, 2015/06/01
- Igor Stroh, 2015/06/10
docs/quick_tour.rst
@@ -818,14 +818,14 @@
language. SQLAlchemy uses "models" for this mapping. The scaffold
generated a sample model:
.. literalinclude:: quick_tour/sqla_demo/sqla_demo/models.py
.. literalinclude:: quick_tour/sqla_demo/sqla_demo/models/mymodel.py
    :start-after: Start Sphinx Include
    :end-before: End Sphinx Include
View code, which mediates the logic between web requests and the rest
of the system, can then easily get at the data thanks to SQLAlchemy:
.. literalinclude:: quick_tour/sqla_demo/sqla_demo/views.py
.. literalinclude:: quick_tour/sqla_demo/sqla_demo/views/default.py
    :start-after: Start Sphinx Include
    :end-before: End Sphinx Include
docs/quick_tour/sqla_demo/development.ini
@@ -27,7 +27,7 @@
[server:main]
use = egg:waitress#main
host = 0.0.0.0
host = 127.0.0.1
port = 6543
###
@@ -68,4 +68,4 @@
formatter = generic
[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s
docs/quick_tour/sqla_demo/production.ini
@@ -59,4 +59,4 @@
formatter = generic
[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s
docs/quick_tour/sqla_demo/setup.py
@@ -3,15 +3,18 @@
from setuptools import setup, find_packages
here = os.path.abspath(os.path.dirname(__file__))
README = open(os.path.join(here, 'README.txt')).read()
CHANGES = open(os.path.join(here, 'CHANGES.txt')).read()
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',
    'pyramid_tm',
    'SQLAlchemy',
    'transaction',
    'pyramid_tm',
    'pyramid_debugtoolbar',
    'zope.sqlalchemy',
    'waitress',
    ]
docs/quick_tour/sqla_demo/sqla_demo.sqlite
Binary files differ
docs/quick_tour/sqla_demo/sqla_demo/__init__.py
@@ -1,19 +1,12 @@
from pyramid.config import Configurator
from sqlalchemy import engine_from_config
from .models import (
    DBSession,
    Base,
    )
def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine
    config = Configurator(settings=settings)
    config.include('pyramid_jinja2')
    config.include('.models.meta')
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.add_route('home', '/')
    config.scan()
docs/quick_tour/sqla_demo/sqla_demo/models.py
File was deleted
docs/quick_tour/sqla_demo/sqla_demo/models/__init__.py
New file
@@ -0,0 +1,7 @@
from sqlalchemy.orm import configure_mappers
# import all models classes here for sqlalchemy mappers
# to pick up
from .mymodel import MyModel # flake8: noqa
# run configure mappers to ensure we avoid any race conditions
configure_mappers()
docs/quick_tour/sqla_demo/sqla_demo/models/meta.py
New file
@@ -0,0 +1,46 @@
from sqlalchemy import engine_from_config
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy.schema import MetaData
import zope.sqlalchemy
NAMING_CONVENTION = {
    "ix": 'ix_%(column_0_label)s',
    "uq": "uq_%(table_name)s_%(column_0_name)s",
    "ck": "ck_%(table_name)s_%(constraint_name)s",
    "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
    "pk": "pk_%(table_name)s"
}
metadata = MetaData(naming_convention=NAMING_CONVENTION)
Base = declarative_base(metadata=metadata)
def includeme(config):
    settings = config.get_settings()
    dbmaker = get_dbmaker(get_engine(settings))
    config.add_request_method(
        lambda r: get_session(r.tm, dbmaker),
        'dbsession',
        reify=True
    )
    config.include('pyramid_tm')
def get_session(transaction_manager, dbmaker):
    dbsession = dbmaker()
    zope.sqlalchemy.register(dbsession,
                             transaction_manager=transaction_manager)
    return dbsession
def get_engine(settings, prefix='sqlalchemy.'):
    return engine_from_config(settings, prefix)
def get_dbmaker(engine):
    dbmaker = sessionmaker()
    dbmaker.configure(bind=engine)
    return dbmaker
docs/quick_tour/sqla_demo/sqla_demo/models/mymodel.py
New file
@@ -0,0 +1,19 @@
from .meta import Base
from sqlalchemy import (
    Column,
    Index,
    Integer,
    Text,
)
# Start Sphinx Include
class MyModel(Base):
    __tablename__ = 'models'
    id = Column(Integer, primary_key=True)
    name = Column(Text)
    value = Column(Integer)
    # End Sphinx Include
Index('my_index', MyModel.name, unique=True, mysql_length=255)
docs/quick_tour/sqla_demo/sqla_demo/scripts/initializedb.py
@@ -2,36 +2,44 @@
import sys
import transaction
from sqlalchemy import engine_from_config
from pyramid.paster import (
    get_appsettings,
    setup_logging,
    )
from ..models import (
    DBSession,
    MyModel,
from pyramid.scripts.common import parse_vars
from ..models.meta import (
    Base,
    get_session,
    get_engine,
    get_dbmaker,
    )
from ..models.mymodel import MyModel
def usage(argv):
    cmd = os.path.basename(argv[0])
    print('usage: %s <config_uri>\n'
    print('usage: %s <config_uri> [var=value]\n'
          '(example: "%s development.ini")' % (cmd, cmd))
    sys.exit(1)
def main(argv=sys.argv):
    if len(argv) != 2:
    if len(argv) < 2:
        usage(argv)
    config_uri = argv[1]
    options = parse_vars(argv[2:])
    setup_logging(config_uri)
    settings = get_appsettings(config_uri)
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    settings = get_appsettings(config_uri, options=options)
    engine = get_engine(settings)
    dbmaker = get_dbmaker(engine)
    dbsession = get_session(transaction.manager, dbmaker)
    Base.metadata.create_all(engine)
    with transaction.manager:
        model = MyModel(name='one', value=1)
        DBSession.add(model)
        dbsession.add(model)
docs/quick_tour/sqla_demo/sqla_demo/static/favicon.ico
Binary files differ
docs/quick_tour/sqla_demo/sqla_demo/static/footerbg.png
Binary files differ
docs/quick_tour/sqla_demo/sqla_demo/static/headerbg.png
Binary files differ
docs/quick_tour/sqla_demo/sqla_demo/static/ie6.css
File was deleted
docs/quick_tour/sqla_demo/sqla_demo/static/middlebg.png
Binary files differ
docs/quick_tour/sqla_demo/sqla_demo/static/pylons.css
File was deleted
docs/quick_tour/sqla_demo/sqla_demo/static/pyramid-16x16.png
docs/quick_tour/sqla_demo/sqla_demo/static/pyramid-small.png
Binary files differ
docs/quick_tour/sqla_demo/sqla_demo/static/pyramid.png

docs/quick_tour/sqla_demo/sqla_demo/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/sqla_demo/sqla_demo/static/theme.min.css
New file
@@ -0,0 +1 @@
@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:#fff;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:#fff}.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:#fff;text-decoration:underline}.starter-template .links ul li .icon-muted{color:#eb8b95;margin-right:5px}.starter-template .links ul li:hover .icon-muted{color:#fff}.starter-template .copyright{margin-top:10px;font-size:.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/sqla_demo/sqla_demo/static/transparent.gif
Binary files differ
docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2
copy from pyramid/scaffolds/alchemy/+package+/templates/mytemplate.pt_tmpl copy to docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2
File was copied from pyramid/scaffolds/alchemy/+package+/templates/mytemplate.pt_tmpl
@@ -1,12 +1,12 @@
<!DOCTYPE html>
<html lang="${request.locale_name}">
<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('{{package}}:static/pyramid-16x16.png')}">
    <link rel="shortcut icon" href="{{request.static_url('sqla_demo:static/pyramid-16x16.png')}}">
    <title>Alchemy Scaffold for The Pyramid Web Framework</title>
@@ -14,7 +14,7 @@
    <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('{{package}}:static/theme.css')}" rel="stylesheet">
    <link href="{{request.static_url('sqla_demo:static/theme.css')}}" rel="stylesheet">
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
@@ -29,20 +29,19 @@
      <div class="container">
        <div class="row">
          <div class="col-md-2">
            <img class="logo img-responsive" src="${request.static_url('{{package}}:static/pyramid.png')}" alt="pyramid web framework">
            <img class="logo img-responsive" src="{{request.static_url('sqla_demo:static/pyramid.png')}}" alt="pyramid web framework">
          </div>
          <div class="col-md-10">
            <div class="content">
              <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Alchemy scaffold</span></h1>
              <p class="lead">Welcome to <span class="font-normal">${project}</span>, an&nbsp;application generated&nbsp;by<br>the <span class="font-normal">Pyramid Web Framework {{pyramid_version}}</span>.</p>
            </div>
            {% block content %}
                <p>No content</p>
            {% endblock content %}
          </div>
        </div>
        <div class="row">
          <div class="links">
            <ul>
              <li class="current-version">Generated by v{{pyramid_version}}</li>
              <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/{{pyramid_docs_branch}}/">Docs</a></li>
              <li class="current-version">Generated by v1.7.dev0</li>
              <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/">Docs</a></li>
              <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="irc://irc.freenode.net#pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
docs/quick_tour/sqla_demo/sqla_demo/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">Alchemy scaffold</span></h1>
  <p class="lead">Welcome to <span class="font-normal">{{project}}</span>, an&nbsp;application generated&nbsp;by<br>the <span class="font-normal">Pyramid Web Framework 1.7.dev0</span>.</p>
</div>
{% endblock content %}
docs/quick_tour/sqla_demo/sqla_demo/templates/mytemplate.pt
File was deleted
docs/quick_tour/sqla_demo/sqla_demo/tests.py
@@ -3,31 +3,63 @@
from pyramid import testing
from .models import DBSession
def dummy_request(dbsession):
    return testing.DummyRequest(dbsession=dbsession)
class TestMyView(unittest.TestCase):
class BaseTest(unittest.TestCase):
    def setUp(self):
        self.config = testing.setUp()
        from sqlalchemy import create_engine
        engine = create_engine('sqlite://')
        from .models import (
            Base,
            MyModel,
        self.config = testing.setUp(settings={
            'sqlalchemy.url': 'sqlite:///:memory:'
        })
        self.config.include('.models.meta')
        settings = self.config.get_settings()
        from .models.meta import (
            get_session,
            get_engine,
            get_dbmaker,
            )
        DBSession.configure(bind=engine)
        Base.metadata.create_all(engine)
        with transaction.manager:
            model = MyModel(name='one', value=55)
            DBSession.add(model)
        self.engine = get_engine(settings)
        dbmaker = get_dbmaker(self.engine)
        self.session = get_session(transaction.manager, dbmaker)
    def init_database(self):
        from .models.meta import Base
        Base.metadata.create_all(self.engine)
    def tearDown(self):
        DBSession.remove()
        testing.tearDown()
        from .models.meta import Base
    def test_it(self):
        from .views import my_view
        request = testing.DummyRequest()
        info = my_view(request)
        testing.tearDown()
        transaction.abort()
        Base.metadata.create_all(self.engine)
class TestMyViewSuccessCondition(BaseTest):
    def setUp(self):
        super(TestMyViewSuccessCondition, self).setUp()
        self.init_database()
        from .models.mymodel import MyModel
        model = MyModel(name='one', value=55)
        self.session.add(model)
    def test_passing_view(self):
        from .views.default import my_view
        info = my_view(dummy_request(self.session))
        self.assertEqual(info['one'].name, 'one')
        self.assertEqual(info['project'], 'sqla_demo')
class TestMyViewFailureCondition(BaseTest):
    def test_failing_view(self):
        from .views.default import my_view
        info = my_view(dummy_request(self.session))
        self.assertEqual(info.status_int, 500)
docs/quick_tour/sqla_demo/sqla_demo/views/__init__.py
docs/quick_tour/sqla_demo/sqla_demo/views/default.py
File was renamed from docs/quick_tour/sqla_demo/sqla_demo/views.py
@@ -3,28 +3,27 @@
from sqlalchemy.exc import DBAPIError
from .models import (
    DBSession,
    MyModel,
    )
from ..models.mymodel import MyModel
@view_config(route_name='home', renderer='templates/mytemplate.pt')
@view_config(route_name='home', renderer='../templates/mytemplate.jinja2')
def my_view(request):
    try:
        query = request.dbsession.query(MyModel)
        # Start Sphinx Include
        one = DBSession.query(MyModel).filter(MyModel.name == 'one').first()
        one = query.filter(MyModel.name == 'one').first()
        # End Sphinx Include
    except DBAPIError:
        return Response(conn_err_msg, content_type='text/plain', status_int=500)
        return Response(db_err_msg, content_type='text/plain', status_int=500)
    return {'one': one, 'project': 'sqla_demo'}
conn_err_msg = """\
db_err_msg = """\
Pyramid is having a problem using your SQL database.  The problem
might be caused by one of the following things:
1.  You may need to run the "initialize_sqla_demo_db" script
    to initialize your database tables.  Check your virtual
    to initialize your database tables.  Check your virtual
    environment's "bin" directory for this script and try to run it.
2.  Your database server may not be running.  Check that the
@@ -34,4 +33,3 @@
After you fix the problem, please restart the Pyramid application to
try it again.
"""
docs/tutorials/wiki2/basiclayout.rst
@@ -12,12 +12,12 @@
A directory on disk can be turned into a Python :term:`package` by containing
an ``__init__.py`` file.  Even if empty, this marks a directory as a Python
package.  We use ``__init__.py`` both as a marker, indicating the directory
in which it's contained is a package, and to contain application configuration
package.  We use ``__init__.py`` both as a marker, indicating the directory in
which it's contained is a package, and to contain application configuration
code.
Open ``tutorial/tutorial/__init__.py``.  It should already contain
the following:
Open ``tutorial/tutorial/__init__.py``.  It should already contain the
following:
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :linenos:
@@ -43,58 +43,37 @@
above is executed.  It accepts some settings and returns a :term:`WSGI`
application.  (See :ref:`startup_chapter` for more about ``pserve``.)
The main function first creates a :term:`SQLAlchemy` database engine using
:func:`sqlalchemy.engine_from_config` from the ``sqlalchemy.`` prefixed
settings in the ``development.ini`` file's ``[app:main]`` section.
This will be a URI (something like ``sqlite://``):
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 13
      :language: py
``main`` then initializes our SQLAlchemy session object, passing it the
engine:
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 14
      :language: py
``main`` subsequently initializes our SQLAlchemy declarative ``Base`` object,
assigning the engine we created to the ``bind`` attribute of it's
``metadata`` object.  This allows table definitions done imperatively
(instead of declaratively, via a class statement) to work.  We won't use any
such tables in our application, but if you add one later, long after you've
forgotten about this tutorial, you won't be left scratching your head when it
doesn't work.
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 15
      :language: py
The next step of ``main`` is to construct a :term:`Configurator` object:
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 16
      :lines: 7
      :language: py
``settings`` is passed to the Configurator as a keyword argument with the
dictionary values passed as the ``**settings`` argument.  This will be a
dictionary of settings parsed from the ``.ini`` file, which contains
deployment-related values such as ``pyramid.reload_templates``,
``db_string``, etc.
``sqlalchemy.url``, and so on.
Next, include :term:`Chameleon` templating bindings so that we can use
renderers with the ``.pt`` extension within our project.
Next include :term:`Jinja2` templating bindings so that we can use renderers
with the ``.jinja2`` extension within our project.
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 17
      :lines: 8
      :language: py
Next include the module ``meta`` from the package ``models`` using a dotted
Python path.
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 9
      :language: py
``main`` now calls :meth:`pyramid.config.Configurator.add_static_view` with
two arguments: ``static`` (the name), and ``static`` (the path):
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 18
      :lines: 10
      :language: py
This registers a static resource view which will match any URL that starts
@@ -112,11 +91,11 @@
used when the URL is ``/``:
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 19
      :lines: 11
      :language: py
Since this route has a ``pattern`` equaling ``/`` it is the route that will
be matched when the URL ``/`` is visited, e.g. ``http://localhost:6543/``.
Since this route has a ``pattern`` equaling ``/``, it is the route that will
be matched when the URL ``/`` is visited, e.g., ``http://localhost:6543/``.
``main`` next calls the ``scan`` method of the configurator
(:meth:`pyramid.config.Configurator.scan`), which will recursively scan our
@@ -126,10 +105,10 @@
application URLs to be mapped to some code.
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 20
      :lines: 12
      :language: py
Finally, ``main`` is finished configuring things, so it uses the
Finally ``main`` is finished configuring things, so it uses the
:meth:`pyramid.config.Configurator.make_wsgi_app` method to return a
:term:`WSGI` application:
@@ -187,6 +166,39 @@
Content models with the ``models`` package
------------------------------------------
.. START moved from Application configuration with ``__init__.py``. This
  section is a WIP, and needs to be updated using the new models package.
The main function first creates a :term:`SQLAlchemy` database engine using
:func:`sqlalchemy.engine_from_config` from the ``sqlalchemy.`` prefixed
settings in the ``development.ini`` file's ``[app:main]`` section.
This will be a URI (something like ``sqlite://``):
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 13
      :language: py
``main`` then initializes our SQLAlchemy session object, passing it the
engine:
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 14
      :language: py
``main`` subsequently initializes our SQLAlchemy declarative ``Base`` object,
assigning the engine we created to the ``bind`` attribute of it's
``metadata`` object.  This allows table definitions done imperatively
(instead of declaratively, via a class statement) to work.  We won't use any
such tables in our application, but if you add one later, long after you've
forgotten about this tutorial, you won't be left scratching your head when it
doesn't work.
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 15
      :language: py
.. END moved from Application configuration with ``__init__.py``
In a SQLAlchemy-based application, a *model* object is an object composed by
querying the SQL database. The ``models`` package is where the ``alchemy``
scaffold put the classes that implement our models.
docs/tutorials/wiki2/src/basiclayout/development.ini
@@ -27,7 +27,7 @@
[server:main]
use = egg:waitress#main
host = 0.0.0.0
host = 127.0.0.1
port = 6543
###
@@ -68,4 +68,4 @@
formatter = generic
[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s
docs/tutorials/wiki2/src/basiclayout/production.ini
@@ -59,4 +59,4 @@
formatter = generic
[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s
docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py
@@ -1,20 +1,12 @@
from pyramid.config import Configurator
from sqlalchemy import engine_from_config
from .models import (
    DBSession,
    Base,
    )
def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine
    config = Configurator(settings=settings)
    config.include('pyramid_chameleon')
    config.include('pyramid_jinja2')
    config.include('.models.meta')
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.add_route('home', '/')
    config.scan()
pyramid/scaffolds/alchemy/+package+/__init__.py
@@ -1,20 +1,12 @@
from pyramid.config import Configurator
from sqlalchemy import engine_from_config
from .models import (
    DBSession,
    Base,
    )
def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine
    config = Configurator(settings=settings)
    config.include('pyramid_chameleon')
    config.include('pyramid_jinja2')
    config.include('.models.meta')
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.add_route('home', '/')
    config.scan()
pyramid/scaffolds/alchemy/+package+/models.py
File was deleted
pyramid/scaffolds/alchemy/+package+/models/__init__.py
New file
@@ -0,0 +1,7 @@
from sqlalchemy.orm import configure_mappers
# import all models classes here for sqlalchemy mappers
# to pick up
from .mymodel import MyModel # flake8: noqa
# run configure mappers to ensure we avoid any race conditions
configure_mappers()
pyramid/scaffolds/alchemy/+package+/models/meta.py
New file
@@ -0,0 +1,46 @@
from sqlalchemy import engine_from_config
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy.schema import MetaData
import zope.sqlalchemy
NAMING_CONVENTION = {
    "ix": 'ix_%(column_0_label)s',
    "uq": "uq_%(table_name)s_%(column_0_name)s",
    "ck": "ck_%(table_name)s_%(constraint_name)s",
    "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
    "pk": "pk_%(table_name)s"
}
metadata = MetaData(naming_convention=NAMING_CONVENTION)
Base = declarative_base(metadata=metadata)
def includeme(config):
    settings = config.get_settings()
    dbmaker = get_dbmaker(get_engine(settings))
    config.add_request_method(
        lambda r: get_session(r.tm, dbmaker),
        'dbsession',
        reify=True
    )
    config.include('pyramid_tm')
def get_session(transaction_manager, dbmaker):
    dbsession = dbmaker()
    zope.sqlalchemy.register(dbsession,
                             transaction_manager=transaction_manager)
    return dbsession
def get_engine(settings, prefix='sqlalchemy.'):
    return engine_from_config(settings, prefix)
def get_dbmaker(engine):
    dbmaker = sessionmaker()
    dbmaker.configure(bind=engine)
    return dbmaker
pyramid/scaffolds/alchemy/+package+/models/mymodel.py
New file
@@ -0,0 +1,17 @@
from .meta import Base
from sqlalchemy import (
    Column,
    Index,
    Integer,
    Text,
)
class MyModel(Base):
    __tablename__ = 'models'
    id = Column(Integer, primary_key=True)
    name = Column(Text)
    value = Column(Integer)
Index('my_index', MyModel.name, unique=True, mysql_length=255)
pyramid/scaffolds/alchemy/+package+/scripts/initializedb.py
@@ -2,8 +2,6 @@
import sys
import transaction
from sqlalchemy import engine_from_config
from pyramid.paster import (
    get_appsettings,
    setup_logging,
@@ -11,11 +9,13 @@
from pyramid.scripts.common import parse_vars
from ..models import (
    DBSession,
    MyModel,
from ..models.meta import (
    Base,
    get_session,
    get_engine,
    get_dbmaker,
    )
from ..models.mymodel import MyModel
def usage(argv):
@@ -32,9 +32,14 @@
    options = parse_vars(argv[2:])
    setup_logging(config_uri)
    settings = get_appsettings(config_uri, options=options)
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    engine = get_engine(settings)
    dbmaker = get_dbmaker(engine)
    dbsession = get_session(transaction.manager, dbmaker)
    Base.metadata.create_all(engine)
    with transaction.manager:
        model = MyModel(name='one', value=1)
        DBSession.add(model)
        dbsession.add(model)
pyramid/scaffolds/alchemy/+package+/templates/layout.jinja2_tmpl
File was renamed from pyramid/scaffolds/alchemy/+package+/templates/mytemplate.pt_tmpl
@@ -1,12 +1,12 @@
<!DOCTYPE html>
<html lang="${request.locale_name}">
<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('{{package}}:static/pyramid-16x16.png')}">
    <link rel="shortcut icon" href="\{\{request.static_url('{{package}}:static/pyramid-16x16.png')\}\}">
    <title>Alchemy Scaffold for The Pyramid Web Framework</title>
@@ -14,7 +14,7 @@
    <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('{{package}}:static/theme.css')}" rel="stylesheet">
    <link href="\{\{request.static_url('{{package}}:static/theme.css')\}\}" rel="stylesheet">
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
@@ -29,13 +29,12 @@
      <div class="container">
        <div class="row">
          <div class="col-md-2">
            <img class="logo img-responsive" src="${request.static_url('{{package}}:static/pyramid.png')}" alt="pyramid web framework">
            <img class="logo img-responsive" src="\{\{request.static_url('{{package}}:static/pyramid.png')\}\}" alt="pyramid web framework">
          </div>
          <div class="col-md-10">
            <div class="content">
              <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Alchemy scaffold</span></h1>
              <p class="lead">Welcome to <span class="font-normal">${project}</span>, an&nbsp;application generated&nbsp;by<br>the <span class="font-normal">Pyramid Web Framework {{pyramid_version}}</span>.</p>
            </div>
            {% block content %}
                <p>No content</p>
            {% endblock content %}
          </div>
        </div>
        <div class="row">
pyramid/scaffolds/alchemy/+package+/templates/mytemplate.jinja2_tmpl
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">Alchemy scaffold</span></h1>
  <p class="lead">Welcome to <span class="font-normal">\{\{project\}\}</span>, an&nbsp;application generated&nbsp;by<br>the <span class="font-normal">Pyramid Web Framework {{pyramid_version}}</span>.</p>
</div>
{% endblock content %}
pyramid/scaffolds/alchemy/+package+/tests.py_tmpl
@@ -3,53 +3,63 @@
from pyramid import testing
from .models import DBSession
def dummy_request(dbsession):
    return testing.DummyRequest(dbsession=dbsession)
class TestMyViewSuccessCondition(unittest.TestCase):
class BaseTest(unittest.TestCase):
    def setUp(self):
        self.config = testing.setUp()
        from sqlalchemy import create_engine
        engine = create_engine('sqlite://')
        from .models import (
            Base,
            MyModel,
        self.config = testing.setUp(settings={
            'sqlalchemy.url': 'sqlite:///:memory:'
        })
        self.config.include('.models.meta')
        settings = self.config.get_settings()
        from .models.meta import (
            get_session,
            get_engine,
            get_dbmaker,
            )
        DBSession.configure(bind=engine)
        Base.metadata.create_all(engine)
        with transaction.manager:
            model = MyModel(name='one', value=55)
            DBSession.add(model)
        self.engine = get_engine(settings)
        dbmaker = get_dbmaker(self.engine)
        self.session = get_session(transaction.manager, dbmaker)
    def init_database(self):
        from .models.meta import Base
        Base.metadata.create_all(self.engine)
    def tearDown(self):
        DBSession.remove()
        from .models.meta import Base
        testing.tearDown()
        transaction.abort()
        Base.metadata.create_all(self.engine)
class TestMyViewSuccessCondition(BaseTest):
    def setUp(self):
        super(TestMyViewSuccessCondition, self).setUp()
        self.init_database()
        from .models.mymodel import MyModel
        model = MyModel(name='one', value=55)
        self.session.add(model)
    def test_passing_view(self):
        from .views import my_view
        request = testing.DummyRequest()
        info = my_view(request)
        from .views.default import my_view
        info = my_view(dummy_request(self.session))
        self.assertEqual(info['one'].name, 'one')
        self.assertEqual(info['project'], '{{project}}')
class TestMyViewFailureCondition(unittest.TestCase):
    def setUp(self):
        self.config = testing.setUp()
        from sqlalchemy import create_engine
        engine = create_engine('sqlite://')
        from .models import (
            Base,
            MyModel,
            )
        DBSession.configure(bind=engine)
    def tearDown(self):
        DBSession.remove()
        testing.tearDown()
class TestMyViewFailureCondition(BaseTest):
    def test_failing_view(self):
        from .views import my_view
        request = testing.DummyRequest()
        info = my_view(request)
        self.assertEqual(info.status_int, 500)
        from .views.default import my_view
        info = my_view(dummy_request(self.session))
        self.assertEqual(info.status_int, 500)
pyramid/scaffolds/alchemy/+package+/views/__init__.py
pyramid/scaffolds/alchemy/+package+/views/default.py_tmpl
File was renamed from pyramid/scaffolds/alchemy/+package+/views.py_tmpl
@@ -3,22 +3,20 @@
from sqlalchemy.exc import DBAPIError
from .models import (
    DBSession,
    MyModel,
    )
from ..models.mymodel import MyModel
@view_config(route_name='home', renderer='templates/mytemplate.pt')
@view_config(route_name='home', renderer='../templates/mytemplate.jinja2')
def my_view(request):
    try:
        one = DBSession.query(MyModel).filter(MyModel.name == 'one').first()
        query = request.dbsession.query(MyModel)
        one = query.filter(MyModel.name == 'one').first()
    except DBAPIError:
        return Response(conn_err_msg, content_type='text/plain', status_int=500)
        return Response(db_err_msg, content_type='text/plain', status_int=500)
    return {'one': one, 'project': '{{project}}'}
conn_err_msg = """\
db_err_msg = """\
Pyramid is having a problem using your SQL database.  The problem
might be caused by one of the following things:
@@ -33,4 +31,3 @@
After you fix the problem, please restart the Pyramid application to
try it again.
"""
pyramid/scaffolds/alchemy/setup.py_tmpl
@@ -10,7 +10,7 @@
requires = [
    'pyramid',
    'pyramid_chameleon',
    'pyramid_jinja2',
    'pyramid_debugtoolbar',
    'pyramid_tm',
    'SQLAlchemy',