From 05a1b4a37df7e855747f66174a472b0de3ce1c9e Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 1 Jul 2011 02:08:03 -0400 Subject: - The Wiki2 tutorial "Tests" chapter had two bugs: it did not tell the user to depend on WebTest, and 2 tests failed as the result of changes to Pyramid itself. These issues have been fixed. --- docs/tutorials/wiki2/src/tests/CHANGES.txt | 4 ++ docs/tutorials/wiki2/src/tests/MANIFEST.in | 2 + docs/tutorials/wiki2/src/tests/README.txt | 4 ++ docs/tutorials/wiki2/src/tests/development.ini | 58 ++++++++++++++++ docs/tutorials/wiki2/src/tests/production.ini | 77 +++++++++++++++++++++ docs/tutorials/wiki2/src/tests/setup.cfg | 27 ++++++++ docs/tutorials/wiki2/src/tests/setup.py | 49 +++++++++++++ .../tutorials/wiki2/src/tests/tutorial/__init__.py | 45 ++++++++++++ docs/tutorials/wiki2/src/tests/tutorial/login.py | 38 ++++++++++ docs/tutorials/wiki2/src/tests/tutorial/models.py | 50 +++++++++++++ .../tutorials/wiki2/src/tests/tutorial/security.py | 8 +++ .../wiki2/src/tests/tutorial/static/favicon.ico | Bin 0 -> 1406 bytes .../wiki2/src/tests/tutorial/static/footerbg.png | Bin 0 -> 333 bytes .../wiki2/src/tests/tutorial/static/headerbg.png | Bin 0 -> 203 bytes .../wiki2/src/tests/tutorial/static/ie6.css | 8 +++ .../wiki2/src/tests/tutorial/static/middlebg.png | Bin 0 -> 2797 bytes .../wiki2/src/tests/tutorial/static/pylons.css | 65 +++++++++++++++++ .../src/tests/tutorial/static/pyramid-small.png | Bin 0 -> 7044 bytes .../wiki2/src/tests/tutorial/static/pyramid.png | Bin 0 -> 33055 bytes .../src/tests/tutorial/static/transparent.gif | Bin 0 -> 49 bytes .../wiki2/src/tests/tutorial/templates/edit.pt | 62 +++++++++++++++++ .../wiki2/src/tests/tutorial/templates/login.pt | 58 ++++++++++++++++ .../src/tests/tutorial/templates/mytemplate.pt | 75 ++++++++++++++++++++ .../wiki2/src/tests/tutorial/templates/view.pt | 65 +++++++++++++++++ docs/tutorials/wiki2/src/tests/tutorial/tests.py | 6 +- docs/tutorials/wiki2/src/tests/tutorial/views.py | 72 +++++++++++++++++++ 26 files changed, 770 insertions(+), 3 deletions(-) create mode 100644 docs/tutorials/wiki2/src/tests/CHANGES.txt create mode 100644 docs/tutorials/wiki2/src/tests/MANIFEST.in create mode 100644 docs/tutorials/wiki2/src/tests/README.txt create mode 100644 docs/tutorials/wiki2/src/tests/development.ini create mode 100644 docs/tutorials/wiki2/src/tests/production.ini create mode 100644 docs/tutorials/wiki2/src/tests/setup.cfg create mode 100644 docs/tutorials/wiki2/src/tests/setup.py create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/__init__.py create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/login.py create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/models.py create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/security.py create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/static/favicon.ico create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/static/footerbg.png create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/static/headerbg.png create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/static/ie6.css create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/static/middlebg.png create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/static/pylons.css create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/static/pyramid-small.png create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/static/pyramid.png create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/static/transparent.gif create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/templates/edit.pt create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/templates/login.pt create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/templates/mytemplate.pt create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/templates/view.pt create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/views.py (limited to 'docs/tutorials/wiki2/src/tests') diff --git a/docs/tutorials/wiki2/src/tests/CHANGES.txt b/docs/tutorials/wiki2/src/tests/CHANGES.txt new file mode 100644 index 000000000..35a34f332 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/CHANGES.txt @@ -0,0 +1,4 @@ +0.0 +--- + +- Initial version diff --git a/docs/tutorials/wiki2/src/tests/MANIFEST.in b/docs/tutorials/wiki2/src/tests/MANIFEST.in new file mode 100644 index 000000000..81beba1b1 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/MANIFEST.in @@ -0,0 +1,2 @@ +include *.txt *.ini *.cfg *.rst +recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml diff --git a/docs/tutorials/wiki2/src/tests/README.txt b/docs/tutorials/wiki2/src/tests/README.txt new file mode 100644 index 000000000..d41f7f90f --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/README.txt @@ -0,0 +1,4 @@ +tutorial README + + + diff --git a/docs/tutorials/wiki2/src/tests/development.ini b/docs/tutorials/wiki2/src/tests/development.ini new file mode 100644 index 000000000..3b615f635 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/development.ini @@ -0,0 +1,58 @@ +[app:tutorial] +use = egg:tutorial +reload_templates = true +debug_authorization = false +debug_notfound = false +debug_routematch = false +debug_templates = true +default_locale_name = en +sqlalchemy.url = sqlite:///%(here)s/tutorial.db + +[pipeline:main] +pipeline = + egg:WebError#evalerror + tm + tutorial + +[filter:tm] +use = egg:repoze.tm2#tm +commit_veto = repoze.tm:default_commit_veto + +[server:main] +use = egg:Paste#http +host = 0.0.0.0 +port = 6543 + +# Begin logging configuration + +[loggers] +keys = root, sqlalchemy + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = INFO +handlers = console + +[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][%(threadName)s] %(message)s + +# End logging configuration diff --git a/docs/tutorials/wiki2/src/tests/production.ini b/docs/tutorials/wiki2/src/tests/production.ini new file mode 100644 index 000000000..0fdc38811 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/production.ini @@ -0,0 +1,77 @@ +[app:tutorial] +use = egg:tutorial +reload_templates = false +debug_authorization = false +debug_notfound = false +debug_routematch = false +debug_templates = false +default_locale_name = en +sqlalchemy.url = sqlite:///%(here)s/tutorial.db + +[filter:weberror] +use = egg:WebError#error_catcher +debug = false +;error_log = +;show_exceptions_in_wsgi_errors = true +;smtp_server = localhost +;error_email = janitor@example.com +;smtp_username = janitor +;smtp_password = "janitor's password" +;from_address = paste@localhost +;error_subject_prefix = "Pyramid Error" +;smtp_use_tls = +;error_message = + +[filter:tm] +use = egg:repoze.tm2#tm +commit_veto = repoze.tm:default_commit_veto + +[pipeline:main] +pipeline = + weberror + tm + tutorial + +[server:main] +use = egg:Paste#http +host = 0.0.0.0 +port = 6543 + +# Begin logging configuration + +[loggers] +keys = root, tutorial, sqlalchemy + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console + +[logger_tutorial] +level = WARN +handlers = +qualname = tutorial + +[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][%(threadName)s] %(message)s + +# End logging configuration diff --git a/docs/tutorials/wiki2/src/tests/setup.cfg b/docs/tutorials/wiki2/src/tests/setup.cfg new file mode 100644 index 000000000..23b2ad983 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/setup.cfg @@ -0,0 +1,27 @@ +[nosetests] +match=^test +nocapture=1 +cover-package=tutorial +with-coverage=1 +cover-erase=1 + +[compile_catalog] +directory = tutorial/locale +domain = tutorial +statistics = true + +[extract_messages] +add_comments = TRANSLATORS: +output_file = tutorial/locale/tutorial.pot +width = 80 + +[init_catalog] +domain = tutorial +input_file = tutorial/locale/tutorial.pot +output_dir = tutorial/locale + +[update_catalog] +domain = tutorial +input_file = tutorial/locale/tutorial.pot +output_dir = tutorial/locale +previous = true diff --git a/docs/tutorials/wiki2/src/tests/setup.py b/docs/tutorials/wiki2/src/tests/setup.py new file mode 100644 index 000000000..7828f185d --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/setup.py @@ -0,0 +1,49 @@ +import os +import sys + +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() + +requires = [ + 'pyramid', + 'SQLAlchemy', + 'transaction', + 'repoze.tm2>=1.0b1', + 'zope.sqlalchemy', + 'WebError', + 'docutils', + 'WebTest', # add this + ] + +if sys.version_info[:3] < (2,5,0): + requires.append('pysqlite') + +setup(name='tutorial', + version='0.0', + description='tutorial', + long_description=README + '\n\n' + CHANGES, + classifiers=[ + "Programming Language :: Python", + "Framework :: Pylons", + "Topic :: Internet :: WWW/HTTP", + "Topic :: Internet :: WWW/HTTP :: WSGI :: Application", + ], + author='', + author_email='', + url='', + keywords='web wsgi bfg pylons pyramid', + packages=find_packages(), + include_package_data=True, + zip_safe=False, + test_suite='tutorial', + install_requires = requires, + entry_points = """\ + [paste.app_factory] + main = tutorial:main + """, + paster_plugins=['pyramid'], + ) + diff --git a/docs/tutorials/wiki2/src/tests/tutorial/__init__.py b/docs/tutorials/wiki2/src/tests/tutorial/__init__.py new file mode 100644 index 000000000..4cd84eda5 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/__init__.py @@ -0,0 +1,45 @@ +from pyramid.config import Configurator +from pyramid.authentication import AuthTktAuthenticationPolicy +from pyramid.authorization import ACLAuthorizationPolicy + +from sqlalchemy import engine_from_config + +from tutorial.models import initialize_sql +from tutorial.security import groupfinder + +def main(global_config, **settings): + """ This function returns a WSGI application. + """ + engine = engine_from_config(settings, 'sqlalchemy.') + initialize_sql(engine) + authn_policy = AuthTktAuthenticationPolicy( + 'sosecret', callback=groupfinder) + authz_policy = ACLAuthorizationPolicy() + config = Configurator(settings=settings, + root_factory='tutorial.models.RootFactory', + authentication_policy=authn_policy, + authorization_policy=authz_policy) + config.add_static_view('static', 'tutorial:static') + + config.add_route('view_wiki', '/') + config.add_route('login', '/login') + config.add_route('logout', '/logout') + config.add_route('view_page', '/{pagename}') + config.add_route('add_page', '/add_page/{pagename}') + config.add_route('edit_page', '/{pagename}/edit_page') + + config.add_view('tutorial.views.view_wiki', route_name='view_wiki') + config.add_view('tutorial.login.login', route_name='login', + renderer='tutorial:templates/login.pt') + config.add_view('tutorial.login.logout', route_name='logout') + config.add_view('tutorial.views.view_page', route_name='view_page', + renderer='tutorial:templates/view.pt') + config.add_view('tutorial.views.add_page', route_name='add_page', + renderer='tutorial:templates/edit.pt', permission='edit') + config.add_view('tutorial.views.edit_page', route_name='edit_page', + renderer='tutorial:templates/edit.pt', permission='edit') + config.add_view('tutorial.login.login', + context='pyramid.httpexceptions.HTTPForbidden', + renderer='tutorial:templates/login.pt') + return config.make_wsgi_app() + diff --git a/docs/tutorials/wiki2/src/tests/tutorial/login.py b/docs/tutorials/wiki2/src/tests/tutorial/login.py new file mode 100644 index 000000000..7a1d1f663 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/login.py @@ -0,0 +1,38 @@ +from pyramid.httpexceptions import HTTPFound +from pyramid.security import remember +from pyramid.security import forget +from pyramid.url import route_url + +from tutorial.security import USERS + +def login(request): + login_url = route_url('login', request) + referrer = request.url + if referrer == login_url: + referrer = '/' # never use the login form itself as came_from + came_from = request.params.get('came_from', referrer) + message = '' + login = '' + password = '' + if 'form.submitted' in request.params: + login = request.params['login'] + password = request.params['password'] + if USERS.get(login) == password: + headers = remember(request, login) + return HTTPFound(location = came_from, + headers = headers) + message = 'Failed login' + + return dict( + message = message, + url = request.application_url + '/login', + came_from = came_from, + login = login, + password = password, + ) + +def logout(request): + headers = forget(request) + return HTTPFound(location = route_url('view_wiki', request), + headers = headers) + diff --git a/docs/tutorials/wiki2/src/tests/tutorial/models.py b/docs/tutorials/wiki2/src/tests/tutorial/models.py new file mode 100644 index 000000000..53c6d1122 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/models.py @@ -0,0 +1,50 @@ +import transaction + +from pyramid.security import Allow +from pyramid.security import Everyone + +from sqlalchemy import Column +from sqlalchemy import Integer +from sqlalchemy import Text + +from sqlalchemy.exc import IntegrityError +from sqlalchemy.ext.declarative import declarative_base + +from sqlalchemy.orm import scoped_session +from sqlalchemy.orm import sessionmaker + +from zope.sqlalchemy import ZopeTransactionExtension + +DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension())) +Base = declarative_base() + +class Page(Base): + """ The SQLAlchemy declarative model class for a Page object. """ + __tablename__ = 'pages' + id = Column(Integer, primary_key=True) + name = Column(Text, unique=True) + data = Column(Text) + + def __init__(self, name, data): + self.name = name + self.data = data + +def initialize_sql(engine): + DBSession.configure(bind=engine) + Base.metadata.bind = engine + Base.metadata.create_all(engine) + try: + transaction.begin() + session = DBSession() + page = Page('FrontPage', 'This is the front page') + session.add(page) + transaction.commit() + except IntegrityError: + # already created + pass + +class RootFactory(object): + __acl__ = [ (Allow, Everyone, 'view'), + (Allow, 'group:editors', 'edit') ] + def __init__(self, request): + pass diff --git a/docs/tutorials/wiki2/src/tests/tutorial/security.py b/docs/tutorials/wiki2/src/tests/tutorial/security.py new file mode 100644 index 000000000..cfd13071e --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/security.py @@ -0,0 +1,8 @@ +USERS = {'editor':'editor', + 'viewer':'viewer'} +GROUPS = {'editor':['group:editors']} + +def groupfinder(userid, request): + if userid in USERS: + return GROUPS.get(userid, []) + diff --git a/docs/tutorials/wiki2/src/tests/tutorial/static/favicon.ico b/docs/tutorials/wiki2/src/tests/tutorial/static/favicon.ico new file mode 100644 index 000000000..71f837c9e Binary files /dev/null and b/docs/tutorials/wiki2/src/tests/tutorial/static/favicon.ico differ diff --git a/docs/tutorials/wiki2/src/tests/tutorial/static/footerbg.png b/docs/tutorials/wiki2/src/tests/tutorial/static/footerbg.png new file mode 100644 index 000000000..1fbc873da Binary files /dev/null and b/docs/tutorials/wiki2/src/tests/tutorial/static/footerbg.png differ diff --git a/docs/tutorials/wiki2/src/tests/tutorial/static/headerbg.png b/docs/tutorials/wiki2/src/tests/tutorial/static/headerbg.png new file mode 100644 index 000000000..0596f2020 Binary files /dev/null and b/docs/tutorials/wiki2/src/tests/tutorial/static/headerbg.png differ diff --git a/docs/tutorials/wiki2/src/tests/tutorial/static/ie6.css b/docs/tutorials/wiki2/src/tests/tutorial/static/ie6.css new file mode 100644 index 000000000..b7c8493d8 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/static/ie6.css @@ -0,0 +1,8 @@ +* html img, +* html .png{position:relative;behavior:expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none", +this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "',sizingMethod='image')", +this.src = "static/transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("','').replace('")',''), +this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "',sizingMethod='crop')", +this.runtimeStyle.backgroundImage = "none")),this.pngSet=true) +);} +#wrap{display:table;height:100%} diff --git a/docs/tutorials/wiki2/src/tests/tutorial/static/middlebg.png b/docs/tutorials/wiki2/src/tests/tutorial/static/middlebg.png new file mode 100644 index 000000000..2369cfb7d Binary files /dev/null and b/docs/tutorials/wiki2/src/tests/tutorial/static/middlebg.png differ diff --git a/docs/tutorials/wiki2/src/tests/tutorial/static/pylons.css b/docs/tutorials/wiki2/src/tests/tutorial/static/pylons.css new file mode 100644 index 000000000..fd1914d8d --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/static/pylons.css @@ -0,0 +1,65 @@ +html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;/* 16px */ +vertical-align:baseline;background:transparent;} +body{line-height:1;} +ol,ul{list-style:none;} +blockquote,q{quotes:none;} +blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;} +:focus{outline:0;} +ins{text-decoration:none;} +del{text-decoration:line-through;} +table{border-collapse:collapse;border-spacing:0;} +sub{vertical-align:sub;font-size:smaller;line-height:normal;} +sup{vertical-align:super;font-size:smaller;line-height:normal;} +ul,menu,dir{display:block;list-style-type:disc;margin:1em 0;padding-left:40px;} +ol{display:block;list-style-type:decimal-leading-zero;margin:1em 0;padding-left:40px;} +li{display:list-item;} +ul ul,ul ol,ul dir,ul menu,ul dl,ol ul,ol ol,ol dir,ol menu,ol dl,dir ul,dir ol,dir dir,dir menu,dir dl,menu ul,menu ol,menu dir,menu menu,menu dl,dl ul,dl ol,dl dir,dl menu,dl dl{margin-top:0;margin-bottom:0;} +ol ul,ul ul,menu ul,dir ul,ol menu,ul menu,menu menu,dir menu,ol dir,ul dir,menu dir,dir dir{list-style-type:circle;} +ol ol ul,ol ul ul,ol menu ul,ol dir ul,ol ol menu,ol ul menu,ol menu menu,ol dir menu,ol ol dir,ol ul dir,ol menu dir,ol dir dir,ul ol ul,ul ul ul,ul menu ul,ul dir ul,ul ol menu,ul ul menu,ul menu menu,ul dir menu,ul ol dir,ul ul dir,ul menu dir,ul dir dir,menu ol ul,menu ul ul,menu menu ul,menu dir ul,menu ol menu,menu ul menu,menu menu menu,menu dir menu,menu ol dir,menu ul dir,menu menu dir,menu dir dir,dir ol ul,dir ul ul,dir menu ul,dir dir ul,dir ol menu,dir ul menu,dir menu menu,dir dir menu,dir ol dir,dir ul dir,dir menu dir,dir dir dir{list-style-type:square;} +.hidden{display:none;} +p{line-height:1.5em;} +h1{font-size:1.75em;line-height:1.7em;font-family:helvetica,verdana;} +h2{font-size:1.5em;line-height:1.7em;font-family:helvetica,verdana;} +h3{font-size:1.25em;line-height:1.7em;font-family:helvetica,verdana;} +h4{font-size:1em;line-height:1.7em;font-family:helvetica,verdana;} +html,body{width:100%;height:100%;} +body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;} +a{color:#1b61d6;text-decoration:none;} +a:hover{color:#e88f00;text-decoration:underline;} +body h1, +body h2, +body h3, +body h4, +body h5, +body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} +#wrap{min-height:100%;} +#header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;} +#header{background:#000000;top:0;font-size:14px;} +#footer{bottom:0;background:#000000 url(footerbg.png) repeat-x 0 top;position:relative;margin-top:-40px;clear:both;} +.header,.footer{width:750px;margin-right:auto;margin-left:auto;} +.wrapper{width:100%} +#top,#top-small,#bottom{width:100%;} +#top{color:#000000;height:230px;background:#ffffff url(headerbg.png) repeat-x 0 top;position:relative;} +#top-small{color:#000000;height:60px;background:#ffffff url(headerbg.png) repeat-x 0 top;position:relative;} +#bottom{color:#222;background-color:#ffffff;} +.top,.top-small,.middle,.bottom{width:750px;margin-right:auto;margin-left:auto;} +.top{padding-top:40px;} +.top-small{padding-top:10px;} +#middle{width:100%;height:100px;background:url(middlebg.png) repeat-x;border-top:2px solid #ffffff;border-bottom:2px solid #b2b2b2;} +.app-welcome{margin-top:25px;} +.app-name{color:#000000;font-weight:bold;} +.bottom{padding-top:50px;} +#left{width:350px;float:left;padding-right:25px;} +#right{width:350px;float:right;padding-left:25px;} +.align-left{text-align:left;} +.align-right{text-align:right;} +.align-center{text-align:center;} +ul.links{margin:0;padding:0;} +ul.links li{list-style-type:none;font-size:14px;} +form{border-style:none;} +fieldset{border-style:none;} +input{color:#222;border:1px solid #ccc;font-family:sans-serif;font-size:12px;line-height:16px;} +input[type=text],input[type=password]{width:205px;} +input[type=submit]{background-color:#ddd;font-weight:bold;} +/*Opera Fix*/ +body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;} diff --git a/docs/tutorials/wiki2/src/tests/tutorial/static/pyramid-small.png b/docs/tutorials/wiki2/src/tests/tutorial/static/pyramid-small.png new file mode 100644 index 000000000..a5bc0ade7 Binary files /dev/null and b/docs/tutorials/wiki2/src/tests/tutorial/static/pyramid-small.png differ diff --git a/docs/tutorials/wiki2/src/tests/tutorial/static/pyramid.png b/docs/tutorials/wiki2/src/tests/tutorial/static/pyramid.png new file mode 100644 index 000000000..347e05549 Binary files /dev/null and b/docs/tutorials/wiki2/src/tests/tutorial/static/pyramid.png differ diff --git a/docs/tutorials/wiki2/src/tests/tutorial/static/transparent.gif b/docs/tutorials/wiki2/src/tests/tutorial/static/transparent.gif new file mode 100644 index 000000000..0341802e5 Binary files /dev/null and b/docs/tutorials/wiki2/src/tests/tutorial/static/transparent.gif differ diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/edit.pt b/docs/tutorials/wiki2/src/tests/tutorial/templates/edit.pt new file mode 100644 index 000000000..ca28b9fa5 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/templates/edit.pt @@ -0,0 +1,62 @@ + + + + ${page.name} - Pyramid tutorial wiki (based on + TurboGears 20-Minute Wiki) + + + + + + + + +
+
+
+
+ pyramid +
+
+
+
+
+
+ Editing Page Name + Goes Here
+ You can return to the + FrontPage.
+
+ +
+
+
+
+
+ +
+
+ +
+ +
+
- - -
-
-
- Editing Page Name - Goes Here
- You can return to the - FrontPage.
-
-
-
-
-
- +
+
+ +
+ +
+
+ +
+ +
+ + + + + + + + + + diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/edit.pt b/docs/tutorials/wiki2/src/tests/tutorial/templates/edit.pt deleted file mode 100644 index 50e55c850..000000000 --- a/docs/tutorials/wiki2/src/tests/tutorial/templates/edit.pt +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - ${page.name} - Pyramid tutorial wiki (based on - TurboGears 20-Minute Wiki) - - - - - - - - - - - - -
-
-
-
- -
-
-
-

- Editing Page Name Goes - Here -

-

You can return to the - FrontPage. -

-

- - Logout - -

-
-
- -
-
- -
-
-
-
-
-
- -
-
-
- - - - - - - - diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 new file mode 100644 index 000000000..ff624c65b --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 @@ -0,0 +1,66 @@ + + + + + + + + + + + Alchemy Scaffold for The Pyramid Web Framework + + + + + + + + + + + + + +
+
+
+
+ +
+
+ {% block content %} +

No content

+ {% endblock content %} +
+
+
+ +
+
+ +
+
+
+ + + + + + + + diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/login.jinja2 b/docs/tutorials/wiki2/src/tests/tutorial/templates/login.jinja2 new file mode 100644 index 000000000..a80a2a165 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/templates/login.jinja2 @@ -0,0 +1,74 @@ + + + + + + + + + + + Login - Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki) + + + + + + + + + + + + + +
+
+
+
+ +
+
+
+

+ + Login +
+ {{ message }} +

+
+ +
+ + +
+
+ + +
+
+ +
+
+
+
+
+
+ +
+
+
+ + + + + + + + diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/login.pt b/docs/tutorials/wiki2/src/tests/tutorial/templates/login.pt deleted file mode 100644 index 5f8e9b98c..000000000 --- a/docs/tutorials/wiki2/src/tests/tutorial/templates/login.pt +++ /dev/null @@ -1,54 +0,0 @@ - - - - Login - Pyramid tutorial wiki (based on TurboGears - 20-Minute Wiki) - - - - - - - - -
-
-
-
- pyramid -
-
-
-
-
-
- Login
- -
- -
-
-
-
-
- -
-
- -
-
-
-
- - diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/mytemplate.jinja2 b/docs/tutorials/wiki2/src/tests/tutorial/templates/mytemplate.jinja2 new file mode 100644 index 000000000..bb622bf5a --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/templates/mytemplate.jinja2 @@ -0,0 +1,8 @@ +{% extends "layout.jinja2" %} + +{% block content %} +
+

Pyramid Alchemy scaffold

+

Welcome to {{project}}, an application generated by
the Pyramid Web Framework 1.7.dev0.

+
+{% endblock content %} diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki2/src/tests/tutorial/templates/mytemplate.pt deleted file mode 100644 index c9b0cec21..000000000 --- a/docs/tutorials/wiki2/src/tests/tutorial/templates/mytemplate.pt +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - Alchemy Scaffold for The Pyramid Web Framework - - - - - - - - - - - - - -
-
-
-
- -
-
-
-

Pyramid Alchemy scaffold

-

Welcome to ${project}, an application generated by
the Pyramid Web Framework.

-
-
-
- -
- -
-
-
- - - - - - - - diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/view.jinja2 b/docs/tutorials/wiki2/src/tests/tutorial/templates/view.jinja2 new file mode 100644 index 000000000..a7afc66fc --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/templates/view.jinja2 @@ -0,0 +1,71 @@ + + + + + + + + + + + {{page.name}} - Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki) + + + + + + + + + + + + + +
+
+
+
+ +
+
+
+ {% if logged_in %} +

+ Logout +

+ {% endif %} +

{{ content|safe }}

+

+ + Edit this page + +

+

+ Viewing {% if page.name %}{{page.name}}{% else %}Page Name Goes Here{% endif %} +

+

You can return to the + FrontPage. +

+
+
+
+
+ +
+
+
+ + + + + + + + diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/view.pt b/docs/tutorials/wiki2/src/tests/tutorial/templates/view.pt deleted file mode 100644 index 4e5772de0..000000000 --- a/docs/tutorials/wiki2/src/tests/tutorial/templates/view.pt +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - ${page.name} - Pyramid tutorial wiki (based on - TurboGears 20-Minute Wiki) - - - - - - - - - - - - -
-
-
-
- -
-
-
-
- Page text goes here. -
-

- - Edit this page - -

-

- Viewing - Page Name Goes Here -

-

You can return to the - FrontPage. -

-

- - Logout - -

-
-
-
-
- -
-
-
- - - - - - - - diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests.py b/docs/tutorials/wiki2/src/tests/tutorial/tests.py deleted file mode 100644 index c50e05b6d..000000000 --- a/docs/tutorials/wiki2/src/tests/tutorial/tests.py +++ /dev/null @@ -1,235 +0,0 @@ -import unittest -import transaction - -from pyramid import testing - - -def _initTestingDB(): - from sqlalchemy import create_engine - from tutorial.models import ( - DBSession, - Page, - Base - ) - engine = create_engine('sqlite://') - Base.metadata.create_all(engine) - DBSession.configure(bind=engine) - with transaction.manager: - model = Page(name='FrontPage', data='This is the front page') - DBSession.add(model) - return DBSession - - -def _registerRoutes(config): - config.add_route('view_page', '{pagename}') - config.add_route('edit_page', '{pagename}/edit_page') - config.add_route('add_page', 'add_page/{pagename}') - - -class ViewWikiTests(unittest.TestCase): - def setUp(self): - self.config = testing.setUp() - - def tearDown(self): - testing.tearDown() - - def _callFUT(self, request): - from tutorial.views import view_wiki - return view_wiki(request) - - def test_it(self): - _registerRoutes(self.config) - request = testing.DummyRequest() - response = self._callFUT(request) - self.assertEqual(response.location, 'http://example.com/FrontPage') - - -class ViewPageTests(unittest.TestCase): - def setUp(self): - self.session = _initTestingDB() - self.config = testing.setUp() - - def tearDown(self): - self.session.remove() - testing.tearDown() - - def _callFUT(self, request): - from tutorial.views import view_page - return view_page(request) - - def test_it(self): - from tutorial.models import Page - request = testing.DummyRequest() - request.matchdict['pagename'] = 'IDoExist' - page = Page(name='IDoExist', data='Hello CruelWorld IDoExist') - self.session.add(page) - _registerRoutes(self.config) - info = self._callFUT(request) - self.assertEqual(info['page'], page) - self.assertEqual( - info['content'], - '
\n' - '

Hello ' - 'CruelWorld ' - '' - 'IDoExist' - '

\n
\n') - self.assertEqual(info['edit_url'], - 'http://example.com/IDoExist/edit_page') - - -class AddPageTests(unittest.TestCase): - def setUp(self): - self.session = _initTestingDB() - self.config = testing.setUp() - - def tearDown(self): - self.session.remove() - testing.tearDown() - - def _callFUT(self, request): - from tutorial.views import add_page - return add_page(request) - - def test_it_notsubmitted(self): - _registerRoutes(self.config) - request = testing.DummyRequest() - request.matchdict = {'pagename':'AnotherPage'} - info = self._callFUT(request) - self.assertEqual(info['page'].data,'') - self.assertEqual(info['save_url'], - 'http://example.com/add_page/AnotherPage') - - def test_it_submitted(self): - from tutorial.models import Page - _registerRoutes(self.config) - request = testing.DummyRequest({'form.submitted':True, - 'body':'Hello yo!'}) - request.matchdict = {'pagename':'AnotherPage'} - self._callFUT(request) - page = self.session.query(Page).filter_by(name='AnotherPage').one() - self.assertEqual(page.data, 'Hello yo!') - - -class EditPageTests(unittest.TestCase): - def setUp(self): - self.session = _initTestingDB() - self.config = testing.setUp() - - def tearDown(self): - self.session.remove() - testing.tearDown() - - def _callFUT(self, request): - from tutorial.views import edit_page - return edit_page(request) - - def test_it_notsubmitted(self): - from tutorial.models import Page - _registerRoutes(self.config) - request = testing.DummyRequest() - request.matchdict = {'pagename':'abc'} - page = Page(name='abc', data='hello') - self.session.add(page) - info = self._callFUT(request) - self.assertEqual(info['page'], page) - self.assertEqual(info['save_url'], - 'http://example.com/abc/edit_page') - - def test_it_submitted(self): - from tutorial.models import Page - _registerRoutes(self.config) - request = testing.DummyRequest({'form.submitted':True, - 'body':'Hello yo!'}) - request.matchdict = {'pagename':'abc'} - page = Page(name='abc', data='hello') - self.session.add(page) - response = self._callFUT(request) - self.assertEqual(response.location, 'http://example.com/abc') - self.assertEqual(page.data, 'Hello yo!') - - -class FunctionalTests(unittest.TestCase): - - viewer_login = '/login?login=viewer&password=viewer' \ - '&came_from=FrontPage&form.submitted=Login' - viewer_wrong_login = '/login?login=viewer&password=incorrect' \ - '&came_from=FrontPage&form.submitted=Login' - editor_login = '/login?login=editor&password=editor' \ - '&came_from=FrontPage&form.submitted=Login' - - def setUp(self): - from tutorial import main - settings = { 'sqlalchemy.url': 'sqlite://'} - app = main({}, **settings) - from webtest import TestApp - self.testapp = TestApp(app) - _initTestingDB() - - def tearDown(self): - del self.testapp - from tutorial.models import DBSession - DBSession.remove() - - def test_root(self): - res = self.testapp.get('/', status=302) - self.assertEqual(res.location, 'http://localhost/FrontPage') - - def test_FrontPage(self): - res = self.testapp.get('/FrontPage', status=200) - self.assertTrue(b'FrontPage' in res.body) - - def test_unexisting_page(self): - self.testapp.get('/SomePage', status=404) - - def test_successful_log_in(self): - res = self.testapp.get(self.viewer_login, status=302) - self.assertEqual(res.location, 'http://localhost/FrontPage') - - def test_failed_log_in(self): - res = self.testapp.get(self.viewer_wrong_login, status=200) - self.assertTrue(b'login' in res.body) - - def test_logout_link_present_when_logged_in(self): - self.testapp.get(self.viewer_login, status=302) - res = self.testapp.get('/FrontPage', status=200) - self.assertTrue(b'Logout' in res.body) - - def test_logout_link_not_present_after_logged_out(self): - self.testapp.get(self.viewer_login, status=302) - self.testapp.get('/FrontPage', status=200) - res = self.testapp.get('/logout', status=302) - self.assertTrue(b'Logout' not in res.body) - - def test_anonymous_user_cannot_edit(self): - res = self.testapp.get('/FrontPage/edit_page', status=200) - self.assertTrue(b'Login' in res.body) - - def test_anonymous_user_cannot_add(self): - res = self.testapp.get('/add_page/NewPage', status=200) - self.assertTrue(b'Login' in res.body) - - def test_viewer_user_cannot_edit(self): - self.testapp.get(self.viewer_login, status=302) - res = self.testapp.get('/FrontPage/edit_page', status=200) - self.assertTrue(b'Login' in res.body) - - def test_viewer_user_cannot_add(self): - self.testapp.get(self.viewer_login, status=302) - res = self.testapp.get('/add_page/NewPage', status=200) - self.assertTrue(b'Login' in res.body) - - def test_editors_member_user_can_edit(self): - self.testapp.get(self.editor_login, status=302) - res = self.testapp.get('/FrontPage/edit_page', status=200) - self.assertTrue(b'Editing' in res.body) - - def test_editors_member_user_can_add(self): - self.testapp.get(self.editor_login, status=302) - res = self.testapp.get('/add_page/NewPage', status=200) - self.assertTrue(b'Editing' in res.body) - - def test_editors_member_user_can_view(self): - self.testapp.get(self.editor_login, status=302) - res = self.testapp.get('/FrontPage', status=200) - self.assertTrue(b'FrontPage' in res.body) diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests/__init__.py b/docs/tutorials/wiki2/src/tests/tutorial/tests/__init__.py new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/tests/__init__.py @@ -0,0 +1 @@ + diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py new file mode 100644 index 000000000..339c60bc2 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py @@ -0,0 +1,141 @@ +import unittest + +from pyramid import testing + + +def dummy_request(dbsession): + return testing.DummyRequest(dbsession=dbsession) + + +def _register_routes(config): + config.add_route('view_page', '{pagename}') + config.add_route('edit_page', '{pagename}/edit_page') + config.add_route('add_page', 'add_page/{pagename}') + + +class FunctionalTests(unittest.TestCase): + + viewer_login = '/login?login=viewer&password=viewer' \ + '&came_from=FrontPage&form.submitted=Login' + viewer_wrong_login = '/login?login=viewer&password=incorrect' \ + '&came_from=FrontPage&form.submitted=Login' + editor_login = '/login?login=editor&password=editor' \ + '&came_from=FrontPage&form.submitted=Login' + + engine = None + + @staticmethod + def setup_database(): + import transaction + from tutorial.models.mymodel import Page + from tutorial.models.meta import ( + Base, + ) + import tutorial.models.meta + + + def initialize_db(dbsession, engine): + Base.metadata.create_all(engine) + with transaction.manager: + model = Page(name='FrontPage', data='This is the front page') + dbsession.add(model) + + def wrap_get_session(transaction_manager, dbmaker): + dbsession = get_session(transaction_manager, dbmaker) + initialize_db(dbsession, engine) + tutorial.models.meta.get_session = get_session + tutorial.models.meta.get_engine = get_engine + return dbsession + + def wrap_get_engine(settings): + global engine + engine = get_engine(settings) + return engine + + get_session = tutorial.models.meta.get_session + tutorial.models.meta.get_session = wrap_get_session + + get_engine = tutorial.models.meta.get_engine + tutorial.models.meta.get_engine = wrap_get_engine + + @classmethod + def setUpClass(cls): + cls.setup_database() + + from webtest import TestApp + from tutorial import main + settings = {'sqlalchemy.url': 'sqlite://'} + app = main({}, **settings) + cls.testapp = TestApp(app) + + @classmethod + def tearDownClass(cls): + from tutorial.models.meta import Base + Base.metadata.drop_all(engine) + + def tearDown(self): + import transaction + transaction.abort() + + def test_root(self): + res = self.testapp.get('/', status=302) + self.assertEqual(res.location, 'http://localhost/FrontPage') + + def test_FrontPage(self): + res = self.testapp.get('/FrontPage', status=200) + self.assertTrue(b'FrontPage' in res.body) + + def test_unexisting_page(self): + self.testapp.get('/SomePage', status=404) + + def test_successful_log_in(self): + res = self.testapp.get(self.viewer_login, status=302) + self.assertEqual(res.location, 'http://localhost/FrontPage') + + def test_failed_log_in(self): + res = self.testapp.get(self.viewer_wrong_login, status=200) + self.assertTrue(b'login' in res.body) + + def test_logout_link_present_when_logged_in(self): + self.testapp.get(self.viewer_login, status=302) + res = self.testapp.get('/FrontPage', status=200) + self.assertTrue(b'Logout' in res.body) + + def test_logout_link_not_present_after_logged_out(self): + self.testapp.get(self.viewer_login, status=302) + self.testapp.get('/FrontPage', status=200) + res = self.testapp.get('/logout', status=302) + self.assertTrue(b'Logout' not in res.body) + + def test_anonymous_user_cannot_edit(self): + res = self.testapp.get('/FrontPage/edit_page', status=200) + self.assertTrue(b'Login' in res.body) + + def test_anonymous_user_cannot_add(self): + res = self.testapp.get('/add_page/NewPage', status=200) + self.assertTrue(b'Login' in res.body) + + def test_viewer_user_cannot_edit(self): + self.testapp.get(self.viewer_login, status=302) + res = self.testapp.get('/FrontPage/edit_page', status=200) + self.assertTrue(b'Login' in res.body) + + def test_viewer_user_cannot_add(self): + self.testapp.get(self.viewer_login, status=302) + res = self.testapp.get('/add_page/NewPage', status=200) + self.assertTrue(b'Login' in res.body) + + def test_editors_member_user_can_edit(self): + self.testapp.get(self.editor_login, status=302) + res = self.testapp.get('/FrontPage/edit_page', status=200) + self.assertTrue(b'Editing' in res.body) + + def test_editors_member_user_can_add(self): + self.testapp.get(self.editor_login, status=302) + res = self.testapp.get('/add_page/NewPage', status=200) + self.assertTrue(b'Editing' in res.body) + + def test_editors_member_user_can_view(self): + self.testapp.get(self.editor_login, status=302) + res = self.testapp.get('/FrontPage', status=200) + self.assertTrue(b'FrontPage' in res.body) diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py new file mode 100644 index 000000000..d70311e38 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py @@ -0,0 +1,168 @@ +import unittest +import transaction + +from pyramid import testing + + +def dummy_request(dbsession): + return testing.DummyRequest(dbsession=dbsession) + + +def _register_routes(config): + config.add_route('view_page', '{pagename}') + config.add_route('edit_page', '{pagename}/edit_page') + config.add_route('add_page', 'add_page/{pagename}') + + +class BaseTest(unittest.TestCase): + def setUp(self): + self.config = testing.setUp(settings={ + 'sqlalchemy.url': 'sqlite:///:memory:' + }) + self.config.include('..models.meta') + _register_routes(self.config) + settings = self.config.get_settings() + + from ..models.meta import ( + get_session, + get_engine, + get_dbmaker, + ) + + self.engine = get_engine(settings) + dbmaker = get_dbmaker(self.engine) + + self.session = get_session(transaction.manager, dbmaker) + + self.init_database() + + def init_database(self): + from ..models.meta import Base + Base.metadata.create_all(self.engine) + + def tearDown(self): + testing.tearDown() + transaction.abort() + + +class ViewWikiTests(unittest.TestCase): + + def setUp(self): + self.config = testing.setUp() + _register_routes(self.config) + + def tearDown(self): + testing.tearDown() + + def _callFUT(self, request): + from tutorial.views.default import view_wiki + return view_wiki(request) + + def test_it(self): + request = testing.DummyRequest() + response = self._callFUT(request) + self.assertEqual(response.location, 'http://example.com/FrontPage') + + +class ViewPageTests(BaseTest): + def setUp(self): + super(ViewPageTests, self).setUp() + + def tearDown(self): + transaction.abort() + testing.tearDown() + + def _callFUT(self, request): + from tutorial.views.default import view_page + return view_page(request) + + def test_it(self): + # add a page to the db + from ..models.mymodel import Page + page = Page(name='IDoExist', data='Hello CruelWorld IDoExist') + self.session.add(page) + + # create a request asking for the page we've created + request = dummy_request(self.session) + request.matchdict['pagename'] = 'IDoExist' + + # call the view we're testing and check its behavior + info = self._callFUT(request) + self.assertEqual(info['page'], page) + self.assertEqual( + info['content'], + '
\n' + '

Hello ' + 'CruelWorld ' + '' + 'IDoExist' + '

\n
\n') + self.assertEqual(info['edit_url'], + 'http://example.com/IDoExist/edit_page') + + +class AddPageTests(BaseTest): + def setUp(self): + super(AddPageTests, self).setUp() + + def tearDown(self): + transaction.abort() + testing.tearDown() + + def _callFUT(self, request): + from tutorial.views.default import add_page + return add_page(request) + + def test_it_notsubmitted(self): + request = dummy_request(self.session) + request.matchdict = {'pagename': 'AnotherPage'} + info = self._callFUT(request) + self.assertEqual(info['page'].data, '') + self.assertEqual(info['save_url'], + 'http://example.com/add_page/AnotherPage') + + def test_it_submitted(self): + from ..models.mymodel import Page + request = testing.DummyRequest({'form.submitted': True, + 'body': 'Hello yo!'}, + dbsession=self.session) + request.matchdict = {'pagename': 'AnotherPage'} + self._callFUT(request) + page = self.session.query(Page).filter_by(name='AnotherPage').one() + self.assertEqual(page.data, 'Hello yo!') + + +class EditPageTests(BaseTest): + def setUp(self): + super(EditPageTests, self).setUp() + + def tearDown(self): + transaction.abort() + testing.tearDown() + + def _callFUT(self, request): + from tutorial.views.default import edit_page + return edit_page(request) + + def test_it_notsubmitted(self): + from ..models.mymodel import Page + request = dummy_request(self.session) + request.matchdict = {'pagename': 'abc'} + page = Page(name='abc', data='hello') + self.session.add(page) + info = self._callFUT(request) + self.assertEqual(info['page'], page) + self.assertEqual(info['save_url'], + 'http://example.com/abc/edit_page') + + def test_it_submitted(self): + from ..models.mymodel import Page + request = testing.DummyRequest({'form.submitted': True, + 'body': 'Hello yo!'}, + dbsession=self.session) + request.matchdict = {'pagename': 'abc'} + page = Page(name='abc', data='hello') + self.session.add(page) + response = self._callFUT(request) + self.assertEqual(response.location, 'http://example.com/abc') + self.assertEqual(page.data, 'Hello yo!') diff --git a/docs/tutorials/wiki2/src/tests/tutorial/views.py b/docs/tutorials/wiki2/src/tests/tutorial/views.py deleted file mode 100644 index 41bea4785..000000000 --- a/docs/tutorials/wiki2/src/tests/tutorial/views.py +++ /dev/null @@ -1,123 +0,0 @@ -import re -from docutils.core import publish_parts - -from pyramid.httpexceptions import ( - HTTPFound, - HTTPNotFound, - ) - -from pyramid.view import ( - view_config, - forbidden_view_config, - ) - -from pyramid.security import ( - remember, - forget, - ) - -from .security import USERS - -from .models import ( - DBSession, - Page, - ) - - -# regular expression used to find WikiWords -wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") - -@view_config(route_name='view_wiki', - permission='view') -def view_wiki(request): - return HTTPFound(location = request.route_url('view_page', - pagename='FrontPage')) - -@view_config(route_name='view_page', renderer='templates/view.pt', - permission='view') -def view_page(request): - pagename = request.matchdict['pagename'] - page = DBSession.query(Page).filter_by(name=pagename).first() - if page is None: - return HTTPNotFound('No such page') - - def check(match): - word = match.group(1) - exists = DBSession.query(Page).filter_by(name=word).all() - if exists: - view_url = request.route_url('view_page', pagename=word) - return '%s' % (view_url, word) - else: - add_url = request.route_url('add_page', pagename=word) - return '%s' % (add_url, word) - - content = publish_parts(page.data, writer_name='html')['html_body'] - content = wikiwords.sub(check, content) - edit_url = request.route_url('edit_page', pagename=pagename) - return dict(page=page, content=content, edit_url=edit_url, - logged_in=request.authenticated_userid) - -@view_config(route_name='add_page', renderer='templates/edit.pt', - permission='edit') -def add_page(request): - pagename = request.matchdict['pagename'] - if 'form.submitted' in request.params: - body = request.params['body'] - page = Page(name=pagename, data=body) - DBSession.add(page) - return HTTPFound(location = request.route_url('view_page', - pagename=pagename)) - save_url = request.route_url('add_page', pagename=pagename) - page = Page(name='', data='') - return dict(page=page, save_url=save_url, - logged_in=request.authenticated_userid) - -@view_config(route_name='edit_page', renderer='templates/edit.pt', - permission='edit') -def edit_page(request): - pagename = request.matchdict['pagename'] - page = DBSession.query(Page).filter_by(name=pagename).one() - if 'form.submitted' in request.params: - page.data = request.params['body'] - DBSession.add(page) - return HTTPFound(location = request.route_url('view_page', - pagename=pagename)) - return dict( - page=page, - save_url=request.route_url('edit_page', pagename=pagename), - logged_in=request.authenticated_userid - ) - -@view_config(route_name='login', renderer='templates/login.pt') -@forbidden_view_config(renderer='templates/login.pt') -def login(request): - login_url = request.route_url('login') - referrer = request.url - if referrer == login_url: - referrer = '/' # never use the login form itself as came_from - came_from = request.params.get('came_from', referrer) - message = '' - login = '' - password = '' - if 'form.submitted' in request.params: - login = request.params['login'] - password = request.params['password'] - if USERS.get(login) == password: - headers = remember(request, login) - return HTTPFound(location = came_from, - headers = headers) - message = 'Failed login' - - return dict( - message = message, - url = request.application_url + '/login', - came_from = came_from, - login = login, - password = password, - ) - -@view_config(route_name='logout') -def logout(request): - headers = forget(request) - return HTTPFound(location = request.route_url('view_wiki'), - headers = headers) diff --git a/docs/tutorials/wiki2/src/tests/tutorial/views/__init__.py b/docs/tutorials/wiki2/src/tests/tutorial/views/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs/tutorials/wiki2/src/tests/tutorial/views/default.py b/docs/tutorials/wiki2/src/tests/tutorial/views/default.py new file mode 100644 index 000000000..f35f041a4 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/views/default.py @@ -0,0 +1,120 @@ +import cgi +import re +from docutils.core import publish_parts + +from pyramid.httpexceptions import ( + HTTPFound, + HTTPNotFound, + ) + +from pyramid.view import ( + view_config, + forbidden_view_config, + ) + +from pyramid.security import ( + remember, + forget, + ) + +from ..security.default import USERS + +from ..models.mymodel import Page + +# regular expression used to find WikiWords +wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") + +@view_config(route_name='view_wiki', + permission='view') +def view_wiki(request): + return HTTPFound(location=request.route_url('view_page', + pagename='FrontPage')) + +@view_config(route_name='view_page', renderer='templates/view.jinja2', + permission='view') +def view_page(request): + pagename = request.matchdict['pagename'] + page = request.dbsession.query(Page).filter_by(name=pagename).first() + if page is None: + return HTTPNotFound('No such page') + + def check(match): + word = match.group(1) + exists = request.dbsession.query(Page).filter_by(name=word).all() + if exists: + view_url = request.route_url('view_page', pagename=word) + return '%s' % (view_url, cgi.escape(word)) + else: + add_url = request.route_url('add_page', pagename=word) + return '%s' % (add_url, cgi.escape(word)) + + content = publish_parts(page.data, writer_name='html')['html_body'] + content = wikiwords.sub(check, content) + edit_url = request.route_url('edit_page', pagename=pagename) + return dict(page=page, content=content, edit_url=edit_url, + logged_in=request.authenticated_userid) + +@view_config(route_name='add_page', renderer='templates/edit.jinja2', + permission='edit') +def add_page(request): + pagename = request.matchdict['pagename'] + if 'form.submitted' in request.params: + body = request.params['body'] + page = Page(name=pagename, data=body) + request.dbsession.add(page) + return HTTPFound(location = request.route_url('view_page', + pagename=pagename)) + save_url = request.route_url('add_page', pagename=pagename) + page = Page(name='', data='') + return dict(page=page, save_url=save_url, + logged_in=request.authenticated_userid) + +@view_config(route_name='edit_page', renderer='templates/edit.jinja2', + permission='edit') +def edit_page(request): + pagename = request.matchdict['pagename'] + page = request.dbsession.query(Page).filter_by(name=pagename).one() + if 'form.submitted' in request.params: + page.data = request.params['body'] + request.dbsession.add(page) + return HTTPFound(location = request.route_url('view_page', + pagename=pagename)) + return dict( + page=page, + save_url = request.route_url('edit_page', pagename=pagename), + logged_in=request.authenticated_userid + ) + +@view_config(route_name='login', renderer='templates/login.jinja2') +@forbidden_view_config(renderer='templates/login.jinja2') +def login(request): + login_url = request.route_url('login') + referrer = request.url + if referrer == login_url: + referrer = '/' # never use the login form itself as came_from + came_from = request.params.get('came_from', referrer) + message = '' + login = '' + password = '' + if 'form.submitted' in request.params: + login = request.params['login'] + password = request.params['password'] + if USERS.get(login) == password: + headers = remember(request, login) + return HTTPFound(location = came_from, + headers = headers) + message = 'Failed login' + + return dict( + message = message, + url = request.application_url + '/login', + came_from = came_from, + login = login, + password = password, + ) + +@view_config(route_name='logout') +def logout(request): + headers = forget(request) + return HTTPFound(location = request.route_url('view_wiki'), + headers = headers) -- cgit v1.2.3 From 022a6e0f05b72c679aada6b3c9313c4fd5b31b80 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 2 Dec 2015 04:30:47 -0800 Subject: - add comment to NAMING_CONVENTION per 9b12c01168cb756ec36351d7414cad95e87f6581 --- docs/tutorials/wiki2/src/tests/tutorial/models/meta.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'docs/tutorials/wiki2/src/tests') diff --git a/docs/tutorials/wiki2/src/tests/tutorial/models/meta.py b/docs/tutorials/wiki2/src/tests/tutorial/models/meta.py index b72b45f9f..80ececd8c 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/models/meta.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/models/meta.py @@ -4,6 +4,9 @@ from sqlalchemy.orm import sessionmaker from sqlalchemy.schema import MetaData import zope.sqlalchemy +# Recommended naming convention used by Alembic, as various different database +# providers will autogenerate vastly different names making migrations more +# difficult. See: http://alembic.readthedocs.org/en/latest/naming.html NAMING_CONVENTION = { "ix": 'ix_%(column_0_label)s', "uq": "uq_%(table_name)s_%(column_0_name)s", -- cgit v1.2.3 From 1c108019dae884e810d6436e10f8648c77bdd181 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 8 Feb 2016 00:43:47 -0600 Subject: [wip] update tests in wiki2 tutorial --- docs/tutorials/wiki2/src/tests/MANIFEST.in | 2 +- docs/tutorials/wiki2/src/tests/production.ini | 2 - docs/tutorials/wiki2/src/tests/setup.py | 1 - .../tutorials/wiki2/src/tests/tutorial/__init__.py | 11 ++-- .../wiki2/src/tests/tutorial/models/__init__.py | 72 +++++++++++++++++++++- .../wiki2/src/tests/tutorial/models/meta.py | 33 ---------- .../wiki2/src/tests/tutorial/models/mymodel.py | 19 +++--- .../src/tests/tutorial/scripts/initializedb.py | 27 ++++---- .../wiki2/src/tests/tutorial/security/__init__.py | 1 - .../wiki2/src/tests/tutorial/security/default.py | 11 +++- .../wiki2/src/tests/tutorial/templates/404.jinja2 | 8 +++ .../wiki2/src/tests/tutorial/templates/edit.jinja2 | 6 +- .../wiki2/src/tests/tutorial/templates/view.jinja2 | 6 +- .../wiki2/src/tests/tutorial/tests/__init__.py | 1 - .../src/tests/tutorial/tests/test_functional.py | 29 ++------- .../wiki2/src/tests/tutorial/tests/test_views.py | 46 +++----------- .../wiki2/src/tests/tutorial/views/default.py | 54 +++++++--------- .../wiki2/src/tests/tutorial/views/errors.py | 5 ++ 18 files changed, 167 insertions(+), 167 deletions(-) create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/templates/404.jinja2 create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/views/errors.py (limited to 'docs/tutorials/wiki2/src/tests') diff --git a/docs/tutorials/wiki2/src/tests/MANIFEST.in b/docs/tutorials/wiki2/src/tests/MANIFEST.in index 81beba1b1..42cd299b5 100644 --- a/docs/tutorials/wiki2/src/tests/MANIFEST.in +++ b/docs/tutorials/wiki2/src/tests/MANIFEST.in @@ -1,2 +1,2 @@ include *.txt *.ini *.cfg *.rst -recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml +recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.jinja2 *.pt *.txt *.mak *.mako *.js *.html *.xml diff --git a/docs/tutorials/wiki2/src/tests/production.ini b/docs/tutorials/wiki2/src/tests/production.ini index 97acfbd7d..cb1db3211 100644 --- a/docs/tutorials/wiki2/src/tests/production.ini +++ b/docs/tutorials/wiki2/src/tests/production.ini @@ -11,8 +11,6 @@ pyramid.debug_authorization = false pyramid.debug_notfound = false pyramid.debug_routematch = false pyramid.default_locale_name = en -pyramid.includes = - pyramid_tm sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite diff --git a/docs/tutorials/wiki2/src/tests/setup.py b/docs/tutorials/wiki2/src/tests/setup.py index f640b4399..d4e5a4072 100644 --- a/docs/tutorials/wiki2/src/tests/setup.py +++ b/docs/tutorials/wiki2/src/tests/setup.py @@ -18,7 +18,6 @@ requires = [ 'zope.sqlalchemy', 'waitress', 'docutils', - 'WebTest', ] setup(name='tutorial', diff --git a/docs/tutorials/wiki2/src/tests/tutorial/__init__.py b/docs/tutorials/wiki2/src/tests/tutorial/__init__.py index 084fee19f..a62c42378 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/__init__.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/__init__.py @@ -2,7 +2,8 @@ from pyramid.config import Configurator from pyramid.authentication import AuthTktAuthenticationPolicy from pyramid.authorization import ACLAuthorizationPolicy -from security.default import groupfinder +from .security.default import groupfinder + def main(global_config, **settings): """ This function returns a Pyramid WSGI application. @@ -10,12 +11,12 @@ def main(global_config, **settings): authn_policy = AuthTktAuthenticationPolicy( 'sosecret', callback=groupfinder, hashalg='sha512') authz_policy = ACLAuthorizationPolicy() - config = Configurator(settings=settings, - root_factory='tutorial.models.mymodel.RootFactory') + config = Configurator(settings=settings) + config.include('pyramid_jinja2') + config.include('.models') + config.set_root_factory('.models.mymodel.RootFactory') config.set_authentication_policy(authn_policy) config.set_authorization_policy(authz_policy) - config.include('pyramid_jinja2') - config.include('.models.meta') config.add_static_view('static', 'static', cache_max_age=3600) config.add_route('view_wiki', '/') config.add_route('login', '/login') diff --git a/docs/tutorials/wiki2/src/tests/tutorial/models/__init__.py b/docs/tutorials/wiki2/src/tests/tutorial/models/__init__.py index 7b1c62867..3d3efe06f 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/models/__init__.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/models/__init__.py @@ -1,7 +1,73 @@ +from sqlalchemy import engine_from_config +from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import configure_mappers -# import all models classes here for sqlalchemy mappers -# to pick up +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 Page # flake8: noqa -# run configure mappers to ensure we avoid any race conditions +# 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('tutorial.models')``. + + """ + settings = config.get_settings() + + # use pyramid_tm to hook the transaction lifecycle to the request + config.include('pyramid_tm') + + 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 + ) diff --git a/docs/tutorials/wiki2/src/tests/tutorial/models/meta.py b/docs/tutorials/wiki2/src/tests/tutorial/models/meta.py index 80ececd8c..fc3e8f1dd 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/models/meta.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/models/meta.py @@ -1,8 +1,5 @@ -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 # Recommended naming convention used by Alembic, as various different database # providers will autogenerate vastly different names making migrations more @@ -17,33 +14,3 @@ NAMING_CONVENTION = { 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 diff --git a/docs/tutorials/wiki2/src/tests/tutorial/models/mymodel.py b/docs/tutorials/wiki2/src/tests/tutorial/models/mymodel.py index 03e2f90ca..25209c745 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/models/mymodel.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/models/mymodel.py @@ -1,15 +1,14 @@ -from .meta import Base - from pyramid.security import ( Allow, Everyone, - ) - +) from sqlalchemy import ( Column, Integer, Text, - ) +) + +from .meta import Base class Page(Base): @@ -19,8 +18,12 @@ class Page(Base): name = Column(Text, unique=True) data = Column(Integer) + class RootFactory(object): - __acl__ = [ (Allow, Everyone, 'view'), - (Allow, 'group:editors', 'edit') ] + __acl__ = [ + (Allow, Everyone, 'view'), + (Allow, 'group:editors', 'edit'), + ] + def __init__(self, request): - pass \ No newline at end of file + pass diff --git a/docs/tutorials/wiki2/src/tests/tutorial/scripts/initializedb.py b/docs/tutorials/wiki2/src/tests/tutorial/scripts/initializedb.py index 4aac4a848..601a6e73f 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/scripts/initializedb.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/scripts/initializedb.py @@ -7,13 +7,15 @@ from pyramid.paster import ( setup_logging, ) -from ..models.meta import ( - Base, - get_session, +from pyramid.scripts.common import parse_vars + +from ..models.meta import Base +from ..models import ( get_engine, - get_dbmaker, + get_session_factory, + get_tm_session, ) -from ..models.mymodel import Page +from ..models import Page def usage(argv): @@ -27,16 +29,17 @@ 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) + 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) + session_factory = get_session_factory(engine) + with transaction.manager: - model = Page(name='FrontPage', data='This is the front page') - dbsession.add(model) + dbsession = get_tm_session(session_factory, transaction.manager) + + page = Page(name='FrontPage', data='This is the front page') + dbsession.add(page) diff --git a/docs/tutorials/wiki2/src/tests/tutorial/security/__init__.py b/docs/tutorials/wiki2/src/tests/tutorial/security/__init__.py index 5bb534f79..e69de29bb 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/security/__init__.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/security/__init__.py @@ -1 +0,0 @@ -# package diff --git a/docs/tutorials/wiki2/src/tests/tutorial/security/default.py b/docs/tutorials/wiki2/src/tests/tutorial/security/default.py index d88c9c71f..7fc1ea7c8 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/security/default.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/security/default.py @@ -1,6 +1,11 @@ -USERS = {'editor':'editor', - 'viewer':'viewer'} -GROUPS = {'editor':['group:editors']} +USERS = { + 'editor': 'editor', + 'viewer': 'viewer', +} + +GROUPS = { + 'editor': ['group:editors'], +} def groupfinder(userid, request): if userid in USERS: diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/404.jinja2 b/docs/tutorials/wiki2/src/tests/tutorial/templates/404.jinja2 new file mode 100644 index 000000000..1917f83c7 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/templates/404.jinja2 @@ -0,0 +1,8 @@ +{% extends "layout.jinja2" %} + +{% block content %} +
+

Pyramid Alchemy scaffold

+

404 Page Not Found

+
+{% endblock content %} diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/edit.jinja2 b/docs/tutorials/wiki2/src/tests/tutorial/templates/edit.jinja2 index c4f3a2c93..70ce49b73 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/templates/edit.jinja2 +++ b/docs/tutorials/wiki2/src/tests/tutorial/templates/edit.jinja2 @@ -33,16 +33,16 @@
- {% if logged_in %} + {% if request.authenticated_userid is not None %}

- Logout + Logout

{% endif %}

Editing {% if page.name %}{{page.name}}{% else %}Page Name Goes Here{% endif %}

You can return to the - FrontPage. + FrontPage.

diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/view.jinja2 b/docs/tutorials/wiki2/src/tests/tutorial/templates/view.jinja2 index a7afc66fc..b12ca5b0c 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/templates/view.jinja2 +++ b/docs/tutorials/wiki2/src/tests/tutorial/templates/view.jinja2 @@ -33,9 +33,9 @@
- {% if logged_in %} + {% if request.authenticated_userid is not None %}

- Logout + Logout

{% endif %}

{{ content|safe }}

@@ -48,7 +48,7 @@ Viewing {% if page.name %}{{page.name}}{% else %}Page Name Goes Here{% endif %}

You can return to the - FrontPage. + FrontPage.

diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests/__init__.py b/docs/tutorials/wiki2/src/tests/tutorial/tests/__init__.py index 8b1378917..e69de29bb 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/tests/__init__.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/tests/__init__.py @@ -1 +0,0 @@ - diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py index 339c60bc2..eda47c064 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py @@ -1,17 +1,5 @@ import unittest -from pyramid import testing - - -def dummy_request(dbsession): - return testing.DummyRequest(dbsession=dbsession) - - -def _register_routes(config): - config.add_route('view_page', '{pagename}') - config.add_route('edit_page', '{pagename}/edit_page') - config.add_route('add_page', 'add_page/{pagename}') - class FunctionalTests(unittest.TestCase): @@ -27,11 +15,8 @@ class FunctionalTests(unittest.TestCase): @staticmethod def setup_database(): import transaction - from tutorial.models.mymodel import Page - from tutorial.models.meta import ( - Base, - ) - import tutorial.models.meta + from tutorial.models import Page + from tutorial.models.meta import Base def initialize_db(dbsession, engine): @@ -40,11 +25,9 @@ class FunctionalTests(unittest.TestCase): model = Page(name='FrontPage', data='This is the front page') dbsession.add(model) - def wrap_get_session(transaction_manager, dbmaker): - dbsession = get_session(transaction_manager, dbmaker) + def wrap_get_tm_session(session_factory, transaction_manager): + dbsession = get_tm_session(session_factory, transaction_manager) initialize_db(dbsession, engine) - tutorial.models.meta.get_session = get_session - tutorial.models.meta.get_engine = get_engine return dbsession def wrap_get_engine(settings): @@ -53,10 +36,10 @@ class FunctionalTests(unittest.TestCase): return engine get_session = tutorial.models.meta.get_session - tutorial.models.meta.get_session = wrap_get_session + tutorial.models.get_tm_session = wrap_get_tm_session get_engine = tutorial.models.meta.get_engine - tutorial.models.meta.get_engine = wrap_get_engine + tutorial.models.get_engine = wrap_get_engine @classmethod def setUpClass(cls): diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py index d70311e38..81d84fa30 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py @@ -10,35 +10,29 @@ def dummy_request(dbsession): def _register_routes(config): config.add_route('view_page', '{pagename}') - config.add_route('edit_page', '{pagename}/edit_page') config.add_route('add_page', 'add_page/{pagename}') + config.add_route('edit_page', '{pagename}/edit_page') class BaseTest(unittest.TestCase): def setUp(self): + from ..models import get_tm_session self.config = testing.setUp(settings={ 'sqlalchemy.url': 'sqlite:///:memory:' }) - self.config.include('..models.meta') - _register_routes(self.config) - settings = self.config.get_settings() + self.config.include('..models') + self.config.include(_register_routes) - from ..models.meta import ( - get_session, - get_engine, - get_dbmaker, - ) - - self.engine = get_engine(settings) - dbmaker = get_dbmaker(self.engine) - - self.session = get_session(transaction.manager, dbmaker) + session_factory = self.config.registry['dbsession_factory'] + self.session = get_tm_session(session_factory, transaction.manager) self.init_database() def init_database(self): from ..models.meta import Base - Base.metadata.create_all(self.engine) + session_factory = self.config.registry['dbsession_factory'] + engine = session_factory.get_bind() + Base.metadata.create_all(engine) def tearDown(self): testing.tearDown() @@ -46,7 +40,6 @@ class BaseTest(unittest.TestCase): class ViewWikiTests(unittest.TestCase): - def setUp(self): self.config = testing.setUp() _register_routes(self.config) @@ -65,13 +58,6 @@ class ViewWikiTests(unittest.TestCase): class ViewPageTests(BaseTest): - def setUp(self): - super(ViewPageTests, self).setUp() - - def tearDown(self): - transaction.abort() - testing.tearDown() - def _callFUT(self, request): from tutorial.views.default import view_page return view_page(request) @@ -102,13 +88,6 @@ class ViewPageTests(BaseTest): class AddPageTests(BaseTest): - def setUp(self): - super(AddPageTests, self).setUp() - - def tearDown(self): - transaction.abort() - testing.tearDown() - def _callFUT(self, request): from tutorial.views.default import add_page return add_page(request) @@ -133,13 +112,6 @@ class AddPageTests(BaseTest): class EditPageTests(BaseTest): - def setUp(self): - super(EditPageTests, self).setUp() - - def tearDown(self): - transaction.abort() - testing.tearDown() - def _callFUT(self, request): from tutorial.views.default import edit_page return edit_page(request) diff --git a/docs/tutorials/wiki2/src/tests/tutorial/views/default.py b/docs/tutorials/wiki2/src/tests/tutorial/views/default.py index f35f041a4..aa77facd7 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/views/default.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/views/default.py @@ -6,31 +6,27 @@ from pyramid.httpexceptions import ( HTTPFound, HTTPNotFound, ) - from pyramid.view import ( view_config, forbidden_view_config, ) - from pyramid.security import ( remember, forget, ) +from ..models import Page from ..security.default import USERS -from ..models.mymodel import Page - # regular expression used to find WikiWords wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") -@view_config(route_name='view_wiki', - permission='view') +@view_config(route_name='view_wiki', permission='view') def view_wiki(request): - return HTTPFound(location=request.route_url('view_page', - pagename='FrontPage')) + next_url = request.route_url('view_page', pagename='FrontPage') + return HTTPFound(location=next_url) -@view_config(route_name='view_page', renderer='templates/view.jinja2', +@view_config(route_name='view_page', renderer='../templates/view.jinja2', permission='view') def view_page(request): pagename = request.matchdict['pagename'] @@ -51,10 +47,9 @@ def view_page(request): content = publish_parts(page.data, writer_name='html')['html_body'] content = wikiwords.sub(check, content) edit_url = request.route_url('edit_page', pagename=pagename) - return dict(page=page, content=content, edit_url=edit_url, - logged_in=request.authenticated_userid) + return dict(page=page, content=content, edit_url=edit_url) -@view_config(route_name='add_page', renderer='templates/edit.jinja2', +@view_config(route_name='add_page', renderer='../templates/edit.jinja2', permission='edit') def add_page(request): pagename = request.matchdict['pagename'] @@ -62,29 +57,27 @@ def add_page(request): body = request.params['body'] page = Page(name=pagename, data=body) request.dbsession.add(page) - return HTTPFound(location = request.route_url('view_page', - pagename=pagename)) + next_url = request.route_url('view_page', pagename=pagename) + return HTTPFound(location=next_url) save_url = request.route_url('add_page', pagename=pagename) page = Page(name='', data='') - return dict(page=page, save_url=save_url, - logged_in=request.authenticated_userid) + return dict(page=page, save_url=save_url) -@view_config(route_name='edit_page', renderer='templates/edit.jinja2', +@view_config(route_name='edit_page', renderer='../templates/edit.jinja2', permission='edit') def edit_page(request): pagename = request.matchdict['pagename'] page = request.dbsession.query(Page).filter_by(name=pagename).one() if 'form.submitted' in request.params: page.data = request.params['body'] - request.dbsession.add(page) - return HTTPFound(location = request.route_url('view_page', - pagename=pagename)) + next_url = request.route_url('view_page', pagename=pagename) + return HTTPFound(location=next_url) return dict( page=page, - save_url = request.route_url('edit_page', pagename=pagename), - logged_in=request.authenticated_userid + save_url=request.route_url('edit_page', pagename=pagename), ) + @view_config(route_name='login', renderer='templates/login.jinja2') @forbidden_view_config(renderer='templates/login.jinja2') def login(request): @@ -101,20 +94,19 @@ def login(request): password = request.params['password'] if USERS.get(login) == password: headers = remember(request, login) - return HTTPFound(location = came_from, - headers = headers) + return HTTPFound(location=came_from, headers=headers) message = 'Failed login' return dict( - message = message, - url = request.application_url + '/login', - came_from = came_from, - login = login, - password = password, + message=message, + url=request.route_url('login'), + came_from=came_from, + login=login, + password=password, ) @view_config(route_name='logout') def logout(request): headers = forget(request) - return HTTPFound(location = request.route_url('view_wiki'), - headers = headers) + next_url = request.route_url('view_wiki') + return HTTPFound(location=next_url, headers=headers) diff --git a/docs/tutorials/wiki2/src/tests/tutorial/views/errors.py b/docs/tutorials/wiki2/src/tests/tutorial/views/errors.py new file mode 100644 index 000000000..a4b8201f1 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/views/errors.py @@ -0,0 +1,5 @@ +from pyramid.view import notfound_view_config + +@notfound_view_config(renderer='../templates/404.jinja2') +def notfound_view(request): + return {} -- cgit v1.2.3 From d6a758e58ef1c4782ecd3fe53c8563284f2496ca Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 8 Feb 2016 22:37:22 -0600 Subject: fix tests to get the bind from dbsession_factory properly --- docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/tutorials/wiki2/src/tests') diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py index 81d84fa30..b2830d070 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py @@ -31,7 +31,7 @@ class BaseTest(unittest.TestCase): def init_database(self): from ..models.meta import Base session_factory = self.config.registry['dbsession_factory'] - engine = session_factory.get_bind() + engine = session_factory.kw['bind'] Base.metadata.create_all(engine) def tearDown(self): -- cgit v1.2.3 From 91ffccabafd2f074ac7620b5b64e52a8eb3cb31a Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 8 Feb 2016 23:00:48 -0600 Subject: fix jinja2 none test --- docs/tutorials/wiki2/src/tests/tutorial/templates/edit.jinja2 | 2 +- docs/tutorials/wiki2/src/tests/tutorial/templates/view.jinja2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'docs/tutorials/wiki2/src/tests') diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/edit.jinja2 b/docs/tutorials/wiki2/src/tests/tutorial/templates/edit.jinja2 index 70ce49b73..4d767cfbe 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/templates/edit.jinja2 +++ b/docs/tutorials/wiki2/src/tests/tutorial/templates/edit.jinja2 @@ -33,7 +33,7 @@
- {% if request.authenticated_userid is not None %} + {% if request.authenticated_userid is not none %}

Logout

diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/view.jinja2 b/docs/tutorials/wiki2/src/tests/tutorial/templates/view.jinja2 index b12ca5b0c..942b8479b 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/templates/view.jinja2 +++ b/docs/tutorials/wiki2/src/tests/tutorial/templates/view.jinja2 @@ -33,7 +33,7 @@
- {% if request.authenticated_userid is not None %} + {% if request.authenticated_userid is not none %}

Logout

-- cgit v1.2.3 From 62f0411a12a7f86bd7e3060b14f223cfb96322ad Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 8 Feb 2016 23:00:58 -0600 Subject: fix functional tests --- docs/tutorials/wiki2/src/tests/setup.py | 5 ++ .../src/tests/tutorial/tests/test_functional.py | 57 +++++++--------------- 2 files changed, 23 insertions(+), 39 deletions(-) (limited to 'docs/tutorials/wiki2/src/tests') diff --git a/docs/tutorials/wiki2/src/tests/setup.py b/docs/tutorials/wiki2/src/tests/setup.py index d4e5a4072..93195a68c 100644 --- a/docs/tutorials/wiki2/src/tests/setup.py +++ b/docs/tutorials/wiki2/src/tests/setup.py @@ -20,6 +20,10 @@ requires = [ 'docutils', ] +tests_require = [ + 'WebTest', +] + setup(name='tutorial', version='0.0', description='tutorial', @@ -39,6 +43,7 @@ setup(name='tutorial', zip_safe=False, test_suite='tutorial', install_requires=requires, + tests_require=tests_require, entry_points="""\ [paste.app_factory] main = tutorial:main diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py index eda47c064..2c08f9a64 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py @@ -1,4 +1,6 @@ +import transaction import unittest +from webtest import TestApp class FunctionalTests(unittest.TestCase): @@ -10,55 +12,32 @@ class FunctionalTests(unittest.TestCase): editor_login = '/login?login=editor&password=editor' \ '&came_from=FrontPage&form.submitted=Login' - engine = None - - @staticmethod - def setup_database(): - import transaction - from tutorial.models import Page - from tutorial.models.meta import Base - - - def initialize_db(dbsession, engine): - Base.metadata.create_all(engine) - with transaction.manager: - model = Page(name='FrontPage', data='This is the front page') - dbsession.add(model) - - def wrap_get_tm_session(session_factory, transaction_manager): - dbsession = get_tm_session(session_factory, transaction_manager) - initialize_db(dbsession, engine) - return dbsession - - def wrap_get_engine(settings): - global engine - engine = get_engine(settings) - return engine - - get_session = tutorial.models.meta.get_session - tutorial.models.get_tm_session = wrap_get_tm_session - - get_engine = tutorial.models.meta.get_engine - tutorial.models.get_engine = wrap_get_engine - @classmethod def setUpClass(cls): - cls.setup_database() - - from webtest import TestApp + from tutorial.models.meta import Base + from tutorial.models import ( + Page, + get_tm_session, + ) from tutorial import main + settings = {'sqlalchemy.url': 'sqlite://'} app = main({}, **settings) cls.testapp = TestApp(app) + session_factory = app.registry['dbsession_factory'] + cls.engine = session_factory.kw['bind'] + Base.metadata.create_all(bind=cls.engine) + + with transaction.manager: + dbsession = get_tm_session(session_factory, transaction.manager) + model = Page(name='FrontPage', data='This is the front page') + dbsession.add(model) + @classmethod def tearDownClass(cls): from tutorial.models.meta import Base - Base.metadata.drop_all(engine) - - def tearDown(self): - import transaction - transaction.abort() + Base.metadata.drop_all(bind=cls.engine) def test_root(self): res = self.testapp.get('/', status=302) -- cgit v1.2.3 From ff88c1535c65a717a030a480e39723724d53d985 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Wed, 10 Feb 2016 22:28:47 -0600 Subject: split login from forbidden --- .../wiki2/src/tests/tutorial/tests/test_functional.py | 8 ++++---- docs/tutorials/wiki2/src/tests/tutorial/views/default.py | 7 +------ docs/tutorials/wiki2/src/tests/tutorial/views/errors.py | 11 ++++++++++- 3 files changed, 15 insertions(+), 11 deletions(-) (limited to 'docs/tutorials/wiki2/src/tests') diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py index 2c08f9a64..b25d9a332 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py @@ -70,21 +70,21 @@ class FunctionalTests(unittest.TestCase): self.assertTrue(b'Logout' not in res.body) def test_anonymous_user_cannot_edit(self): - res = self.testapp.get('/FrontPage/edit_page', status=200) + res = self.testapp.get('/FrontPage/edit_page', status=302).follow() self.assertTrue(b'Login' in res.body) def test_anonymous_user_cannot_add(self): - res = self.testapp.get('/add_page/NewPage', status=200) + res = self.testapp.get('/add_page/NewPage', status=302).follow() self.assertTrue(b'Login' in res.body) def test_viewer_user_cannot_edit(self): self.testapp.get(self.viewer_login, status=302) - res = self.testapp.get('/FrontPage/edit_page', status=200) + res = self.testapp.get('/FrontPage/edit_page', status=302).follow() self.assertTrue(b'Login' in res.body) def test_viewer_user_cannot_add(self): self.testapp.get(self.viewer_login, status=302) - res = self.testapp.get('/add_page/NewPage', status=200) + res = self.testapp.get('/add_page/NewPage', status=302).follow() self.assertTrue(b'Login' in res.body) def test_editors_member_user_can_edit(self): diff --git a/docs/tutorials/wiki2/src/tests/tutorial/views/default.py b/docs/tutorials/wiki2/src/tests/tutorial/views/default.py index aa77facd7..bc8a59fe8 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/views/default.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/views/default.py @@ -6,14 +6,11 @@ from pyramid.httpexceptions import ( HTTPFound, HTTPNotFound, ) -from pyramid.view import ( - view_config, - forbidden_view_config, - ) from pyramid.security import ( remember, forget, ) +from pyramid.view import view_config from ..models import Page from ..security.default import USERS @@ -77,9 +74,7 @@ def edit_page(request): save_url=request.route_url('edit_page', pagename=pagename), ) - @view_config(route_name='login', renderer='templates/login.jinja2') -@forbidden_view_config(renderer='templates/login.jinja2') def login(request): login_url = request.route_url('login') referrer = request.url diff --git a/docs/tutorials/wiki2/src/tests/tutorial/views/errors.py b/docs/tutorials/wiki2/src/tests/tutorial/views/errors.py index a4b8201f1..f8dbe4e05 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/views/errors.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/views/errors.py @@ -1,5 +1,14 @@ -from pyramid.view import notfound_view_config +from pyramid.httpexceptions import HTTPFound +from pyramid.view import ( + forbidden_view_config, + notfound_view_config, +) @notfound_view_config(renderer='../templates/404.jinja2') def notfound_view(request): return {} + +@forbidden_view_config() +def forbidden_view(request): + next_url = request.route_url('login', _query={'came_from': request.url}) + return HTTPFound(location=next_url) -- cgit v1.2.3 From 07d38f5d4c9ebaf267d4ecaf8c0bd4c508f1848f Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Wed, 10 Feb 2016 22:38:38 -0600 Subject: several simple refactorings - move auth from default.py to auth.py - rename errors to notfound - drop basic templates (mytemplate.jinja2, layout.jinja2) --- .../src/tests/tutorial/templates/layout.jinja2 | 66 ---------------------- .../src/tests/tutorial/templates/mytemplate.jinja2 | 8 --- .../src/tests/tutorial/tests/test_functional.py | 15 +++-- .../wiki2/src/tests/tutorial/views/auth.py | 49 ++++++++++++++++ .../wiki2/src/tests/tutorial/views/default.py | 37 ------------ .../wiki2/src/tests/tutorial/views/errors.py | 14 ----- .../wiki2/src/tests/tutorial/views/notfound.py | 7 +++ 7 files changed, 65 insertions(+), 131 deletions(-) delete mode 100644 docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 delete mode 100644 docs/tutorials/wiki2/src/tests/tutorial/templates/mytemplate.jinja2 create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/views/auth.py delete mode 100644 docs/tutorials/wiki2/src/tests/tutorial/views/errors.py create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/views/notfound.py (limited to 'docs/tutorials/wiki2/src/tests') diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 deleted file mode 100644 index ff624c65b..000000000 --- a/docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - Alchemy Scaffold for The Pyramid Web Framework - - - - - - - - - - - - - -
-
-
-
- -
-
- {% block content %} -

No content

- {% endblock content %} -
-
-
- -
-
- -
-
-
- - - - - - - - diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/mytemplate.jinja2 b/docs/tutorials/wiki2/src/tests/tutorial/templates/mytemplate.jinja2 deleted file mode 100644 index bb622bf5a..000000000 --- a/docs/tutorials/wiki2/src/tests/tutorial/templates/mytemplate.jinja2 +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "layout.jinja2" %} - -{% block content %} -
-

Pyramid Alchemy scaffold

-

Welcome to {{project}}, an application generated by
the Pyramid Web Framework 1.7.dev0.

-
-{% endblock content %} diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py index b25d9a332..c716537ae 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py @@ -5,12 +5,15 @@ from webtest import TestApp class FunctionalTests(unittest.TestCase): - viewer_login = '/login?login=viewer&password=viewer' \ - '&came_from=FrontPage&form.submitted=Login' - viewer_wrong_login = '/login?login=viewer&password=incorrect' \ - '&came_from=FrontPage&form.submitted=Login' - editor_login = '/login?login=editor&password=editor' \ - '&came_from=FrontPage&form.submitted=Login' + viewer_login = ( + '/login?login=viewer&password=viewer' + '&came_from=FrontPage&form.submitted=Login') + viewer_wrong_login = ( + '/login?login=viewer&password=incorrect' + '&came_from=FrontPage&form.submitted=Login') + editor_login = ( + '/login?login=editor&password=editor' + '&came_from=FrontPage&form.submitted=Login') @classmethod def setUpClass(cls): diff --git a/docs/tutorials/wiki2/src/tests/tutorial/views/auth.py b/docs/tutorials/wiki2/src/tests/tutorial/views/auth.py new file mode 100644 index 000000000..08aa2bfad --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/views/auth.py @@ -0,0 +1,49 @@ +from pyramid.httpexceptions import HTTPFound +from pyramid.security import ( + remember, + forget, + ) +from pyramid.view import ( + forbidden_view_config, + view_config, +) + +from ..security.default import USERS + + +@view_config(route_name='login', renderer='templates/login.jinja2') +def login(request): + login_url = request.route_url('login') + referrer = request.url + if referrer == login_url: + referrer = '/' # never use the login form itself as came_from + came_from = request.params.get('came_from', referrer) + message = '' + login = '' + password = '' + if 'form.submitted' in request.params: + login = request.params['login'] + password = request.params['password'] + if USERS.get(login) == password: + headers = remember(request, login) + return HTTPFound(location=came_from, headers=headers) + message = 'Failed login' + + return dict( + message=message, + url=request.route_url('login'), + came_from=came_from, + login=login, + password=password, + ) + +@view_config(route_name='logout') +def logout(request): + headers = forget(request) + next_url = request.route_url('view_wiki') + return HTTPFound(location=next_url, headers=headers) + +@forbidden_view_config() +def forbidden_view(request): + next_url = request.route_url('login', _query={'came_from': request.url}) + return HTTPFound(location=next_url) diff --git a/docs/tutorials/wiki2/src/tests/tutorial/views/default.py b/docs/tutorials/wiki2/src/tests/tutorial/views/default.py index bc8a59fe8..6fb3c8744 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/views/default.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/views/default.py @@ -6,14 +6,9 @@ from pyramid.httpexceptions import ( HTTPFound, HTTPNotFound, ) -from pyramid.security import ( - remember, - forget, - ) from pyramid.view import view_config from ..models import Page -from ..security.default import USERS # regular expression used to find WikiWords wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") @@ -73,35 +68,3 @@ def edit_page(request): page=page, save_url=request.route_url('edit_page', pagename=pagename), ) - -@view_config(route_name='login', renderer='templates/login.jinja2') -def login(request): - login_url = request.route_url('login') - referrer = request.url - if referrer == login_url: - referrer = '/' # never use the login form itself as came_from - came_from = request.params.get('came_from', referrer) - message = '' - login = '' - password = '' - if 'form.submitted' in request.params: - login = request.params['login'] - password = request.params['password'] - if USERS.get(login) == password: - headers = remember(request, login) - return HTTPFound(location=came_from, headers=headers) - message = 'Failed login' - - return dict( - message=message, - url=request.route_url('login'), - came_from=came_from, - login=login, - password=password, - ) - -@view_config(route_name='logout') -def logout(request): - headers = forget(request) - next_url = request.route_url('view_wiki') - return HTTPFound(location=next_url, headers=headers) diff --git a/docs/tutorials/wiki2/src/tests/tutorial/views/errors.py b/docs/tutorials/wiki2/src/tests/tutorial/views/errors.py deleted file mode 100644 index f8dbe4e05..000000000 --- a/docs/tutorials/wiki2/src/tests/tutorial/views/errors.py +++ /dev/null @@ -1,14 +0,0 @@ -from pyramid.httpexceptions import HTTPFound -from pyramid.view import ( - forbidden_view_config, - notfound_view_config, -) - -@notfound_view_config(renderer='../templates/404.jinja2') -def notfound_view(request): - return {} - -@forbidden_view_config() -def forbidden_view(request): - next_url = request.route_url('login', _query={'came_from': request.url}) - return HTTPFound(location=next_url) diff --git a/docs/tutorials/wiki2/src/tests/tutorial/views/notfound.py b/docs/tutorials/wiki2/src/tests/tutorial/views/notfound.py new file mode 100644 index 000000000..69d6e2804 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/views/notfound.py @@ -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 {} -- cgit v1.2.3 From 9a7cfe3b4e248451750f5694255450bf1983e848 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Wed, 10 Feb 2016 23:54:51 -0600 Subject: update 404 templates --- docs/tutorials/wiki2/src/tests/tutorial/templates/404.jinja2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/tutorials/wiki2/src/tests') diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/404.jinja2 b/docs/tutorials/wiki2/src/tests/tutorial/templates/404.jinja2 index 1917f83c7..37b0a16b6 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/templates/404.jinja2 +++ b/docs/tutorials/wiki2/src/tests/tutorial/templates/404.jinja2 @@ -2,7 +2,7 @@ {% block content %}
-

Pyramid Alchemy scaffold

+

Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki)

404 Page Not Found

{% endblock content %} -- cgit v1.2.3 From 4872a1e713f894b383990f62cf82c2b21f810c16 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Fri, 12 Feb 2016 02:48:09 -0600 Subject: forward port changes to models / scripts to later chapters --- docs/tutorials/wiki2/src/tests/setup.py | 3 ++- .../wiki2/src/tests/tutorial/models/__init__.py | 3 ++- .../wiki2/src/tests/tutorial/models/mymodel.py | 29 ---------------------- .../wiki2/src/tests/tutorial/models/page.py | 20 +++++++++++++++ .../wiki2/src/tests/tutorial/models/user.py | 27 ++++++++++++++++++++ .../src/tests/tutorial/scripts/initializedb.py | 16 ++++++++++-- 6 files changed, 65 insertions(+), 33 deletions(-) delete mode 100644 docs/tutorials/wiki2/src/tests/tutorial/models/mymodel.py create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/models/page.py create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/models/user.py (limited to 'docs/tutorials/wiki2/src/tests') diff --git a/docs/tutorials/wiki2/src/tests/setup.py b/docs/tutorials/wiki2/src/tests/setup.py index 93195a68c..e06aa06e4 100644 --- a/docs/tutorials/wiki2/src/tests/setup.py +++ b/docs/tutorials/wiki2/src/tests/setup.py @@ -9,6 +9,8 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: CHANGES = f.read() requires = [ + 'bcrypt', + 'docutils', 'pyramid', 'pyramid_jinja2', 'pyramid_debugtoolbar', @@ -17,7 +19,6 @@ requires = [ 'transaction', 'zope.sqlalchemy', 'waitress', - 'docutils', ] tests_require = [ diff --git a/docs/tutorials/wiki2/src/tests/tutorial/models/__init__.py b/docs/tutorials/wiki2/src/tests/tutorial/models/__init__.py index 3d3efe06f..a8871f6f5 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/models/__init__.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/models/__init__.py @@ -5,7 +5,8 @@ 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 Page # flake8: noqa +from .page import Page # flake8: noqa +from .user import User # flake8: noqa # run configure_mappers after defining all of the models to ensure # all relationships can be setup diff --git a/docs/tutorials/wiki2/src/tests/tutorial/models/mymodel.py b/docs/tutorials/wiki2/src/tests/tutorial/models/mymodel.py deleted file mode 100644 index 25209c745..000000000 --- a/docs/tutorials/wiki2/src/tests/tutorial/models/mymodel.py +++ /dev/null @@ -1,29 +0,0 @@ -from pyramid.security import ( - Allow, - Everyone, -) -from sqlalchemy import ( - Column, - Integer, - Text, -) - -from .meta import Base - - -class Page(Base): - """ The SQLAlchemy declarative model class for a Page object. """ - __tablename__ = 'pages' - id = Column(Integer, primary_key=True) - name = Column(Text, unique=True) - data = Column(Integer) - - -class RootFactory(object): - __acl__ = [ - (Allow, Everyone, 'view'), - (Allow, 'group:editors', 'edit'), - ] - - def __init__(self, request): - pass diff --git a/docs/tutorials/wiki2/src/tests/tutorial/models/page.py b/docs/tutorials/wiki2/src/tests/tutorial/models/page.py new file mode 100644 index 000000000..4dd5b5721 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/models/page.py @@ -0,0 +1,20 @@ +from sqlalchemy import ( + Column, + ForeignKey, + Integer, + Text, +) +from sqlalchemy.orm import relationship + +from .meta import Base + + +class Page(Base): + """ The SQLAlchemy declarative model class for a Page object. """ + __tablename__ = 'pages' + id = Column(Integer, primary_key=True) + name = Column(Text, nullable=False, unique=True) + data = Column(Integer, nullable=False) + + creator_id = Column(ForeignKey('users.id'), nullable=False) + creator = relationship('User', backref='created_pages') diff --git a/docs/tutorials/wiki2/src/tests/tutorial/models/user.py b/docs/tutorials/wiki2/src/tests/tutorial/models/user.py new file mode 100644 index 000000000..25b0a8187 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/models/user.py @@ -0,0 +1,27 @@ +import bcrypt +from sqlalchemy import ( + Column, + Integer, + Text, +) + +from .meta import Base + + +class User(Base): + """ The SQLAlchemy declarative model class for a User object. """ + __tablename__ = 'users' + id = Column(Integer, primary_key=True) + name = Column(Text, nullable=False, unique=True) + role = Column(Text, nullable=False) + + password_hash = Column(Text) + + def set_password(self, pw): + pwhash = bcrypt.hashpw(pw, bcrypt.gensalt()) + self.password_hash = pwhash + + def check_password(self, pw): + if self.password_hash is not None: + return bcrypt.hashpw(pw, self.password_hash) == self.password_hash + return False diff --git a/docs/tutorials/wiki2/src/tests/tutorial/scripts/initializedb.py b/docs/tutorials/wiki2/src/tests/tutorial/scripts/initializedb.py index 601a6e73f..f3c0a6fef 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/scripts/initializedb.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/scripts/initializedb.py @@ -15,7 +15,7 @@ from ..models import ( get_session_factory, get_tm_session, ) -from ..models import Page +from ..models import Page, User def usage(argv): @@ -41,5 +41,17 @@ def main(argv=sys.argv): with transaction.manager: dbsession = get_tm_session(session_factory, transaction.manager) - page = Page(name='FrontPage', data='This is the front page') + editor = User(name='editor', role='editor') + editor.set_password('editor') + dbsession.add(editor) + + basic = User(name='basic', role='basic') + basic.set_password('basic') + dbsession.add(basic) + + page = Page( + name='FrontPage', + creator=editor, + data='This is the front page', + ) dbsession.add(page) -- cgit v1.2.3 From 66fabb4ac707b5b4289db0094756f1a1af7269cc Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Thu, 18 Feb 2016 02:32:08 -0600 Subject: update tests chapter --- docs/tutorials/wiki2/src/tests/development.ini | 2 + docs/tutorials/wiki2/src/tests/production.ini | 2 + docs/tutorials/wiki2/src/tests/setup.py | 2 +- .../tutorials/wiki2/src/tests/tutorial/__init__.py | 19 +--- .../wiki2/src/tests/tutorial/models/user.py | 6 +- docs/tutorials/wiki2/src/tests/tutorial/routes.py | 50 +++++++++++ .../tutorials/wiki2/src/tests/tutorial/security.py | 40 +++++++++ .../wiki2/src/tests/tutorial/security/__init__.py | 0 .../wiki2/src/tests/tutorial/security/default.py | 12 --- .../wiki2/src/tests/tutorial/templates/edit.jinja2 | 93 +++++-------------- .../src/tests/tutorial/templates/layout.jinja2 | 64 +++++++++++++ .../src/tests/tutorial/templates/login.jinja2 | 100 ++++++--------------- .../wiki2/src/tests/tutorial/templates/view.jinja2 | 89 ++++-------------- .../src/tests/tutorial/tests/test_functional.py | 56 +++++++----- .../wiki2/src/tests/tutorial/tests/test_views.py | 66 ++++++++------ .../wiki2/src/tests/tutorial/views/auth.py | 25 +++--- .../wiki2/src/tests/tutorial/views/default.py | 54 +++++------ 17 files changed, 341 insertions(+), 339 deletions(-) create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/routes.py create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/security.py delete mode 100644 docs/tutorials/wiki2/src/tests/tutorial/security/__init__.py delete mode 100644 docs/tutorials/wiki2/src/tests/tutorial/security/default.py create mode 100644 docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 (limited to 'docs/tutorials/wiki2/src/tests') diff --git a/docs/tutorials/wiki2/src/tests/development.ini b/docs/tutorials/wiki2/src/tests/development.ini index 99c4ff0fe..f3079727e 100644 --- a/docs/tutorials/wiki2/src/tests/development.ini +++ b/docs/tutorials/wiki2/src/tests/development.ini @@ -17,6 +17,8 @@ pyramid.includes = sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite +auth.secret = seekrit + # By default, the toolbar only appears for clients from IP addresses # '127.0.0.1' and '::1'. # debugtoolbar.hosts = 127.0.0.1 ::1 diff --git a/docs/tutorials/wiki2/src/tests/production.ini b/docs/tutorials/wiki2/src/tests/production.ini index cb1db3211..686dba48a 100644 --- a/docs/tutorials/wiki2/src/tests/production.ini +++ b/docs/tutorials/wiki2/src/tests/production.ini @@ -14,6 +14,8 @@ pyramid.default_locale_name = en sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite +auth.secret = real-seekrit + [server:main] use = egg:waitress#main host = 0.0.0.0 diff --git a/docs/tutorials/wiki2/src/tests/setup.py b/docs/tutorials/wiki2/src/tests/setup.py index e06aa06e4..57538f2d0 100644 --- a/docs/tutorials/wiki2/src/tests/setup.py +++ b/docs/tutorials/wiki2/src/tests/setup.py @@ -43,8 +43,8 @@ setup(name='tutorial', include_package_data=True, zip_safe=False, test_suite='tutorial', - install_requires=requires, tests_require=tests_require, + install_requires=requires, entry_points="""\ [paste.app_factory] main = tutorial:main diff --git a/docs/tutorials/wiki2/src/tests/tutorial/__init__.py b/docs/tutorials/wiki2/src/tests/tutorial/__init__.py index a62c42378..f5c033b8b 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/__init__.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/__init__.py @@ -1,28 +1,13 @@ from pyramid.config import Configurator -from pyramid.authentication import AuthTktAuthenticationPolicy -from pyramid.authorization import ACLAuthorizationPolicy - -from .security.default import groupfinder def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ - authn_policy = AuthTktAuthenticationPolicy( - 'sosecret', callback=groupfinder, hashalg='sha512') - authz_policy = ACLAuthorizationPolicy() config = Configurator(settings=settings) config.include('pyramid_jinja2') config.include('.models') - config.set_root_factory('.models.mymodel.RootFactory') - config.set_authentication_policy(authn_policy) - config.set_authorization_policy(authz_policy) - config.add_static_view('static', 'static', cache_max_age=3600) - config.add_route('view_wiki', '/') - config.add_route('login', '/login') - config.add_route('logout', '/logout') - config.add_route('view_page', '/{pagename}') - config.add_route('add_page', '/add_page/{pagename}') - config.add_route('edit_page', '/{pagename}/edit_page') + config.include('.routes') + config.include('.security') config.scan() return config.make_wsgi_app() diff --git a/docs/tutorials/wiki2/src/tests/tutorial/models/user.py b/docs/tutorials/wiki2/src/tests/tutorial/models/user.py index 25b0a8187..6fb32a1b2 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/models/user.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/models/user.py @@ -18,10 +18,12 @@ class User(Base): password_hash = Column(Text) def set_password(self, pw): - pwhash = bcrypt.hashpw(pw, bcrypt.gensalt()) + pwhash = bcrypt.hashpw(pw.encode('utf8'), bcrypt.gensalt()) self.password_hash = pwhash def check_password(self, pw): if self.password_hash is not None: - return bcrypt.hashpw(pw, self.password_hash) == self.password_hash + expected_hash = self.password_hash.encode('utf8') + actual_hash = bcrypt.hashpw(pw.encode('utf8'), expected_hash) + return expected_hash == actual_hash return False diff --git a/docs/tutorials/wiki2/src/tests/tutorial/routes.py b/docs/tutorials/wiki2/src/tests/tutorial/routes.py new file mode 100644 index 000000000..c7c3a2120 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/routes.py @@ -0,0 +1,50 @@ +from pyramid.httpexceptions import HTTPNotFound +from pyramid.security import ( + Allow, + Everyone, +) + +from .models import Page + +def includeme(config): + config.add_static_view('static', 'static', cache_max_age=3600) + config.add_route('view_wiki', '/') + config.add_route('login', '/login') + config.add_route('logout', '/logout') + config.add_route('view_page', '/{pagename}', factory=page_factory) + config.add_route('add_page', '/add_page/{pagename}', + factory=new_page_factory) + config.add_route('edit_page', '/{pagename}/edit_page', + factory=page_factory) + +def new_page_factory(request): + pagename = request.matchdict['pagename'] + return NewPage(pagename) + +class NewPage(object): + def __init__(self, pagename): + self.pagename = pagename + + def __acl__(self): + return [ + (Allow, 'role:editor', 'create'), + (Allow, 'role:basic', 'create'), + ] + +def page_factory(request): + pagename = request.matchdict['pagename'] + page = request.dbsession.query(Page).filter_by(name=pagename).first() + if page is None: + raise HTTPNotFound + return PageResource(page) + +class PageResource(object): + def __init__(self, page): + self.page = page + + def __acl__(self): + return [ + (Allow, Everyone, 'view'), + (Allow, 'role:editor', 'edit'), + (Allow, str(self.page.creator_id), 'edit'), + ] diff --git a/docs/tutorials/wiki2/src/tests/tutorial/security.py b/docs/tutorials/wiki2/src/tests/tutorial/security.py new file mode 100644 index 000000000..25cff7b05 --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/security.py @@ -0,0 +1,40 @@ +from pyramid.authentication import AuthTktAuthenticationPolicy +from pyramid.authorization import ACLAuthorizationPolicy +from pyramid.security import ( + Authenticated, + Everyone, +) + +from .models import User + + +class MyAuthenticationPolicy(AuthTktAuthenticationPolicy): + def authenticated_userid(self, request): + user = request.user + if user is not None: + return user.id + + def effective_principals(self, request): + principals = [Everyone] + user = request.user + if user is not None: + principals.append(Authenticated) + principals.append(str(user.id)) + principals.append('role:' + user.role) + return principals + +def get_user(request): + user_id = request.unauthenticated_userid + if user_id is not None: + user = request.dbsession.query(User).get(user_id) + return user + +def includeme(config): + settings = config.get_settings() + authn_policy = MyAuthenticationPolicy( + settings['auth.secret'], + hashalg='sha512', + ) + config.set_authentication_policy(authn_policy) + config.set_authorization_policy(ACLAuthorizationPolicy()) + config.add_request_method(get_user, 'user', reify=True) diff --git a/docs/tutorials/wiki2/src/tests/tutorial/security/__init__.py b/docs/tutorials/wiki2/src/tests/tutorial/security/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/docs/tutorials/wiki2/src/tests/tutorial/security/default.py b/docs/tutorials/wiki2/src/tests/tutorial/security/default.py deleted file mode 100644 index 7fc1ea7c8..000000000 --- a/docs/tutorials/wiki2/src/tests/tutorial/security/default.py +++ /dev/null @@ -1,12 +0,0 @@ -USERS = { - 'editor': 'editor', - 'viewer': 'viewer', -} - -GROUPS = { - 'editor': ['group:editors'], -} - -def groupfinder(userid, request): - if userid in USERS: - return GROUPS.get(userid, []) diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/edit.jinja2 b/docs/tutorials/wiki2/src/tests/tutorial/templates/edit.jinja2 index 4d767cfbe..7db25c674 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/templates/edit.jinja2 +++ b/docs/tutorials/wiki2/src/tests/tutorial/templates/edit.jinja2 @@ -1,73 +1,20 @@ - - - - - - - - - - - Edit{% if page.name %} {{page.name}}{% endif %} - Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki) - - - - - - - - - - - - - -
-
-
-
- -
-
-
- {% if request.authenticated_userid is not none %} -

- Logout -

- {% endif %} -

- Editing {% if page.name %}{{page.name}}{% else %}Page Name Goes Here{% endif %} -

-

You can return to the - FrontPage. -

- -
- -
-
- -
- -
-
-
-
- -
-
-
- - - - - - - - +{% extends 'layout.jinja2' %} + +{% block subtitle %}Edit {{pagename}} - {% endblock subtitle %} + +{% block content %} +

+Editing {{pagename}} +

+

You can return to the +FrontPage. +

+
+
+ +
+
+ +
+
+{% endblock content %} diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 new file mode 100644 index 000000000..44d14304e --- /dev/null +++ b/docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 @@ -0,0 +1,64 @@ + + + + + + + + + + + {% block subtitle %}{% endblock %}Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki) + + + + + + + + + + + + + +
+
+
+
+ +
+
+
+ {% if request.user is none %} +

+ Login +

+ {% else %} +

+ {{request.user.name}} Logout +

+ {% endif %} + {% block content %}{% endblock %} +
+
+
+
+ +
+
+
+ + + + + + + + diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/login.jinja2 b/docs/tutorials/wiki2/src/tests/tutorial/templates/login.jinja2 index a80a2a165..1806de0ff 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/templates/login.jinja2 +++ b/docs/tutorials/wiki2/src/tests/tutorial/templates/login.jinja2 @@ -1,74 +1,26 @@ - - - - - - - - - - - Login - Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki) - - - - - - - - - - - - - -
-
-
-
- -
-
-
-

- - Login -
- {{ message }} -

-
- -
- - -
-
- - -
-
- -
-
-
-
-
-
- -
-
-
- - - - - - - - +{% extends 'layout.jinja2' %} + +{% block title %}Login - {% endblock title %} + +{% block content %} +

+ + Login +
+{{ message }} +

+
+ +
+ + +
+
+ + +
+
+ +
+
+{% endblock content %} diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/view.jinja2 b/docs/tutorials/wiki2/src/tests/tutorial/templates/view.jinja2 index 942b8479b..94419e228 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/templates/view.jinja2 +++ b/docs/tutorials/wiki2/src/tests/tutorial/templates/view.jinja2 @@ -1,71 +1,18 @@ - - - - - - - - - - - {{page.name}} - Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki) - - - - - - - - - - - - - -
-
-
-
- -
-
-
- {% if request.authenticated_userid is not none %} -

- Logout -

- {% endif %} -

{{ content|safe }}

-

- - Edit this page - -

-

- Viewing {% if page.name %}{{page.name}}{% else %}Page Name Goes Here{% endif %} -

-

You can return to the - FrontPage. -

-
-
-
-
- -
-
-
- - - - - - - - +{% extends 'layout.jinja2' %} + +{% block subtitle %}{{page.name}} - {% endblock subtitle %} + +{% block content %} +

{{ content|safe }}

+

+ + Edit this page + +

+

+ Viewing {{page.name}}, created by {{page.creator.name}}. +

+

You can return to the +FrontPage. +

+{% endblock content %} diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py index c716537ae..b2c6e0975 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py @@ -5,26 +5,30 @@ from webtest import TestApp class FunctionalTests(unittest.TestCase): - viewer_login = ( - '/login?login=viewer&password=viewer' - '&came_from=FrontPage&form.submitted=Login') - viewer_wrong_login = ( - '/login?login=viewer&password=incorrect' - '&came_from=FrontPage&form.submitted=Login') + basic_login = ( + '/login?login=basic&password=basic' + '&next=FrontPage&form.submitted=Login') + basic_wrong_login = ( + '/login?login=basic&password=incorrect' + '&next=FrontPage&form.submitted=Login') editor_login = ( '/login?login=editor&password=editor' - '&came_from=FrontPage&form.submitted=Login') + '&next=FrontPage&form.submitted=Login') @classmethod def setUpClass(cls): from tutorial.models.meta import Base from tutorial.models import ( + User, Page, get_tm_session, ) from tutorial import main - settings = {'sqlalchemy.url': 'sqlite://'} + settings = { + 'sqlalchemy.url': 'sqlite://', + 'auth.secret': 'seekrit', + } app = main({}, **settings) cls.testapp = TestApp(app) @@ -34,8 +38,15 @@ class FunctionalTests(unittest.TestCase): with transaction.manager: dbsession = get_tm_session(session_factory, transaction.manager) - model = Page(name='FrontPage', data='This is the front page') - dbsession.add(model) + editor = User(name='editor', role='editor') + editor.set_password('editor') + basic = User(name='basic', role='basic') + basic.set_password('basic') + page1 = Page(name='FrontPage', data='This is the front page') + page1.creator = editor + page2 = Page(name='BackPage', data='This is the back page') + page2.creator = basic + dbsession.add_all([basic, editor, page1, page2]) @classmethod def tearDownClass(cls): @@ -54,20 +65,20 @@ class FunctionalTests(unittest.TestCase): self.testapp.get('/SomePage', status=404) def test_successful_log_in(self): - res = self.testapp.get(self.viewer_login, status=302) + res = self.testapp.get(self.basic_login, status=302) self.assertEqual(res.location, 'http://localhost/FrontPage') def test_failed_log_in(self): - res = self.testapp.get(self.viewer_wrong_login, status=200) + res = self.testapp.get(self.basic_wrong_login, status=200) self.assertTrue(b'login' in res.body) def test_logout_link_present_when_logged_in(self): - self.testapp.get(self.viewer_login, status=302) + self.testapp.get(self.basic_login, status=302) res = self.testapp.get('/FrontPage', status=200) self.assertTrue(b'Logout' in res.body) def test_logout_link_not_present_after_logged_out(self): - self.testapp.get(self.viewer_login, status=302) + self.testapp.get(self.basic_login, status=302) self.testapp.get('/FrontPage', status=200) res = self.testapp.get('/logout', status=302) self.assertTrue(b'Logout' not in res.body) @@ -80,15 +91,20 @@ class FunctionalTests(unittest.TestCase): res = self.testapp.get('/add_page/NewPage', status=302).follow() self.assertTrue(b'Login' in res.body) - def test_viewer_user_cannot_edit(self): - self.testapp.get(self.viewer_login, status=302) + def test_basic_user_cannot_edit_front(self): + self.testapp.get(self.basic_login, status=302) res = self.testapp.get('/FrontPage/edit_page', status=302).follow() self.assertTrue(b'Login' in res.body) - def test_viewer_user_cannot_add(self): - self.testapp.get(self.viewer_login, status=302) - res = self.testapp.get('/add_page/NewPage', status=302).follow() - self.assertTrue(b'Login' in res.body) + def test_basic_user_can_edit_back(self): + self.testapp.get(self.basic_login, status=302) + res = self.testapp.get('/BackPage/edit_page', status=200) + self.assertTrue(b'Editing' in res.body) + + def test_basic_user_can_add(self): + self.testapp.get(self.basic_login, status=302) + res = self.testapp.get('/add_page/NewPage', status=200) + self.assertTrue(b'Editing' in res.body) def test_editors_member_user_can_edit(self): self.testapp.get(self.editor_login, status=302) diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py index b2830d070..5253183df 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py @@ -8,12 +8,6 @@ def dummy_request(dbsession): return testing.DummyRequest(dbsession=dbsession) -def _register_routes(config): - config.add_route('view_page', '{pagename}') - config.add_route('add_page', 'add_page/{pagename}') - config.add_route('edit_page', '{pagename}/edit_page') - - class BaseTest(unittest.TestCase): def setUp(self): from ..models import get_tm_session @@ -21,7 +15,7 @@ class BaseTest(unittest.TestCase): 'sqlalchemy.url': 'sqlite:///:memory:' }) self.config.include('..models') - self.config.include(_register_routes) + self.config.include('..routes') session_factory = self.config.registry['dbsession_factory'] self.session = get_tm_session(session_factory, transaction.manager) @@ -38,11 +32,21 @@ class BaseTest(unittest.TestCase): testing.tearDown() transaction.abort() + def makeUser(self, name, role, password='dummy'): + from ..models import User + user = User(name=name, role=role) + user.set_password(password) + return user + + def makePage(self, name, data, creator): + from ..models import Page + return Page(name=name, data=data, creator=creator) + class ViewWikiTests(unittest.TestCase): def setUp(self): self.config = testing.setUp() - _register_routes(self.config) + self.config.include('..routes') def tearDown(self): testing.tearDown() @@ -63,14 +67,16 @@ class ViewPageTests(BaseTest): return view_page(request) def test_it(self): + from ..routes import PageResource + # add a page to the db - from ..models.mymodel import Page - page = Page(name='IDoExist', data='Hello CruelWorld IDoExist') - self.session.add(page) + user = self.makeUser('foo', 'editor') + page = self.makePage('IDoExist', 'Hello CruelWorld IDoExist', user) + self.session.add_all([page, user]) # create a request asking for the page we've created request = dummy_request(self.session) - request.matchdict['pagename'] = 'IDoExist' + request.context = PageResource(page) # call the view we're testing and check its behavior info = self._callFUT(request) @@ -93,19 +99,23 @@ class AddPageTests(BaseTest): return add_page(request) def test_it_notsubmitted(self): + from ..routes import NewPage request = dummy_request(self.session) - request.matchdict = {'pagename': 'AnotherPage'} + request.user = self.makeUser('foo', 'editor') + request.context = NewPage('AnotherPage') info = self._callFUT(request) - self.assertEqual(info['page'].data, '') + self.assertEqual(info['pagedata'], '') self.assertEqual(info['save_url'], 'http://example.com/add_page/AnotherPage') def test_it_submitted(self): - from ..models.mymodel import Page + from ..models import Page + from ..routes import NewPage request = testing.DummyRequest({'form.submitted': True, 'body': 'Hello yo!'}, dbsession=self.session) - request.matchdict = {'pagename': 'AnotherPage'} + request.user = self.makeUser('foo', 'editor') + request.context = NewPage('AnotherPage') self._callFUT(request) page = self.session.query(Page).filter_by(name='AnotherPage').one() self.assertEqual(page.data, 'Hello yo!') @@ -116,25 +126,31 @@ class EditPageTests(BaseTest): from tutorial.views.default import edit_page return edit_page(request) + def makeContext(self, page): + from ..routes import PageResource + return PageResource(page) + def test_it_notsubmitted(self): - from ..models.mymodel import Page + user = self.makeUser('foo', 'editor') + page = self.makePage('abc', 'hello', user) + self.session.add_all([page, user]) + request = dummy_request(self.session) - request.matchdict = {'pagename': 'abc'} - page = Page(name='abc', data='hello') - self.session.add(page) + request.context = self.makeContext(page) info = self._callFUT(request) - self.assertEqual(info['page'], page) + self.assertEqual(info['pagename'], 'abc') self.assertEqual(info['save_url'], 'http://example.com/abc/edit_page') def test_it_submitted(self): - from ..models.mymodel import Page + user = self.makeUser('foo', 'editor') + page = self.makePage('abc', 'hello', user) + self.session.add_all([page, user]) + request = testing.DummyRequest({'form.submitted': True, 'body': 'Hello yo!'}, dbsession=self.session) - request.matchdict = {'pagename': 'abc'} - page = Page(name='abc', data='hello') - self.session.add(page) + request.context = self.makeContext(page) response = self._callFUT(request) self.assertEqual(response.location, 'http://example.com/abc') self.assertEqual(page.data, 'Hello yo!') diff --git a/docs/tutorials/wiki2/src/tests/tutorial/views/auth.py b/docs/tutorials/wiki2/src/tests/tutorial/views/auth.py index 08aa2bfad..2b993b430 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/views/auth.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/views/auth.py @@ -8,33 +8,30 @@ from pyramid.view import ( view_config, ) -from ..security.default import USERS +from ..models import User -@view_config(route_name='login', renderer='templates/login.jinja2') +@view_config(route_name='login', renderer='../templates/login.jinja2') def login(request): - login_url = request.route_url('login') - referrer = request.url - if referrer == login_url: - referrer = '/' # never use the login form itself as came_from - came_from = request.params.get('came_from', referrer) + next_url = request.params.get('next', request.referrer) + if not next_url: + next_url = request.route_url('view_wiki') message = '' login = '' - password = '' if 'form.submitted' in request.params: login = request.params['login'] password = request.params['password'] - if USERS.get(login) == password: - headers = remember(request, login) - return HTTPFound(location=came_from, headers=headers) + user = request.dbsession.query(User).filter_by(name=login).first() + if user is not None and user.check_password(password): + headers = remember(request, user.id) + return HTTPFound(location=next_url, headers=headers) message = 'Failed login' return dict( message=message, url=request.route_url('login'), - came_from=came_from, + next_url=next_url, login=login, - password=password, ) @view_config(route_name='logout') @@ -45,5 +42,5 @@ def logout(request): @forbidden_view_config() def forbidden_view(request): - next_url = request.route_url('login', _query={'came_from': request.url}) + next_url = request.route_url('login', _query={'next': request.url}) return HTTPFound(location=next_url) diff --git a/docs/tutorials/wiki2/src/tests/tutorial/views/default.py b/docs/tutorials/wiki2/src/tests/tutorial/views/default.py index 6fb3c8744..9358993ea 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/views/default.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/views/default.py @@ -2,10 +2,7 @@ import cgi import re from docutils.core import publish_parts -from pyramid.httpexceptions import ( - HTTPFound, - HTTPNotFound, - ) +from pyramid.httpexceptions import HTTPFound from pyramid.view import view_config from ..models import Page @@ -13,7 +10,7 @@ from ..models import Page # regular expression used to find WikiWords wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") -@view_config(route_name='view_wiki', permission='view') +@view_config(route_name='view_wiki') def view_wiki(request): next_url = request.route_url('view_page', pagename='FrontPage') return HTTPFound(location=next_url) @@ -21,12 +18,9 @@ def view_wiki(request): @view_config(route_name='view_page', renderer='../templates/view.jinja2', permission='view') def view_page(request): - pagename = request.matchdict['pagename'] - page = request.dbsession.query(Page).filter_by(name=pagename).first() - if page is None: - return HTTPNotFound('No such page') + page = request.context.page - def check(match): + def add_link(match): word = match.group(1) exists = request.dbsession.query(Page).filter_by(name=word).all() if exists: @@ -37,34 +31,34 @@ def view_page(request): return '%s' % (add_url, cgi.escape(word)) content = publish_parts(page.data, writer_name='html')['html_body'] - content = wikiwords.sub(check, content) - edit_url = request.route_url('edit_page', pagename=pagename) + content = wikiwords.sub(add_link, content) + edit_url = request.route_url('edit_page', pagename=page.name) return dict(page=page, content=content, edit_url=edit_url) -@view_config(route_name='add_page', renderer='../templates/edit.jinja2', +@view_config(route_name='edit_page', renderer='../templates/edit.jinja2', permission='edit') +def edit_page(request): + page = request.context.page + if 'form.submitted' in request.params: + page.data = request.params['body'] + next_url = request.route_url('view_page', pagename=page.name) + return HTTPFound(location=next_url) + return dict( + pagename=page.name, + pagedata=page.data, + save_url=request.route_url('edit_page', pagename=page.name), + ) + +@view_config(route_name='add_page', renderer='../templates/edit.jinja2', + permission='create') def add_page(request): - pagename = request.matchdict['pagename'] + pagename = request.context.pagename if 'form.submitted' in request.params: body = request.params['body'] page = Page(name=pagename, data=body) + page.creator = request.user request.dbsession.add(page) next_url = request.route_url('view_page', pagename=pagename) return HTTPFound(location=next_url) save_url = request.route_url('add_page', pagename=pagename) - page = Page(name='', data='') - return dict(page=page, save_url=save_url) - -@view_config(route_name='edit_page', renderer='../templates/edit.jinja2', - permission='edit') -def edit_page(request): - pagename = request.matchdict['pagename'] - page = request.dbsession.query(Page).filter_by(name=pagename).one() - if 'form.submitted' in request.params: - page.data = request.params['body'] - next_url = request.route_url('view_page', pagename=pagename) - return HTTPFound(location=next_url) - return dict( - page=page, - save_url=request.route_url('edit_page', pagename=pagename), - ) + return dict(pagename=pagename, pagedata='', save_url=save_url) -- cgit v1.2.3 From a26a08b92f390aeaa3eb0c39241bb5e76f5a72ea Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 28 Feb 2016 01:29:55 -0800 Subject: apply change to all src/*/user.py --- docs/tutorials/wiki2/src/tests/tutorial/models/user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/tutorials/wiki2/src/tests') diff --git a/docs/tutorials/wiki2/src/tests/tutorial/models/user.py b/docs/tutorials/wiki2/src/tests/tutorial/models/user.py index 6fb32a1b2..6bd3315d6 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/models/user.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/models/user.py @@ -23,7 +23,7 @@ class User(Base): def check_password(self, pw): if self.password_hash is not None: - expected_hash = self.password_hash.encode('utf8') + expected_hash = self.password_hash actual_hash = bcrypt.hashpw(pw.encode('utf8'), expected_hash) return expected_hash == actual_hash return False -- cgit v1.2.3 From 3e30040da7c2d5c38b330727b48d9f6b852956d9 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 28 Feb 2016 22:30:22 -0800 Subject: redirect to edit page when user attempts to add page that already exists - update src/*/views/default.py - update src/*/routes.py - write new test - revise docs, double-checking line counts and highlighting --- docs/tutorials/wiki2/src/tests/tutorial/routes.py | 8 +++++++- docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py | 12 ++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'docs/tutorials/wiki2/src/tests') diff --git a/docs/tutorials/wiki2/src/tests/tutorial/routes.py b/docs/tutorials/wiki2/src/tests/tutorial/routes.py index c7c3a2120..f0a8b7f96 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/routes.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/routes.py @@ -1,4 +1,7 @@ -from pyramid.httpexceptions import HTTPNotFound +from pyramid.httpexceptions import ( + HTTPNotFound, + HTTPFound, +) from pyramid.security import ( Allow, Everyone, @@ -19,6 +22,9 @@ def includeme(config): def new_page_factory(request): pagename = request.matchdict['pagename'] + if request.dbsession.query(Page).filter_by(name=pagename).count() > 0: + next_url = request.route_url('edit_page', pagename=pagename) + raise HTTPFound(location=next_url) return NewPage(pagename) class NewPage(object): diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py index 5253183df..2c945ab33 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py @@ -98,6 +98,18 @@ class AddPageTests(BaseTest): from tutorial.views.default import add_page return add_page(request) + def test_it_pageexists(self): + from ..models import Page + from ..routes import NewPage + request = testing.DummyRequest({'form.submitted': True, + 'body': 'Hello yo!'}, + dbsession=self.session) + request.user = self.makeUser('foo', 'editor') + request.context = NewPage('AnotherPage') + self._callFUT(request) + pagecount = self.session.query(Page).filter_by(name='AnotherPage').count() + self.assertGreater(pagecount, 0) + def test_it_notsubmitted(self): from ..routes import NewPage request = dummy_request(self.session) -- cgit v1.2.3 From e35dcbcd9388d79f3850e9ff8faf76ba14467a10 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 9 Apr 2016 14:46:41 -0700 Subject: - update wiki2/tests step --- docs/tutorials/wiki2/src/tests/development.ini | 4 ++-- docs/tutorials/wiki2/src/tests/production.ini | 4 ++-- docs/tutorials/wiki2/src/tests/setup.py | 23 +++++++++++++---------- 3 files changed, 17 insertions(+), 14 deletions(-) (limited to 'docs/tutorials/wiki2/src/tests') diff --git a/docs/tutorials/wiki2/src/tests/development.ini b/docs/tutorials/wiki2/src/tests/development.ini index f3079727e..4a6c9325c 100644 --- a/docs/tutorials/wiki2/src/tests/development.ini +++ b/docs/tutorials/wiki2/src/tests/development.ini @@ -1,6 +1,6 @@ ### # app configuration -# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html +# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html ### [app:main] @@ -34,7 +34,7 @@ port = 6543 ### # logging configuration -# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html +# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html ### [loggers] diff --git a/docs/tutorials/wiki2/src/tests/production.ini b/docs/tutorials/wiki2/src/tests/production.ini index 686dba48a..a13a0ca19 100644 --- a/docs/tutorials/wiki2/src/tests/production.ini +++ b/docs/tutorials/wiki2/src/tests/production.ini @@ -1,6 +1,6 @@ ### # app configuration -# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html +# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html ### [app:main] @@ -23,7 +23,7 @@ port = 6543 ### # logging configuration -# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html +# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html ### [loggers] diff --git a/docs/tutorials/wiki2/src/tests/setup.py b/docs/tutorials/wiki2/src/tests/setup.py index 57538f2d0..8dca906c8 100644 --- a/docs/tutorials/wiki2/src/tests/setup.py +++ b/docs/tutorials/wiki2/src/tests/setup.py @@ -21,20 +21,22 @@ requires = [ 'waitress', ] -tests_require = [ - 'WebTest', -] +testing_extras = [ + 'WebTest >= 1.3.1', # py3 compat + 'pytest', # includes virtualenv + 'pytest-cov', + ] setup(name='tutorial', version='0.0', description='tutorial', long_description=README + '\n\n' + CHANGES, classifiers=[ - "Programming Language :: Python", - "Framework :: Pyramid", - "Topic :: Internet :: WWW/HTTP", - "Topic :: Internet :: WWW/HTTP :: WSGI :: Application", - ], + "Programming Language :: Python", + "Framework :: Pyramid", + "Topic :: Internet :: WWW/HTTP", + "Topic :: Internet :: WWW/HTTP :: WSGI :: Application", + ], author='', author_email='', url='', @@ -42,8 +44,9 @@ setup(name='tutorial', packages=find_packages(), include_package_data=True, zip_safe=False, - test_suite='tutorial', - tests_require=tests_require, + extras_require={ + 'testing': testing_extras, + }, install_requires=requires, entry_points="""\ [paste.app_factory] -- cgit v1.2.3 From b59e75fd9fd3a6f1a552ee13bbb734aa9ef65f6c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 9 Apr 2016 20:23:30 -0700 Subject: use an alias for the import. Fixes #2450. Thanks @bertjwregeer! --- docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs/tutorials/wiki2/src/tests') diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py index b2c6e0975..77bfd2f17 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py @@ -1,6 +1,6 @@ import transaction import unittest -from webtest import TestApp +from webtest import TestApp as WebtestApp class FunctionalTests(unittest.TestCase): @@ -30,7 +30,7 @@ class FunctionalTests(unittest.TestCase): 'auth.secret': 'seekrit', } app = main({}, **settings) - cls.testapp = TestApp(app) + cls.testapp = WebtestApp(app) session_factory = app.registry['dbsession_factory'] cls.engine = session_factory.kw['bind'] -- cgit v1.2.3 From a9e55f269891d3deed86bbe0f5397f6ff198781a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 11 Apr 2016 00:27:11 -0700 Subject: tweak wiki2 test to be more succinct --- docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs/tutorials/wiki2/src/tests') diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py index 77bfd2f17..715768b2e 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py @@ -1,6 +1,6 @@ import transaction import unittest -from webtest import TestApp as WebtestApp +import webtest class FunctionalTests(unittest.TestCase): @@ -30,7 +30,7 @@ class FunctionalTests(unittest.TestCase): 'auth.secret': 'seekrit', } app = main({}, **settings) - cls.testapp = WebtestApp(app) + cls.testapp = webtest.TestApp(app) session_factory = app.registry['dbsession_factory'] cls.engine = session_factory.kw['bind'] -- cgit v1.2.3 From f9a67aa2f725d9375fb00321b67c2bfa211b4cff Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 11 Apr 2016 21:26:24 -0500 Subject: fix readme to show directions in both alchemy and zodb --- docs/tutorials/wiki2/src/tests/README.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/tutorials/wiki2/src/tests') diff --git a/docs/tutorials/wiki2/src/tests/README.txt b/docs/tutorials/wiki2/src/tests/README.txt index 68f430110..5b0101e5f 100644 --- a/docs/tutorials/wiki2/src/tests/README.txt +++ b/docs/tutorials/wiki2/src/tests/README.txt @@ -6,7 +6,7 @@ Getting Started - cd -- $VENV/bin/python setup.py develop +- $VENV/bin/pip install -e . - $VENV/bin/initialize_tutorial_db development.ini -- cgit v1.2.3 From db3aa086a25504f8faf0149875eb7ff73ef08352 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 11 Apr 2016 21:26:46 -0500 Subject: remove theme.min.css, it serves no purpose --- docs/tutorials/wiki2/src/tests/tutorial/static/theme.min.css | 1 - 1 file changed, 1 deletion(-) delete mode 100644 docs/tutorials/wiki2/src/tests/tutorial/static/theme.min.css (limited to 'docs/tutorials/wiki2/src/tests') diff --git a/docs/tutorials/wiki2/src/tests/tutorial/static/theme.min.css b/docs/tutorials/wiki2/src/tests/tutorial/static/theme.min.css deleted file mode 100644 index 0d25de5b6..000000000 --- a/docs/tutorials/wiki2/src/tests/tutorial/static/theme.min.css +++ /dev/null @@ -1 +0,0 @@ -@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}} -- cgit v1.2.3 From ebbe68144ad6a6022863aa4a29f5611fde02258f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 12 Apr 2016 04:52:20 -0700 Subject: - use an environment variable and venv. See https://github.com/Pylons/pyramid/pull/2468#discussion_r59311019 - rename stanza from `testing_extras` to `tests_require` - switch from nose to pytest --- docs/tutorials/wiki2/src/tests/setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs/tutorials/wiki2/src/tests') diff --git a/docs/tutorials/wiki2/src/tests/setup.py b/docs/tutorials/wiki2/src/tests/setup.py index 8dca906c8..def3ce1f6 100644 --- a/docs/tutorials/wiki2/src/tests/setup.py +++ b/docs/tutorials/wiki2/src/tests/setup.py @@ -21,7 +21,7 @@ requires = [ 'waitress', ] -testing_extras = [ +tests_require = [ 'WebTest >= 1.3.1', # py3 compat 'pytest', # includes virtualenv 'pytest-cov', @@ -45,7 +45,7 @@ setup(name='tutorial', include_package_data=True, zip_safe=False, extras_require={ - 'testing': testing_extras, + 'testing': tests_require, }, install_requires=requires, entry_points="""\ -- cgit v1.2.3