Add wutta wrapper for AppProvider
This commit is contained in:
parent
20cd12d682
commit
a073be3529
|
@ -41,7 +41,7 @@ from functools import partial
|
|||
import humanize
|
||||
from mako.template import Template
|
||||
|
||||
from wuttjamaican.app import AppHandler as WuttaAppHandler
|
||||
from wuttjamaican.app import AppHandler as WuttaAppHandler, AppProvider as WuttaAppProvider
|
||||
from wuttjamaican.util import parse_bool
|
||||
|
||||
from rattail.util import (load_object, load_entry_points,
|
||||
|
@ -113,28 +113,6 @@ class AppHandler(WuttaAppHandler):
|
|||
"""
|
||||
return self.config.get_model()
|
||||
|
||||
def get_all_providers(self):
|
||||
"""
|
||||
Returns a dict of all registered providers.
|
||||
"""
|
||||
providers = load_entry_points('rattail.providers')
|
||||
for key in list(providers):
|
||||
providers[key] = providers[key](self)
|
||||
return providers
|
||||
|
||||
def __getattr__(self, name):
|
||||
|
||||
if name == 'providers':
|
||||
self.providers = self.get_all_providers()
|
||||
return self.providers
|
||||
|
||||
if 'providers' not in self.__dict__:
|
||||
self.__dict__['providers'] = self.get_all_providers()
|
||||
|
||||
for provider in self.providers.values():
|
||||
if hasattr(provider, name):
|
||||
return getattr(provider, name)
|
||||
|
||||
def get_title(self, default='Rattail'):
|
||||
"""
|
||||
Returns the configured title (name) of the app.
|
||||
|
@ -2286,33 +2264,42 @@ class MergeMixin(object):
|
|||
setattr(keeping, field['name'], removing_value)
|
||||
|
||||
|
||||
class RattailProvider:
|
||||
class RattailProvider(WuttaAppProvider):
|
||||
"""
|
||||
Base class for Rattail providers. These can add arbitrary extra
|
||||
functionality to the main AppHandler.
|
||||
Base class for Rattail app providers.
|
||||
|
||||
This inherits from upstream
|
||||
:class:`~wuttjamaican:wuttjamaican.app.AppProvider` and adds the
|
||||
following to it:
|
||||
|
||||
.. attribute:: enum
|
||||
|
||||
Reference to the ``enum`` module for the app.
|
||||
|
||||
.. attribute:: model
|
||||
|
||||
Reference to the ``model`` module for the app.
|
||||
|
||||
.. attribute:: handlers
|
||||
|
||||
Dictionary of "secondary" handlers used by the provider, if
|
||||
applicable.
|
||||
"""
|
||||
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
self.config = app.config
|
||||
self.model = app.model
|
||||
self.enum = app.enum
|
||||
def __init__(self, config):
|
||||
super().__init__(config)
|
||||
self.enum = self.app.enum
|
||||
self.model = self.app.model
|
||||
self.handlers = {}
|
||||
|
||||
def load_object(self, *args, **kwargs):
|
||||
"""
|
||||
Convenience method which calls
|
||||
:meth:`AppHandler.load_object()`.
|
||||
"""
|
||||
return self.app.load_object(*args, **kwargs)
|
||||
|
||||
|
||||
def get_all_providers(config):
|
||||
"""
|
||||
Returns a dict of all registered providers.
|
||||
"""
|
||||
providers = load_entry_points('rattail.providers')
|
||||
for key in list(providers):
|
||||
providers[key] = providers[key](config)
|
||||
return providers
|
||||
|
||||
|
||||
def make_app(config, **kwargs): # pragma: no cover
|
||||
warnings.warn("function is deprecated, please use "
|
||||
"RattailConfig.get_app() method instead",
|
||||
|
|
|
@ -40,9 +40,9 @@ from getpass import getpass
|
|||
|
||||
import humanize
|
||||
|
||||
from wuttjamaican.commands.base import (Command as WuttaCommand,
|
||||
CommandArgumentParser,
|
||||
Subcommand as WuttaSubcommand)
|
||||
from wuttjamaican.cmd.base import (Command as WuttaCommand,
|
||||
CommandArgumentParser,
|
||||
Subcommand as WuttaSubcommand)
|
||||
from wuttjamaican.util import parse_list
|
||||
|
||||
from rattail import __version__
|
||||
|
|
|
@ -50,7 +50,7 @@ install_requires =
|
|||
requests
|
||||
six
|
||||
texttable
|
||||
WuttJamaican>=0.1.7
|
||||
WuttJamaican>=0.1.8
|
||||
xlrd
|
||||
|
||||
# TODO: revisit this, comment seems dubious
|
||||
|
|
|
@ -26,16 +26,9 @@ from rattail.gpc import GPC
|
|||
class TestAppHandler(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.config = self.make_config()
|
||||
# TODO: rename handler to app?
|
||||
self.handler = self.make_handler()
|
||||
self.app = self.handler
|
||||
|
||||
def make_config(self):
|
||||
return make_config([], extend=False)
|
||||
|
||||
def make_handler(self):
|
||||
return mod.AppHandler(self.config)
|
||||
self.config = make_config([], extend=False)
|
||||
self.app = mod.AppHandler(self.config)
|
||||
self.config.app = self.app
|
||||
|
||||
def test_get_setting(self):
|
||||
Session = orm.sessionmaker()
|
||||
|
@ -66,15 +59,15 @@ class TestAppHandler(TestCase):
|
|||
def test_get_title(self):
|
||||
|
||||
# default for unconfigured title
|
||||
self.assertEqual(self.handler.get_title(), "Rattail")
|
||||
self.assertEqual(self.app.get_title(), "Rattail")
|
||||
|
||||
# unless default is provided
|
||||
self.assertEqual(self.handler.get_title(default="Foo"), "Foo")
|
||||
self.assertEqual(self.app.get_title(default="Foo"), "Foo")
|
||||
|
||||
# or title can be configured
|
||||
self.config.setdefault('rattail', 'app_title', 'Bar')
|
||||
self.assertEqual(self.handler.get_title(), "Bar")
|
||||
self.assertEqual(self.handler.get_title(default="Foo"), "Bar")
|
||||
self.assertEqual(self.app.get_title(), "Bar")
|
||||
self.assertEqual(self.app.get_title(default="Foo"), "Bar")
|
||||
|
||||
def test_make_engine_from_config_record_changes(self):
|
||||
|
||||
|
@ -106,36 +99,19 @@ class TestAppHandler(TestCase):
|
|||
})
|
||||
self.assertTrue(engine.rattail_log_pool_status)
|
||||
|
||||
def test_getattr_providers(self):
|
||||
|
||||
# collection of providers is loaded on demand
|
||||
self.assertNotIn('providers', self.app.__dict__)
|
||||
self.assertIsNotNone(self.app.providers)
|
||||
|
||||
# and then providers can supply other attributes
|
||||
self.app.providers['mytest'] = MagicMock(foo_value='bar')
|
||||
self.assertEqual(self.app.foo_value, 'bar')
|
||||
|
||||
def test_getattr_other(self):
|
||||
|
||||
# attributes are loaded on demand, simply null by default
|
||||
self.assertNotIn('nuttin_honey', self.app.__dict__)
|
||||
# nb. this will force a lookup via the providers
|
||||
self.assertIsNone(self.app.nuttin_honey)
|
||||
|
||||
def test_get_timezone(self):
|
||||
|
||||
# unconfigured zone causes error
|
||||
self.assertRaises(ConfigurationError, self.handler.get_timezone)
|
||||
self.assertRaises(ConfigurationError, self.app.get_timezone)
|
||||
|
||||
# or one can be configured
|
||||
self.config.setdefault('rattail', 'timezone.default', 'America/Chicago')
|
||||
self.assertEqual(str(self.handler.get_timezone()), 'America/Chicago')
|
||||
self.assertEqual(str(self.app.get_timezone()), 'America/Chicago')
|
||||
|
||||
# also can configure alternate zones
|
||||
self.assertRaises(ConfigurationError, self.handler.get_timezone, key='other')
|
||||
self.assertRaises(ConfigurationError, self.app.get_timezone, key='other')
|
||||
self.config.setdefault('rattail', 'timezone.other', 'America/New_York')
|
||||
self.assertEqual(str(self.handler.get_timezone(key='other')), 'America/New_York')
|
||||
self.assertEqual(str(self.app.get_timezone(key='other')), 'America/New_York')
|
||||
|
||||
def test_localtime(self):
|
||||
|
||||
|
@ -144,21 +120,21 @@ class TestAppHandler(TestCase):
|
|||
|
||||
# just confirm the method works on a basic level; the
|
||||
# underlying function is tested elsewhere
|
||||
now = self.handler.localtime()
|
||||
now = self.app.localtime()
|
||||
self.assertIsNotNone(now)
|
||||
|
||||
def test_make_utc(self):
|
||||
|
||||
# just confirm the method works on a basic level; the
|
||||
# underlying function is tested elsewhere
|
||||
now = self.handler.make_utc()
|
||||
now = self.app.make_utc()
|
||||
self.assertIsNotNone(now)
|
||||
|
||||
def test_load_object(self):
|
||||
|
||||
# just confirm the method works on a basic level; the
|
||||
# underlying function is tested elsewhere
|
||||
cls = self.handler.load_object('rattail.core:Object')
|
||||
cls = self.app.load_object('rattail.core:Object')
|
||||
self.assertIs(cls, Object)
|
||||
|
||||
def test_get_active_stores(self):
|
||||
|
@ -168,7 +144,7 @@ class TestAppHandler(TestCase):
|
|||
session = Session(bind=engine)
|
||||
|
||||
# no stores by default
|
||||
stores = self.handler.get_active_stores(session)
|
||||
stores = self.app.get_active_stores(session)
|
||||
self.assertEqual(len(stores), 0)
|
||||
|
||||
# add a basic store
|
||||
|
@ -179,7 +155,7 @@ class TestAppHandler(TestCase):
|
|||
self.assertIsNone(store001.archived)
|
||||
|
||||
# that one store should be returned
|
||||
stores = self.handler.get_active_stores(session)
|
||||
stores = self.app.get_active_stores(session)
|
||||
self.assertEqual(len(stores), 1)
|
||||
self.assertIs(stores[0], store001)
|
||||
|
||||
|
@ -190,7 +166,7 @@ class TestAppHandler(TestCase):
|
|||
session.flush()
|
||||
|
||||
# now only store 002 should be returned
|
||||
stores = self.handler.get_active_stores(session)
|
||||
stores = self.app.get_active_stores(session)
|
||||
self.assertEqual(len(stores), 1)
|
||||
self.assertIs(stores[0], store002)
|
||||
|
||||
|
@ -201,142 +177,142 @@ class TestAppHandler(TestCase):
|
|||
|
||||
# built-in autocompleter should be got okay
|
||||
from rattail.autocomplete.products import ProductAutocompleter
|
||||
autocompleter = self.handler.get_autocompleter('products')
|
||||
autocompleter = self.app.get_autocompleter('products')
|
||||
self.assertIsInstance(autocompleter, ProductAutocompleter)
|
||||
|
||||
# now let's invent one, but first make sure it is not yet valid
|
||||
self.assertRaises(ValueError, self.handler.get_autocompleter, 'foobars')
|
||||
self.assertRaises(ValueError, self.app.get_autocompleter, 'foobars')
|
||||
|
||||
# okay now configure it and then it should be got okay
|
||||
self.config.setdefault('rattail', 'autocomplete.foobars',
|
||||
'tests.test_app:FooBarAutocompleter')
|
||||
autocompleter = self.handler.get_autocompleter('foobars')
|
||||
autocompleter = self.app.get_autocompleter('foobars')
|
||||
self.assertIsInstance(autocompleter, FooBarAutocompleter)
|
||||
|
||||
def test_get_auth_handler(self):
|
||||
|
||||
# first call gets the default handler
|
||||
auth01 = self.handler.get_auth_handler()
|
||||
auth01 = self.app.get_auth_handler()
|
||||
self.assertIsNotNone(auth01)
|
||||
|
||||
# second call gets the same handler instance
|
||||
auth02 = self.handler.get_auth_handler()
|
||||
auth02 = self.app.get_auth_handler()
|
||||
self.assertIs(auth02, auth01)
|
||||
|
||||
def test_get_batch_handler(self):
|
||||
|
||||
# unknown batch type raises error by default
|
||||
self.assertRaises(ValueError, self.handler.get_batch_handler, 'foobar')
|
||||
self.assertRaises(ValueError, self.app.get_batch_handler, 'foobar')
|
||||
|
||||
# or returns None if error is suppressed
|
||||
bhandler = self.handler.get_batch_handler('foobar', error=False)
|
||||
bhandler = self.app.get_batch_handler('foobar', error=False)
|
||||
self.assertIsNone(bhandler)
|
||||
|
||||
# but we can provide our own spec
|
||||
bhandler = self.handler.get_batch_handler(
|
||||
bhandler = self.app.get_batch_handler(
|
||||
'foobar', default='tests.test_app:FooBarBatchHandler')
|
||||
self.assertIsInstance(bhandler, FooBarBatchHandler)
|
||||
|
||||
# we also can configure our handler
|
||||
self.config.setdefault('rattail.batch', 'foobar.handler',
|
||||
'tests.test_app:FooBarBatchHandler')
|
||||
bhandler = self.handler.get_batch_handler('foobar')
|
||||
bhandler = self.app.get_batch_handler('foobar')
|
||||
self.assertIsInstance(bhandler, FooBarBatchHandler)
|
||||
|
||||
# for some reason (?) the "importer" batch handler is special
|
||||
# and can be returned with no config
|
||||
from rattail.batch.importer import ImporterBatchHandler
|
||||
bhandler = self.handler.get_batch_handler('importer')
|
||||
bhandler = self.app.get_batch_handler('importer')
|
||||
self.assertIsInstance(bhandler, ImporterBatchHandler)
|
||||
|
||||
def test_get_board_handler(self):
|
||||
|
||||
# first call gets the default handler
|
||||
board01 = self.handler.get_board_handler()
|
||||
board01 = self.app.get_board_handler()
|
||||
self.assertIsNotNone(board01)
|
||||
|
||||
# second call gets the same handler instance
|
||||
board02 = self.handler.get_board_handler()
|
||||
board02 = self.app.get_board_handler()
|
||||
self.assertIs(board02, board01)
|
||||
|
||||
def test_get_bounce_handler(self):
|
||||
|
||||
# unknown type raises error by default
|
||||
self.assertRaises(ValueError, self.handler.get_bounce_handler, 'foobar')
|
||||
self.assertRaises(ValueError, self.app.get_bounce_handler, 'foobar')
|
||||
|
||||
# but we can configure our own too
|
||||
self.config.setdefault('rattail.bouncer', 'foobar.handler',
|
||||
'tests.test_app:FooBarBounceHandler')
|
||||
bhandler = self.handler.get_bounce_handler('foobar')
|
||||
bhandler = self.app.get_bounce_handler('foobar')
|
||||
self.assertIsInstance(bhandler, FooBarBounceHandler)
|
||||
|
||||
# default handler is special and works out of the box
|
||||
bhandler = self.handler.get_bounce_handler('default')
|
||||
bhandler = self.app.get_bounce_handler('default')
|
||||
self.assertIsInstance(bhandler, BounceHandler)
|
||||
|
||||
def test_get_clientele_handler(self):
|
||||
|
||||
# first call gets the default handler
|
||||
client01 = self.handler.get_clientele_handler()
|
||||
client01 = self.app.get_clientele_handler()
|
||||
self.assertIsNotNone(client01)
|
||||
|
||||
# second call gets the same handler instance
|
||||
client02 = self.handler.get_clientele_handler()
|
||||
client02 = self.app.get_clientele_handler()
|
||||
self.assertIs(client02, client01)
|
||||
|
||||
def test_get_custorder_handler(self):
|
||||
|
||||
# first call gets the default handler
|
||||
custorder01 = self.handler.get_custorder_handler()
|
||||
custorder01 = self.app.get_custorder_handler()
|
||||
self.assertIsNotNone(custorder01)
|
||||
|
||||
# second call gets the same handler instance
|
||||
custorder02 = self.handler.get_custorder_handler()
|
||||
custorder02 = self.app.get_custorder_handler()
|
||||
self.assertIs(custorder02, custorder01)
|
||||
|
||||
def test_get_employment_handler(self):
|
||||
|
||||
# first call gets the default handler
|
||||
employ01 = self.handler.get_employment_handler()
|
||||
employ01 = self.app.get_employment_handler()
|
||||
self.assertIsNotNone(employ01)
|
||||
|
||||
# second call gets the same handler instance
|
||||
employ02 = self.handler.get_employment_handler()
|
||||
employ02 = self.app.get_employment_handler()
|
||||
self.assertIs(employ02, employ01)
|
||||
|
||||
def test_get_feature_handler(self):
|
||||
|
||||
# first call gets the default handler
|
||||
feature01 = self.handler.get_feature_handler()
|
||||
feature01 = self.app.get_feature_handler()
|
||||
self.assertIsNotNone(feature01)
|
||||
|
||||
# second call gets the same handler instance
|
||||
feature02 = self.handler.get_feature_handler()
|
||||
feature02 = self.app.get_feature_handler()
|
||||
self.assertIs(feature02, feature01)
|
||||
|
||||
def test_get_email_handler(self):
|
||||
|
||||
# first call gets the default handler
|
||||
email01 = self.handler.get_email_handler()
|
||||
email01 = self.app.get_email_handler()
|
||||
self.assertIsNotNone(email01)
|
||||
|
||||
# second call gets the same handler instance
|
||||
email02 = self.handler.get_email_handler()
|
||||
email02 = self.app.get_email_handler()
|
||||
self.assertIs(email02, email01)
|
||||
|
||||
def test_get_all_import_handlers(self):
|
||||
|
||||
# several default handlers exist, but not our custom handler
|
||||
Handlers = self.handler.get_all_import_handlers()
|
||||
Handlers = self.app.get_all_import_handlers()
|
||||
self.assertTrue(Handlers)
|
||||
self.assertNotIn(FromFooToBar, Handlers)
|
||||
|
||||
# and by default there are no errors to be raised
|
||||
Handlers = self.handler.get_all_import_handlers(ignore_errors=False)
|
||||
Handlers = self.app.get_all_import_handlers(ignore_errors=False)
|
||||
self.assertTrue(Handlers)
|
||||
|
||||
# and just to make sure sorting "works" (no error)
|
||||
Handlers = self.handler.get_all_import_handlers(sort=True)
|
||||
Handlers = self.app.get_all_import_handlers(sort=True)
|
||||
self.assertTrue(Handlers)
|
||||
|
||||
# finally let's configure a custom handler, and be sure it
|
||||
|
@ -346,14 +322,14 @@ class TestAppHandler(TestCase):
|
|||
self.config.setdefault('rattail.importing',
|
||||
'to_rattail.from_rattail.import.handler',
|
||||
'tests.test_app:FromFooToBar')
|
||||
Handlers = self.handler.get_all_import_handlers()
|
||||
Handlers = self.app.get_all_import_handlers()
|
||||
self.assertTrue(Handlers)
|
||||
self.assertIn(FromFooToBar, Handlers)
|
||||
|
||||
def test_get_designated_import_handlers(self):
|
||||
|
||||
# several default handlers exist, but not our custom handler
|
||||
handlers = self.handler.get_designated_import_handlers()
|
||||
handlers = self.app.get_designated_import_handlers()
|
||||
self.assertTrue(handlers)
|
||||
self.assertFalse(any([isinstance(h, FromFooToBar)
|
||||
for h in handlers]))
|
||||
|
@ -364,14 +340,14 @@ class TestAppHandler(TestCase):
|
|||
self.config.setdefault('rattail.importing',
|
||||
'to_rattail.from_rattail.import.handler',
|
||||
'tests.test_app:FromFooToBar')
|
||||
handlers = self.handler.get_designated_import_handlers()
|
||||
handlers = self.app.get_designated_import_handlers()
|
||||
self.assertTrue(any([isinstance(h, FromFooToBar)
|
||||
for h in handlers]))
|
||||
self.assertFalse(any([isinstance(h, FromRattailToRattailImport)
|
||||
for h in handlers]))
|
||||
|
||||
# but then original default is included with alternates
|
||||
handlers = self.handler.get_designated_import_handlers(with_alternates=True)
|
||||
handlers = self.app.get_designated_import_handlers(with_alternates=True)
|
||||
matches = [h for h in handlers
|
||||
if isinstance(h, FromFooToBar)]
|
||||
self.assertEqual(len(matches), 1)
|
||||
|
@ -383,45 +359,45 @@ class TestAppHandler(TestCase):
|
|||
def test_get_import_handler(self):
|
||||
|
||||
# make sure a basic fetch works
|
||||
handler = self.handler.get_import_handler('to_rattail.from_rattail.import')
|
||||
handler = self.app.get_import_handler('to_rattail.from_rattail.import')
|
||||
self.assertIsInstance(handler, FromRattailToRattailImport)
|
||||
|
||||
# and make sure custom override works
|
||||
self.config.setdefault('rattail.importing',
|
||||
'to_rattail.from_rattail.import.handler',
|
||||
'tests.test_app:FromFooToBar')
|
||||
handler = self.handler.get_import_handler('to_rattail.from_rattail.import')
|
||||
handler = self.app.get_import_handler('to_rattail.from_rattail.import')
|
||||
|
||||
# unknown importer cannot be found
|
||||
handler = self.handler.get_import_handler('this_should_not_work')
|
||||
handler = self.app.get_import_handler('this_should_not_work')
|
||||
self.assertIsNone(handler)
|
||||
|
||||
# and if we require it, error will raise
|
||||
self.assertRaises(ValueError, self.handler.get_import_handler,
|
||||
self.assertRaises(ValueError, self.app.get_import_handler,
|
||||
'this_should_not_work', require=True)
|
||||
|
||||
def test_get_designated_import_handler_spec(self):
|
||||
|
||||
# fetch of unknown key returns none
|
||||
spec = self.handler.get_designated_import_handler_spec('test01')
|
||||
spec = self.app.get_designated_import_handler_spec('test01')
|
||||
self.assertIsNone(spec)
|
||||
|
||||
# unless we require it, in which case, error
|
||||
self.assertRaises(ValueError, self.handler.get_designated_import_handler_spec,
|
||||
self.assertRaises(ValueError, self.app.get_designated_import_handler_spec,
|
||||
'test01', require=True)
|
||||
|
||||
# we configure one for whatever key we like
|
||||
self.config.setdefault('rattail.importing',
|
||||
'test02.handler',
|
||||
'tests.test_app:FromFooToBar')
|
||||
spec = self.handler.get_designated_import_handler_spec('test02')
|
||||
spec = self.app.get_designated_import_handler_spec('test02')
|
||||
self.assertEqual(spec, 'tests.test_app:FromFooToBar')
|
||||
|
||||
# we can also define a "default" designated handler
|
||||
self.config.setdefault('rattail.importing',
|
||||
'test03.default_handler',
|
||||
'tests.test_app:FromFooToBar')
|
||||
spec = self.handler.get_designated_import_handler_spec('test03')
|
||||
spec = self.app.get_designated_import_handler_spec('test03')
|
||||
self.assertEqual(spec, 'tests.test_app:FromFooToBar')
|
||||
|
||||
# we can also designate handler w/ legacy config
|
||||
|
@ -432,87 +408,87 @@ class TestAppHandler(TestCase):
|
|||
self.config.setdefault('rattail.importing',
|
||||
'test04.custom_handler',
|
||||
'tests.test_app:FromFooToBar')
|
||||
spec = self.handler.get_designated_import_handler_spec('test04')
|
||||
spec = self.app.get_designated_import_handler_spec('test04')
|
||||
self.assertEqual(spec, 'tests.test_app:FromFooToBar')
|
||||
|
||||
def test_get_label_handler(self):
|
||||
|
||||
# first call gets the default handler
|
||||
labels01 = self.handler.get_label_handler()
|
||||
labels01 = self.app.get_label_handler()
|
||||
self.assertIsNotNone(labels01)
|
||||
|
||||
# second call gets the same handler instance
|
||||
labels02 = self.handler.get_label_handler()
|
||||
labels02 = self.app.get_label_handler()
|
||||
self.assertIs(labels01, labels01)
|
||||
|
||||
def test_get_membership_handler(self):
|
||||
|
||||
# first call gets the default handler
|
||||
membership01 = self.handler.get_membership_handler()
|
||||
membership01 = self.app.get_membership_handler()
|
||||
self.assertIsNotNone(membership01)
|
||||
|
||||
# second call gets the same handler instance
|
||||
membership02 = self.handler.get_membership_handler()
|
||||
membership02 = self.app.get_membership_handler()
|
||||
self.assertIs(membership02, membership01)
|
||||
|
||||
def test_get_people_handler(self):
|
||||
|
||||
# first call gets the default handler
|
||||
people01 = self.handler.get_people_handler()
|
||||
people01 = self.app.get_people_handler()
|
||||
self.assertIsNotNone(people01)
|
||||
|
||||
# second call gets the same handler instance
|
||||
people02 = self.handler.get_people_handler()
|
||||
people02 = self.app.get_people_handler()
|
||||
self.assertIs(people02, people01)
|
||||
|
||||
def test_get_products_handler(self):
|
||||
|
||||
# first call gets the default handler
|
||||
products01 = self.handler.get_products_handler()
|
||||
products01 = self.app.get_products_handler()
|
||||
self.assertIsNotNone(products01)
|
||||
|
||||
# second call gets the same handler instance
|
||||
products02 = self.handler.get_products_handler()
|
||||
products02 = self.app.get_products_handler()
|
||||
self.assertIs(products02, products01)
|
||||
|
||||
def test_get_report_handler(self):
|
||||
|
||||
# first call gets the default handler
|
||||
report01 = self.handler.get_report_handler()
|
||||
report01 = self.app.get_report_handler()
|
||||
self.assertIsNotNone(report01)
|
||||
|
||||
# second call gets the same handler instance
|
||||
report02 = self.handler.get_report_handler()
|
||||
report02 = self.app.get_report_handler()
|
||||
self.assertIs(report02, report01)
|
||||
|
||||
def test_get_problem_report_handler(self):
|
||||
|
||||
# first call gets the default handler
|
||||
problems01 = self.handler.get_problem_report_handler()
|
||||
problems01 = self.app.get_problem_report_handler()
|
||||
self.assertIsNotNone(problems01)
|
||||
|
||||
# second call gets the same handler instance
|
||||
problems02 = self.handler.get_problem_report_handler()
|
||||
problems02 = self.app.get_problem_report_handler()
|
||||
self.assertIs(problems02, problems01)
|
||||
|
||||
def test_get_trainwreck_handler(self):
|
||||
|
||||
# first call gets the default handler
|
||||
trainwreck01 = self.handler.get_trainwreck_handler()
|
||||
trainwreck01 = self.app.get_trainwreck_handler()
|
||||
self.assertIsNotNone(trainwreck01)
|
||||
|
||||
# second call gets the same handler instance
|
||||
trainwreck02 = self.handler.get_trainwreck_handler()
|
||||
trainwreck02 = self.app.get_trainwreck_handler()
|
||||
self.assertIs(trainwreck02, trainwreck01)
|
||||
|
||||
def test_get_vendor_handler(self):
|
||||
|
||||
# first call gets the default handler
|
||||
vendor01 = self.handler.get_vendor_handler()
|
||||
vendor01 = self.app.get_vendor_handler()
|
||||
self.assertIsNotNone(vendor01)
|
||||
|
||||
# second call gets the same handler instance
|
||||
vendor02 = self.handler.get_vendor_handler()
|
||||
vendor02 = self.app.get_vendor_handler()
|
||||
self.assertIs(vendor02, vendor01)
|
||||
|
||||
def test_progress_loop(self):
|
||||
|
@ -527,21 +503,21 @@ class TestAppHandler(TestCase):
|
|||
result.append(obj)
|
||||
|
||||
# this is just a basic test to get coverage..
|
||||
self.handler.progress_loop(inspect, range(5), NullProgress)
|
||||
self.app.progress_loop(inspect, range(5), NullProgress)
|
||||
self.assertEqual(result, list(range(5)))
|
||||
|
||||
def test_make_object(self):
|
||||
|
||||
# basic test
|
||||
obj = self.handler.make_object()
|
||||
obj = self.app.make_object()
|
||||
self.assertIsNotNone(obj)
|
||||
|
||||
# make sure attr is set
|
||||
obj = self.handler.make_object(answer=42)
|
||||
obj = self.app.make_object(answer=42)
|
||||
self.assertEqual(obj.answer, 42)
|
||||
|
||||
def test_make_uuid(self):
|
||||
uuid = self.handler.make_uuid()
|
||||
uuid = self.app.make_uuid()
|
||||
self.assertIsInstance(uuid, str)
|
||||
self.assertEqual(len(uuid), 32)
|
||||
|
||||
|
@ -554,16 +530,16 @@ class TestAppHandler(TestCase):
|
|||
# giving an unrelated object raises error
|
||||
person = Object()
|
||||
self.assertRaises(orm.exc.UnmappedInstanceError,
|
||||
self.handler.get_session, person)
|
||||
self.app.get_session, person)
|
||||
|
||||
# a related object still may not be in a session
|
||||
person = model.Person()
|
||||
result = self.handler.get_session(person)
|
||||
result = self.app.get_session(person)
|
||||
self.assertIsNone(result)
|
||||
|
||||
# okay then let's add to session, then should work
|
||||
session.add(person)
|
||||
result = self.handler.get_session(person)
|
||||
result = self.app.get_session(person)
|
||||
self.assertIs(result, session)
|
||||
|
||||
session.rollback()
|
||||
|
@ -576,19 +552,19 @@ class TestAppHandler(TestCase):
|
|||
|
||||
# default behavior should "work" albeit with no engine bound,
|
||||
# and no continuum user set
|
||||
session = self.handler.make_session()
|
||||
session = self.app.make_session()
|
||||
self.assertIsNotNone(session)
|
||||
self.assertIsNone(session.bind)
|
||||
self.assertIsNone(session.continuum_user)
|
||||
|
||||
# okay then let's create one with engine bound, and add a user
|
||||
session = self.handler.make_session(bind=engine)
|
||||
session = self.app.make_session(bind=engine)
|
||||
user = model.User(username='ferdinand')
|
||||
session.add(user)
|
||||
session.commit()
|
||||
|
||||
# now we can make a session with that user bound
|
||||
session = self.handler.make_session(bind=engine, user='ferdinand')
|
||||
session = self.app.make_session(bind=engine, user='ferdinand')
|
||||
self.assertEqual(session.continuum_user.username, 'ferdinand')
|
||||
|
||||
# okay add another user, configure it as default, then confirm
|
||||
|
@ -596,7 +572,7 @@ class TestAppHandler(TestCase):
|
|||
session.add(user)
|
||||
session.commit()
|
||||
self.config.setdefault('rattail', 'runas.default', 'beaufort')
|
||||
session = self.handler.make_session(bind=engine)
|
||||
session = self.app.make_session(bind=engine)
|
||||
self.assertEqual(session.continuum_user.username, 'beaufort')
|
||||
|
||||
def test_short_session(self):
|
||||
|
@ -627,7 +603,7 @@ class TestAppHandler(TestCase):
|
|||
session.commit()
|
||||
|
||||
# just do a basic cache to prove the concept
|
||||
stores = self.handler.cache_model(session, model.Store, key='id')
|
||||
stores = self.app.cache_model(session, model.Store, key='id')
|
||||
self.assertEqual(len(stores), 2)
|
||||
self.assertIn('001', stores)
|
||||
self.assertIn('002', stores)
|
||||
|
@ -637,22 +613,22 @@ class TestAppHandler(TestCase):
|
|||
def test_make_temp_dir(self):
|
||||
|
||||
# things work with no args
|
||||
path = self.handler.make_temp_dir()
|
||||
path = self.app.make_temp_dir()
|
||||
self.assertTrue(os.path.exists(path))
|
||||
os.rmdir(path)
|
||||
|
||||
# we can specify an alternate parent dir (in this case also temp)
|
||||
parent = self.handler.make_temp_dir()
|
||||
child = self.handler.make_temp_dir(dir=parent)
|
||||
parent = self.app.make_temp_dir()
|
||||
child = self.app.make_temp_dir(dir=parent)
|
||||
self.assertTrue(os.path.exists(child))
|
||||
self.assertEqual(os.path.dirname(child), parent)
|
||||
os.rmdir(child)
|
||||
os.rmdir(parent)
|
||||
|
||||
# also can configure the workdir, to be used as (indirect) parent
|
||||
workdir = self.handler.make_temp_dir()
|
||||
workdir = self.app.make_temp_dir()
|
||||
self.config.setdefault('rattail', 'workdir', workdir)
|
||||
child = self.handler.make_temp_dir()
|
||||
child = self.app.make_temp_dir()
|
||||
parent = os.path.dirname(child)
|
||||
self.assertEqual(os.path.dirname(parent), workdir)
|
||||
os.rmdir(child)
|
||||
|
@ -662,22 +638,22 @@ class TestAppHandler(TestCase):
|
|||
def test_make_temp_file(self):
|
||||
|
||||
# things work with no args
|
||||
path = self.handler.make_temp_file()
|
||||
path = self.app.make_temp_file()
|
||||
self.assertTrue(os.path.exists(path))
|
||||
os.remove(path)
|
||||
|
||||
# we can specify an alternate parent dir (in this case also temp)
|
||||
parent = self.handler.make_temp_dir()
|
||||
path = self.handler.make_temp_file(dir=parent)
|
||||
parent = self.app.make_temp_dir()
|
||||
path = self.app.make_temp_file(dir=parent)
|
||||
self.assertTrue(os.path.exists(path))
|
||||
self.assertEqual(os.path.dirname(path), parent)
|
||||
os.remove(path)
|
||||
os.rmdir(parent)
|
||||
|
||||
# also can configure the workdir, to be used as (indirect) parent
|
||||
workdir = self.handler.make_temp_dir()
|
||||
workdir = self.app.make_temp_dir()
|
||||
self.config.setdefault('rattail', 'workdir', workdir)
|
||||
path = self.handler.make_temp_file()
|
||||
path = self.app.make_temp_file()
|
||||
self.assertTrue(os.path.exists(path))
|
||||
parent = os.path.dirname(path)
|
||||
self.assertEqual(os.path.dirname(parent), workdir)
|
||||
|
@ -689,54 +665,54 @@ class TestAppHandler(TestCase):
|
|||
|
||||
# pre-normalized value is unchanged
|
||||
number = '8885551234'
|
||||
result = self.handler.normalize_phone_number(number)
|
||||
result = self.app.normalize_phone_number(number)
|
||||
self.assertEqual(result, number)
|
||||
|
||||
# now a basic real-world example
|
||||
number = '(888) 555-1234'
|
||||
result = self.handler.normalize_phone_number(number)
|
||||
result = self.app.normalize_phone_number(number)
|
||||
self.assertEqual(result, '8885551234')
|
||||
|
||||
# and another for good measure
|
||||
number = '888.555.1234'
|
||||
result = self.handler.normalize_phone_number(number)
|
||||
result = self.app.normalize_phone_number(number)
|
||||
self.assertEqual(result, '8885551234')
|
||||
|
||||
def test_phone_number_is_invalid(self):
|
||||
|
||||
# basic real-world example
|
||||
self.assertIsNone(self.handler.phone_number_is_invalid(
|
||||
self.assertIsNone(self.app.phone_number_is_invalid(
|
||||
'(888) 555-1234'))
|
||||
|
||||
# and another for good measure
|
||||
self.assertIsNone(self.handler.phone_number_is_invalid(
|
||||
self.assertIsNone(self.app.phone_number_is_invalid(
|
||||
'888.555.1234'))
|
||||
|
||||
# 10 digits are required, so 9 or 11 digits should fail
|
||||
self.assertEqual(self.handler.phone_number_is_invalid('123456789'),
|
||||
self.assertEqual(self.app.phone_number_is_invalid('123456789'),
|
||||
"Phone number must have 10 digits")
|
||||
self.assertEqual(self.handler.phone_number_is_invalid('12345678901'),
|
||||
self.assertEqual(self.app.phone_number_is_invalid('12345678901'),
|
||||
"Phone number must have 10 digits")
|
||||
|
||||
def test_format_phone_number(self):
|
||||
|
||||
# basic real-world example
|
||||
result = self.handler.format_phone_number('8885551234')
|
||||
result = self.app.format_phone_number('8885551234')
|
||||
self.assertEqual(result, '(888) 555-1234')
|
||||
|
||||
# garbage in garbage out
|
||||
result = self.handler.format_phone_number('garbage')
|
||||
result = self.app.format_phone_number('garbage')
|
||||
self.assertEqual(result, 'garbage')
|
||||
|
||||
def test_make_gpc(self):
|
||||
|
||||
# basic real-world example
|
||||
result = self.handler.make_gpc('074305001321')
|
||||
result = self.app.make_gpc('074305001321')
|
||||
self.assertIsInstance(result, GPC)
|
||||
self.assertEqual(str(result), '00074305001321')
|
||||
|
||||
# and let it calculate check digit
|
||||
result = self.handler.make_gpc('7430500132', calc_check_digit='upc')
|
||||
result = self.app.make_gpc('7430500132', calc_check_digit='upc')
|
||||
self.assertIsInstance(result, GPC)
|
||||
self.assertEqual(str(result), '00074305001321')
|
||||
|
||||
|
@ -744,70 +720,70 @@ class TestAppHandler(TestCase):
|
|||
|
||||
# basic real-world example
|
||||
gpc = GPC('00074305001321')
|
||||
result = self.handler.render_gpc(gpc)
|
||||
result = self.app.render_gpc(gpc)
|
||||
self.assertEqual(result, '0007430500132-1')
|
||||
|
||||
def test_render_currency(self):
|
||||
|
||||
# basic decimal example
|
||||
value = decimal.Decimal('42.00')
|
||||
self.assertEqual(self.handler.render_currency(value), '$42.00')
|
||||
self.assertEqual(self.app.render_currency(value), '$42.00')
|
||||
|
||||
# basic float example
|
||||
value = 42.00
|
||||
self.assertEqual(self.handler.render_currency(value), '$42.00')
|
||||
self.assertEqual(self.app.render_currency(value), '$42.00')
|
||||
|
||||
# decimal places will be rounded
|
||||
value = decimal.Decimal('42.12345')
|
||||
self.assertEqual(self.handler.render_currency(value), '$42.12')
|
||||
self.assertEqual(self.app.render_currency(value), '$42.12')
|
||||
|
||||
# but we can declare the scale
|
||||
value = decimal.Decimal('42.12345')
|
||||
self.assertEqual(self.handler.render_currency(value, scale=4), '$42.1234')
|
||||
self.assertEqual(self.app.render_currency(value, scale=4), '$42.1234')
|
||||
|
||||
# negative numbers get parens
|
||||
value = decimal.Decimal('-42.42')
|
||||
self.assertEqual(self.handler.render_currency(value), '($42.42)')
|
||||
self.assertEqual(self.app.render_currency(value), '($42.42)')
|
||||
|
||||
def test_render_quantity(self):
|
||||
|
||||
# integer decimals become integers
|
||||
value = decimal.Decimal('1.000')
|
||||
self.assertEqual(self.handler.render_quantity(value), '1')
|
||||
self.assertEqual(self.app.render_quantity(value), '1')
|
||||
|
||||
# but decimal places are preserved
|
||||
value = decimal.Decimal('1.234')
|
||||
self.assertEqual(self.handler.render_quantity(value), '1.234')
|
||||
self.assertEqual(self.app.render_quantity(value), '1.234')
|
||||
|
||||
def test_render_cases_units(self):
|
||||
|
||||
# basic examples, note the singular noun
|
||||
self.assertEqual(self.handler.render_cases_units(1, None), '1 case')
|
||||
self.assertEqual(self.handler.render_cases_units(None, 1), '1 unit')
|
||||
self.assertEqual(self.app.render_cases_units(1, None), '1 case')
|
||||
self.assertEqual(self.app.render_cases_units(None, 1), '1 unit')
|
||||
|
||||
# mix it up a bit
|
||||
self.assertEqual(self.handler.render_cases_units(3, 2), '3 cases + 2 units')
|
||||
self.assertEqual(self.app.render_cases_units(3, 2), '3 cases + 2 units')
|
||||
|
||||
# also note that zero is not hidden
|
||||
self.assertEqual(self.handler.render_cases_units(3, 0), '3 cases + 0 units')
|
||||
self.assertEqual(self.app.render_cases_units(3, 0), '3 cases + 0 units')
|
||||
|
||||
def test_render_date(self):
|
||||
|
||||
# basic example
|
||||
date = datetime.date(2021, 12, 31)
|
||||
self.assertEqual(self.handler.render_date(date), '2021-12-31')
|
||||
self.assertEqual(self.app.render_date(date), '2021-12-31')
|
||||
|
||||
def test_render_datetime(self):
|
||||
|
||||
# basic example
|
||||
dt = datetime.datetime(2021, 12, 31, 8, 30)
|
||||
self.assertEqual(self.handler.render_datetime(dt), '2021-12-31 08:30:00 AM')
|
||||
self.assertEqual(self.app.render_datetime(dt), '2021-12-31 08:30:00 AM')
|
||||
|
||||
@patch('rattail.app.send_email')
|
||||
def test_send_email(self, send_email):
|
||||
|
||||
# just make sure underlying function is invoked..
|
||||
self.handler.send_email('test')
|
||||
self.app.send_email('test')
|
||||
send_email.assert_called()
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue