Holger Frey
7 years ago
26 changed files with 756 additions and 1 deletions
@ -0,0 +1,2 @@ |
|||||||
|
include *.txt *.ini *.cfg *.rst |
||||||
|
recursive-include ordr *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml *.jinja2 |
@ -0,0 +1,36 @@ |
|||||||
|
Ordr |
||||||
|
==== |
||||||
|
|
||||||
|
This is a complete redo of the Ordr project. |
||||||
|
|
||||||
|
|
||||||
|
Getting Started |
||||||
|
--------------- |
||||||
|
|
||||||
|
- Change directory into your newly created project. |
||||||
|
|
||||||
|
cd ordr |
||||||
|
|
||||||
|
- 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]" |
||||||
|
|
||||||
|
- Configure the database. |
||||||
|
|
||||||
|
env/bin/initialize_ordr_db development.ini |
||||||
|
|
||||||
|
- Run your project's tests. |
||||||
|
|
||||||
|
env/bin/pytest |
||||||
|
|
||||||
|
- Run your project. |
||||||
|
|
||||||
|
env/bin/pserve development.ini |
@ -0,0 +1,71 @@ |
|||||||
|
### |
||||||
|
# app configuration |
||||||
|
# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html |
||||||
|
### |
||||||
|
|
||||||
|
[app:main] |
||||||
|
use = egg:ordr |
||||||
|
|
||||||
|
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 |
||||||
|
|
||||||
|
sqlalchemy.url = sqlite:///%(here)s/ordr.sqlite |
||||||
|
|
||||||
|
retry.attempts = 3 |
||||||
|
|
||||||
|
# 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 = localhost:6543 |
||||||
|
|
||||||
|
### |
||||||
|
# logging configuration |
||||||
|
# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html |
||||||
|
### |
||||||
|
|
||||||
|
[loggers] |
||||||
|
keys = root, ordr, sqlalchemy |
||||||
|
|
||||||
|
[handlers] |
||||||
|
keys = console |
||||||
|
|
||||||
|
[formatters] |
||||||
|
keys = generic |
||||||
|
|
||||||
|
[logger_root] |
||||||
|
level = INFO |
||||||
|
handlers = console |
||||||
|
|
||||||
|
[logger_ordr] |
||||||
|
level = DEBUG |
||||||
|
handlers = |
||||||
|
qualname = ordr |
||||||
|
|
||||||
|
[logger_sqlalchemy] |
||||||
|
level = INFO |
||||||
|
handlers = |
||||||
|
qualname = sqlalchemy.engine |
||||||
|
# "level = INFO" logs SQL queries. |
||||||
|
# "level = DEBUG" logs SQL queries and results. |
||||||
|
# "level = WARN" logs neither. (Recommended for production systems.) |
||||||
|
|
||||||
|
[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 |
@ -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.include('.models') |
||||||
|
config.include('.routes') |
||||||
|
config.scan() |
||||||
|
return config.make_wsgi_app() |
@ -0,0 +1,77 @@ |
|||||||
|
from sqlalchemy import engine_from_config |
||||||
|
from sqlalchemy.orm import sessionmaker |
||||||
|
from sqlalchemy.orm import configure_mappers |
||||||
|
import zope.sqlalchemy |
||||||
|
|
||||||
|
# import or define all models here to ensure they are attached to the |
||||||
|
# Base.metadata prior to any initialization routines |
||||||
|
from .mymodel import MyModel # flake8: noqa |
||||||
|
|
||||||
|
# run configure_mappers after defining all of the models to ensure |
||||||
|
# all relationships can be setup |
||||||
|
configure_mappers() |
||||||
|
|
||||||
|
|
||||||
|
def get_engine(settings, prefix='sqlalchemy.'): |
||||||
|
return engine_from_config(settings, prefix) |
||||||
|
|
||||||
|
|
||||||
|
def get_session_factory(engine): |
||||||
|
factory = sessionmaker() |
||||||
|
factory.configure(bind=engine) |
||||||
|
return factory |
||||||
|
|
||||||
|
|
||||||
|
def get_tm_session(session_factory, transaction_manager): |
||||||
|
""" |
||||||
|
Get a ``sqlalchemy.orm.Session`` instance backed by a transaction. |
||||||
|
|
||||||
|
This function will hook the session to the transaction manager which |
||||||
|
will take care of committing any changes. |
||||||
|
|
||||||
|
- When using pyramid_tm it will automatically be committed or aborted |
||||||
|
depending on whether an exception is raised. |
||||||
|
|
||||||
|
- When using scripts you should wrap the session in a manager yourself. |
||||||
|
For example:: |
||||||
|
|
||||||
|
import transaction |
||||||
|
|
||||||
|
engine = get_engine(settings) |
||||||
|
session_factory = get_session_factory(engine) |
||||||
|
with transaction.manager: |
||||||
|
dbsession = get_tm_session(session_factory, transaction.manager) |
||||||
|
|
||||||
|
""" |
||||||
|
dbsession = session_factory() |
||||||
|
zope.sqlalchemy.register( |
||||||
|
dbsession, transaction_manager=transaction_manager) |
||||||
|
return dbsession |
||||||
|
|
||||||
|
|
||||||
|
def includeme(config): |
||||||
|
""" |
||||||
|
Initialize the model for a Pyramid app. |
||||||
|
|
||||||
|
Activate this setup using ``config.include('ordr.models')``. |
||||||
|
|
||||||
|
""" |
||||||
|
settings = config.get_settings() |
||||||
|
settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' |
||||||
|
|
||||||
|
# use pyramid_tm to hook the transaction lifecycle to the request |
||||||
|
config.include('pyramid_tm') |
||||||
|
|
||||||
|
# use pyramid_retry to retry a request when transient exceptions occur |
||||||
|
config.include('pyramid_retry') |
||||||
|
|
||||||
|
session_factory = get_session_factory(get_engine(settings)) |
||||||
|
config.registry['dbsession_factory'] = session_factory |
||||||
|
|
||||||
|
# make request.dbsession available for use in Pyramid |
||||||
|
config.add_request_method( |
||||||
|
# r.tm is the transaction manager used by pyramid_tm |
||||||
|
lambda r: get_tm_session(session_factory, r.tm), |
||||||
|
'dbsession', |
||||||
|
reify=True |
||||||
|
) |
@ -0,0 +1,16 @@ |
|||||||
|
from sqlalchemy.ext.declarative import declarative_base |
||||||
|
from sqlalchemy.schema import MetaData |
||||||
|
|
||||||
|
# Recommended naming convention used by Alembic, as various different database |
||||||
|
# providers will autogenerate vastly different names making migrations more |
||||||
|
# difficult. See: http://alembic.zzzcomputing.com/en/latest/naming.html |
||||||
|
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) |
@ -0,0 +1,18 @@ |
|||||||
|
from sqlalchemy import ( |
||||||
|
Column, |
||||||
|
Index, |
||||||
|
Integer, |
||||||
|
Text, |
||||||
|
) |
||||||
|
|
||||||
|
from .meta import Base |
||||||
|
|
||||||
|
|
||||||
|
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) |
@ -0,0 +1,3 @@ |
|||||||
|
def includeme(config): |
||||||
|
config.add_static_view('static', 'static', cache_max_age=3600) |
||||||
|
config.add_route('home', '/') |
@ -0,0 +1,45 @@ |
|||||||
|
import os |
||||||
|
import sys |
||||||
|
import transaction |
||||||
|
|
||||||
|
from pyramid.paster import ( |
||||||
|
get_appsettings, |
||||||
|
setup_logging, |
||||||
|
) |
||||||
|
|
||||||
|
from pyramid.scripts.common import parse_vars |
||||||
|
|
||||||
|
from ..models.meta import Base |
||||||
|
from ..models import ( |
||||||
|
get_engine, |
||||||
|
get_session_factory, |
||||||
|
get_tm_session, |
||||||
|
) |
||||||
|
from ..models import MyModel |
||||||
|
|
||||||
|
|
||||||
|
def usage(argv): |
||||||
|
cmd = os.path.basename(argv[0]) |
||||||
|
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: |
||||||
|
usage(argv) |
||||||
|
config_uri = argv[1] |
||||||
|
options = parse_vars(argv[2:]) |
||||||
|
setup_logging(config_uri) |
||||||
|
settings = get_appsettings(config_uri, options=options) |
||||||
|
|
||||||
|
engine = get_engine(settings) |
||||||
|
Base.metadata.create_all(engine) |
||||||
|
|
||||||
|
session_factory = get_session_factory(engine) |
||||||
|
|
||||||
|
with transaction.manager: |
||||||
|
dbsession = get_tm_session(session_factory, transaction.manager) |
||||||
|
|
||||||
|
model = MyModel(name='one', value=1) |
||||||
|
dbsession.add(model) |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 13 KiB |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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"><span class="font-semi-bold">404</span> Page Not Found</p> |
||||||
|
</div> |
||||||
|
{% endblock content %} |
@ -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('ordr:static/pyramid-16x16.png')}}"> |
||||||
|
|
||||||
|
<title>Cookiecutter Alchemy 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('ordr: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" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script> |
||||||
|
<script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></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('ordr: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="https://pylonsproject.org">Pylons Project</a></li> |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="row"> |
||||||
|
<div class="copyright"> |
||||||
|
Copyright © 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" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script> |
||||||
|
<script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,8 @@ |
|||||||
|
{% extends "layout.jinja2" %} |
||||||
|
|
||||||
|
{% block content %} |
||||||
|
<div class="content"> |
||||||
|
<h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Alchemy project</span></h1> |
||||||
|
<p class="lead">Welcome to <span class="font-normal">Ordr</span>, a Pyramid application generated by<br><span class="font-normal">Cookiecutter</span>.</p> |
||||||
|
</div> |
||||||
|
{% endblock content %} |
@ -0,0 +1,65 @@ |
|||||||
|
import unittest |
||||||
|
import transaction |
||||||
|
|
||||||
|
from pyramid import testing |
||||||
|
|
||||||
|
|
||||||
|
def dummy_request(dbsession): |
||||||
|
return testing.DummyRequest(dbsession=dbsession) |
||||||
|
|
||||||
|
|
||||||
|
class BaseTest(unittest.TestCase): |
||||||
|
def setUp(self): |
||||||
|
self.config = testing.setUp(settings={ |
||||||
|
'sqlalchemy.url': 'sqlite:///:memory:' |
||||||
|
}) |
||||||
|
self.config.include('.models') |
||||||
|
settings = self.config.get_settings() |
||||||
|
|
||||||
|
from .models import ( |
||||||
|
get_engine, |
||||||
|
get_session_factory, |
||||||
|
get_tm_session, |
||||||
|
) |
||||||
|
|
||||||
|
self.engine = get_engine(settings) |
||||||
|
session_factory = get_session_factory(self.engine) |
||||||
|
|
||||||
|
self.session = get_tm_session(session_factory, transaction.manager) |
||||||
|
|
||||||
|
def init_database(self): |
||||||
|
from .models.meta import Base |
||||||
|
Base.metadata.create_all(self.engine) |
||||||
|
|
||||||
|
def tearDown(self): |
||||||
|
from .models.meta import Base |
||||||
|
|
||||||
|
testing.tearDown() |
||||||
|
transaction.abort() |
||||||
|
Base.metadata.drop_all(self.engine) |
||||||
|
|
||||||
|
|
||||||
|
class TestMyViewSuccessCondition(BaseTest): |
||||||
|
|
||||||
|
def setUp(self): |
||||||
|
super(TestMyViewSuccessCondition, self).setUp() |
||||||
|
self.init_database() |
||||||
|
|
||||||
|
from .models 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'], 'Ordr') |
||||||
|
|
||||||
|
|
||||||
|
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) |
@ -0,0 +1,33 @@ |
|||||||
|
from pyramid.response import Response |
||||||
|
from pyramid.view import view_config |
||||||
|
|
||||||
|
from sqlalchemy.exc import DBAPIError |
||||||
|
|
||||||
|
from ..models import MyModel |
||||||
|
|
||||||
|
|
||||||
|
@view_config(route_name='home', renderer='../templates/mytemplate.jinja2') |
||||||
|
def my_view(request): |
||||||
|
try: |
||||||
|
query = request.dbsession.query(MyModel) |
||||||
|
one = query.filter(MyModel.name == 'one').first() |
||||||
|
except DBAPIError: |
||||||
|
return Response(db_err_msg, content_type='text/plain', status=500) |
||||||
|
return {'one': one, 'project': 'Ordr'} |
||||||
|
|
||||||
|
|
||||||
|
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_ordr_db" script |
||||||
|
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 |
||||||
|
database server referred to by the "sqlalchemy.url" setting in |
||||||
|
your "development.ini" file is running. |
||||||
|
|
||||||
|
After you fix the problem, please restart the Pyramid application to |
||||||
|
try it again. |
||||||
|
""" |
@ -0,0 +1,7 @@ |
|||||||
|
from pyramid.view import notfound_view_config |
||||||
|
|
||||||
|
|
||||||
|
@notfound_view_config(renderer='../templates/404.jinja2') |
||||||
|
def notfound_view(request): |
||||||
|
request.response.status = 404 |
||||||
|
return {} |
@ -0,0 +1,65 @@ |
|||||||
|
### |
||||||
|
# app configuration |
||||||
|
# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html |
||||||
|
### |
||||||
|
|
||||||
|
[app:main] |
||||||
|
use = egg:ordr |
||||||
|
|
||||||
|
pyramid.reload_templates = false |
||||||
|
pyramid.debug_authorization = false |
||||||
|
pyramid.debug_notfound = false |
||||||
|
pyramid.debug_routematch = false |
||||||
|
pyramid.default_locale_name = en |
||||||
|
|
||||||
|
sqlalchemy.url = sqlite:///%(here)s/ordr.sqlite |
||||||
|
|
||||||
|
retry.attempts = 3 |
||||||
|
|
||||||
|
### |
||||||
|
# wsgi server configuration |
||||||
|
### |
||||||
|
|
||||||
|
[server:main] |
||||||
|
use = egg:waitress#main |
||||||
|
listen = *:6543 |
||||||
|
|
||||||
|
### |
||||||
|
# logging configuration |
||||||
|
# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html |
||||||
|
### |
||||||
|
|
||||||
|
[loggers] |
||||||
|
keys = root, ordr, sqlalchemy |
||||||
|
|
||||||
|
[handlers] |
||||||
|
keys = console |
||||||
|
|
||||||
|
[formatters] |
||||||
|
keys = generic |
||||||
|
|
||||||
|
[logger_root] |
||||||
|
level = WARN |
||||||
|
handlers = console |
||||||
|
|
||||||
|
[logger_ordr] |
||||||
|
level = WARN |
||||||
|
handlers = |
||||||
|
qualname = ordr |
||||||
|
|
||||||
|
[logger_sqlalchemy] |
||||||
|
level = WARN |
||||||
|
handlers = |
||||||
|
qualname = sqlalchemy.engine |
||||||
|
# "level = INFO" logs SQL queries. |
||||||
|
# "level = DEBUG" logs SQL queries and results. |
||||||
|
# "level = WARN" logs neither. (Recommended for production systems.) |
||||||
|
|
||||||
|
[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 |
@ -0,0 +1,60 @@ |
|||||||
|
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 = [ |
||||||
|
'plaster_pastedeploy', |
||||||
|
'pyramid >= 1.9a', |
||||||
|
'pyramid_debugtoolbar', |
||||||
|
'pyramid_jinja2', |
||||||
|
'pyramid_retry', |
||||||
|
'pyramid_tm', |
||||||
|
'SQLAlchemy', |
||||||
|
'transaction', |
||||||
|
'zope.sqlalchemy', |
||||||
|
'waitress', |
||||||
|
] |
||||||
|
|
||||||
|
tests_require = [ |
||||||
|
'WebTest >= 1.3.1', # py3 compat |
||||||
|
'pytest', |
||||||
|
'pytest-cov', |
||||||
|
] |
||||||
|
|
||||||
|
setup( |
||||||
|
name='ordr', |
||||||
|
version='0.0', |
||||||
|
description='Ordr', |
||||||
|
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 = ordr:main', |
||||||
|
], |
||||||
|
'console_scripts': [ |
||||||
|
'initialize_ordr_db = ordr.scripts.initializedb:main', |
||||||
|
], |
||||||
|
}, |
||||||
|
) |
Reference in new issue