Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quickstart switch to pytest instead of nose #20

Open
wants to merge 3 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ TGTest-*
devtools/tests/data/
dist/
build/
\#*\#
.\#*
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ python:
- "3.6"
- "3.7"
- "3.8"
- "3.9-dev"

install:
- "pip install --upgrade setuptools"
Expand Down
11 changes: 11 additions & 0 deletions devtools/gearbox/quickstart/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,3 +276,14 @@ def overwrite_templates(template_type):
# remove existing migrations directory
package_migrations_dir = os.path.abspath('migration')
shutil.rmtree(package_migrations_dir, ignore_errors=True)

tests_dir = os.path.abspath(os.path.join(opts.package, 'tests'))
if not opts.database:
print('database support disabled, stripping away model tests')
os.remove(os.path.abspath(tests_dir + '/_conftest/models.py'))
shutil.rmtree(os.path.abspath(tests_dir + '/models'))
if not opts.auth:
print('auth disabled, removing relative tests')
os.remove(os.path.abspath(tests_dir + '/functional/test_authentication.py'))
if opts.database:
os.remove(os.path.abspath(tests_dir + '/models/test_auth.py'))
19 changes: 19 additions & 0 deletions devtools/gearbox/quickstart/template/+dot+coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# refer to https://coverage.readthedocs.io/en/latest/config.html
[run]
source = {{package}}

[report]
show_missing = True

# if you don't omit tests directory you have more chances of seeing two tests with same name
omit =
setup.py
migration/*
# tests/*

# fail test suite if coverage drops below 100% (if you uncomment it)
# this does not work for nosetests, set it in setup.cfg (min-cover-percentage)
# fail_under = 100

# Don’t include files in the report that are 100% covered files
skip_covered = True
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ from tg import FullStackApplicationConfigurator
import {{package}}
from {{package}} import model, lib

{{if auth}}
from tg.exceptions import HTTPFound
try:
from urllib.parse import parse_qs, urlencode
except ImportError: # pragma: no cover # py2.7 compatibility
from urlparse import parse_qs
from urllib import urlencode
{{endif}}


base_config = FullStackApplicationConfigurator()

# General configuration
Expand Down Expand Up @@ -115,13 +125,6 @@ class ApplicationAuthMetadata(TGAuthMetadata):
login = None

if login is None:
try:
from urllib.parse import parse_qs, urlencode
except ImportError:
from urlparse import parse_qs
from urllib import urlencode
from tg.exceptions import HTTPFound

params = parse_qs(environ['QUERY_STRING'])
params.pop('password', None) # Remove password in case it was there
if user is None:
Expand Down Expand Up @@ -162,13 +165,6 @@ class ApplicationAuthMetadata(TGAuthMetadata):
login = None

if login is None:
try:
from urllib.parse import parse_qs, urlencode
except ImportError:
from urlparse import parse_qs
from urllib import urlencode
from tg.exceptions import HTTPFound

params = parse_qs(environ['QUERY_STRING'])
params.pop('password', None) # Remove password in case it was there
if user is None:
Expand Down Expand Up @@ -235,7 +231,7 @@ try:
# Enable DebugBar if available, install tgext.debugbar to turn it on
from tgext.debugbar import enable_debugbar
enable_debugbar(base_config)
except ImportError:
except ImportError: # pragma: no cover
pass
{{endif}}

Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,4 @@ def icon(icon_name):
# Import commonly used helpers from WebHelpers2 and TG
from tg.util.html import script_json_encode

try:
from webhelpers2 import date, html, number, misc, text
except SyntaxError:
log.error("WebHelpers2 helpers not available with this Python Version")
from webhelpers2 import date, html, number, misc, text
16 changes: 12 additions & 4 deletions devtools/gearbox/quickstart/template/+package+/model/auth.py_tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class Group(DeclarativeBase):
def __repr__(self):
return '<Group: name=%s>' % repr(self.group_name)

def __unicode__(self):
def __str__(self):
return self.group_name


Expand Down Expand Up @@ -102,15 +102,15 @@ class User(DeclarativeBase):
repr(self.display_name)
)

def __unicode__(self):
def __str__(self):
return self.display_name or self.user_name

@property
def permissions(self):
"""Return a set with all permissions granted to the user."""
perms = set()
for g in self.groups:
perms = perms | set(g.permissions)
perms.update(g.permissions)
return perms

@classmethod
Expand Down Expand Up @@ -192,7 +192,7 @@ class Permission(DeclarativeBase):
def __repr__(self):
return '<Permission: name=%s>' % repr(self.permission_name)

def __unicode__(self):
def __str__(self):
return self.permission_name

{{elif auth == 'ming'}}
Expand Down Expand Up @@ -292,6 +292,11 @@ class User(MappedClass):
def permissions(self):
return Permission.query.find(dict(_groups={'$in':self._groups})).all()

@classmethod
def by_user_name(cls, user_name):
"""Return the user object whose user name is ``user_name``."""
return cls.query.get(user_name=user_name)

@classmethod
def by_email_address(cls, email):
"""Return the user object whose email address is ``email``."""
Expand All @@ -313,4 +318,7 @@ class User(MappedClass):
hash.update((password + self.password[:64]).encode('utf-8'))
return self.password[64:] == hash.hexdigest()

def __eq__(self, other):
return self._id == other._id

{{endif}}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import pytest
from webtest import TestApp as WebTestApp # rename due to pytest warning
from paste.deploy import loadapp, appconfig
from tg import config
from {{package}} import websetup
{{if database}}from {{package}} import model{{endif}}
from os import getcwd
{{if sqlalchemy}}import transaction{{endif}}


{{if database}}
def teardown_db():
{{if sqlalchemy}}
model.DBSession.remove()
engine = config['tg.app_globals'].sa_engine
model.metadata.drop_all(engine)
transaction.abort()
{{elif ming}}
datastore = config['tg.app_globals'].ming_datastore
model.DBSession.clear() # before dropping flush is performed
try:
# On MIM drop all data
datastore.conn.drop_all()
except TypeError: # pragma: no cover
# On MongoDB drop database
datastore.conn.drop_database(datastore.db)
{{endif}}
{{endif}}


@pytest.fixture(scope='function')
def _app():
"""This fixture allows you to reconfigure the application configuration.
Also, you can omit setup_app command"""
def __app(name='main_without_authn', reconfig=None, setup_app=True):
paste_config = 'config:test.ini#%s' % name
app = WebTestApp(loadapp(
paste_config,
relative_to=getcwd(),
global_conf=reconfig or {},
))
if setup_app:
_config = appconfig(paste_config, relative_to=getcwd(), global_conf=reconfig or {})
websetup.setup_app(None, _config, {})
return app
yield __app
{{if database}}teardown_db(){{endif}}


@pytest.fixture(scope='function')
def app(_app):
"""This fixture is the default application"""
return _app()


{{if auth}}
@pytest.fixture()
def env():
"""this is just a shorthand intended to be passed to extra_environ in webtest calls,
remote_user got as parameter will go into REMOTE_USER key,
other kwarguments are included in the returned dictionary"""
def _environ(remote_user, **kwargs):
r = {'REMOTE_USER': remote_user} if remote_user else {}
r.update(kwargs)
return r
return _environ
CastixGitHub marked this conversation as resolved.
Show resolved Hide resolved
{{endif}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import pytest
from {{package}}.model import DBSession
from {{package}}.tests._conftest.app import teardown_db


@pytest.fixture()
def obj():
def _obj(klass, attrs):
new_attrs = {}
new_attrs.update(attrs)
created = klass(**new_attrs)
{{if sqlalchemy}}
DBSession.add(created)
DBSession.flush()
{{elif ming}}
created.__mongometa__.session.flush()
created.__mongometa__.session.clear()
{{endif}}
return created
yield _obj
teardown_db()
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{{if database}}from {{package}}.tests._conftest.models import obj{{endif}}
from {{package}}.tests._conftest.app import app, _app{{if auth}}, env{{endif}}

# Fixtures defined in _conftest came from turbogears2, change them if you wish

# Place here your own fixtures.

This file was deleted.

Loading