rattail.app

App Handler

class rattail.app.AppHandler(config)[source]

Base class and default implementation for top-level Rattail app handler.

aka. “the handler to handle all handlers”

aka. “one handler to bind them all”

This now inherits from wuttjamaican.app.AppHandler although it still overrides most of the upstream methods. Over time more of this class logic will hopefully be moved upstream.

There is normally no need to create one of these yourself; rather you should call get_app() on the config object if you need the app handler.

cache_model(session, model, **kwargs)[source]

Convenience method which invokes rattail.db.cache.cache_model() with the given model and keyword arguments.

delete_setting(session, name, **kwargs)[source]

Delete the given setting from the DB.

Parameters:
  • session – Current DB session.

  • name – Name of the setting to delete.

format_phone_number(number)[source]

Returns a “properly formatted” string based on the given phone number.

Default logic invokes rattail.db.util.format_phone_number().

Parameters:

number – Raw phone number string e.g. as found in some data source.

Returns:

Formatted phone number string.

get_active_stores(session, **kwargs)[source]

Returns the list of “active” stores. A store is considered active if it is not marked as archived.

Parameters:

session – Reference to current DB session.

Returns:

Possibly-empty list of Store records which are deemed active.

get_all_import_handlers(ignore_errors=True, sort=False, **kwargs)[source]

Returns all Import/Export Handler classes which are known to exist, i.e. all which are registered via setup.py for the various packages installed.

This means it will include both “designated” handlers as well as non-designated. See get_designated_import_handlers() if you only want the designated ones.

Note that this will return the Handler classes and not handler instances.

Parameters:
  • ignore_errors – Normally any errors which come up during the loading process are ignored. Pass False here to force errors to raise, e.g. if you are not seeing the results you expect.

  • sort – If you like the results can be sorted with a simple key based on “Source -> Target” labels.

Returns:

List of all registered Import/Export Handler classes.

get_auth_handler(**kwargs)[source]

Get the configured “auth” handler.

Returns:

The AuthHandler instance for the app.

get_autocompleter(key, **kwargs)[source]

Returns a new Autocompleter instance corresponding to the given key, e.g. 'products'.

The app handler has some hard-coded defaults for the built-in autocompleters (see default_autocompleters in the source code). You can override any of these, and/or add your own with custom keys, via config, e.g.:

[rattail]
autocomplete.products = poser.autocomplete.products:ProductAutocompleter
autocomplete.otherthings = poser.autocomplete.things:OtherThingAutocompleter

With the above you can then fetch your custom autocompleter with:

autocompleter = app.get_autocompleter('otherthings')

In any case if it can locate the class, it will create an instance of it and return that.

Params key:

Unique key for the type of autocompleter you need. Often is a simple string, e.g. 'customers' but sometimes there may be a “modifier” with it to get an autocompleter with more specific behavior.

For instance 'customers.phone' would effectively give you a customer autocompleter but which searched by phone number instead of customer name.

Note that each key is still a simple string though, and that must be “unique” in the sense that only one autocompleter can be configured for each key.

Returns:

An Autocompleter instance if found, otherwise None.

get_batch_handler(key, default=None, error=True, **kwargs)[source]

Get the configured batch handler of the given type.

Parameters:
  • key – Unique key designating which type of batch handler is being requested.

  • default – Spec string to be used as the default, if no handler is configured for the given batch type. This spec string must itself refer to a BatchHandler class.

  • error – Flag indicating whether an error should be raised if no handler can be found.

Returns:

A BatchHandler instance of the requested type. If no such handler can be found, and the error param is false, then None is returned; otherwise an error will raise.

get_board_handler(**kwargs)[source]

Get the configured “board” handler.

Returns:

The BoardHandler instance for the app.

get_bounce_handler(key, **kwargs)[source]

Get the configured email bounce handler of the given type.

Parameters:

key – Unique key designating which type of bounce handler is being requested.

Returns:

A BounceHandler instance of the requested type. If no such handler can be found, an error will raise.

get_class_prefix(default=None)[source]

Returns the “class prefix” for the app, used when naming model classes etc.

get_cleanup_handler(**kwargs)[source]

Get the configured “cleanup” handler.

Returns:

The CleanupHandler instance for the app.

get_clientele_handler(**kwargs)[source]

Get the configured “clientele” handler.

Returns:

The ClienteleHandler instance for the app.

get_contact_email(obj, traverse=True, **kwargs)[source]

Return the first email record found for the given object.

Note that this returns the email record and not just the address as string. See also get_contact_email_address().

Returns:

A EmailAddress (likely a subclass) instance, or None.

get_contact_email_address(obj, **kwargs)[source]

Return the first email address found for the given object.

Note that this returns the email address as string and not the full email record. See also get_contact_email_address().

Returns:

Email address as string, or None.

get_contact_phone(obj, traverse=True, **kwargs)[source]

Return the first phone record found for the given object.

Note that this returns the phone record and not just the number as string. See also get_contact_phone_number().

Returns:

A PhoneNumber (likely a subclass) instance, or None.

get_contact_phone_number(obj, **kwargs)[source]

Return the first phone number found for the given object.

Note that this returns the phone number as string and not the full phone record. See also get_contact_phone().

Returns:

Phone number as string, or None.

get_customer(obj, **kwargs)[source]

Convenience method to locate a Customer record for the given object. This delegates to the ClienteleHandler for actual lookup logic.

get_customer_key_field()[source]

Returns the configured fieldname for customer key, e.g. 'id'.

get_customer_key_label(field=None)[source]

Returns the configured field label for customer key, e.g. 'ID'.

get_custorder_handler(**kwargs)[source]

Get the configured “customer order” handler.

Returns:

The CustomerOrderHandler instance for the app.

get_datasync_handler(**kwargs)[source]

Get the configured “datasync” handler.

Returns:

The DatasyncHandler instance for the app.

get_db_handler(**kwargs)[source]

Get the configured “database” handler.

Returns:

The DatabaseHandler instance for the app.

get_designated_import_handler_spec(key, require=False, **kwargs)[source]

Return the designated import handler “spec” string for the given type key.

Parameters:

key – Unique key indicating the type of import handler.

Require:

Flag indicating whether an error should be raised if no handler is found.

Returns:

Spec string for the designated handler. If none is found, then None is returned unless the require param is true, in which case an error is raised.

get_designated_import_handlers(with_alternates=False, **kwargs)[source]

Returns all “designated” import/export handler instances.

Each “handler type key” can have at most one Handler class which is “designated” in the config. This method collects all registered handlers and then sorts out which one is designated, for each type key, ultimately returning only the designated ones.

Note that this will return the handler instances and not Handler classes.

If you have a type key and just need its designated handler, see get_import_handler().

See also get_all_import_handlers() if you need all registered Handler classes.

Parameters:

with_alternates

If you specify True here then each designated handler returned will have an extra attribute named alternate_handlers, which will be a list of the other “available” (registered) handlers which match the designated handler’s type key.

This is probably most / only useful for the Configuration UI, to allow admin to change which is designated.

Returns:

List of all designated import/export handler instances.

get_email_handler(**kwargs)[source]

Get the configured “email” handler.

Returns:

The EmailHandler instance for the app.

get_employee(obj, **kwargs)[source]

Convenience method to locate an Employee record for the given object. This delegates to the EmploymentHandler for actual lookup logic.

get_employment_handler(**kwargs)[source]

Get the configured “employment” handler.

Returns:

The EmploymentHandler instance for the app.

get_feature_handler(**kwargs)[source]

Get the configured “feature” handler.

Returns:

The FeatureHandler instance for the app.

get_import_handler(key, require=False, **kwargs)[source]

Return the designated import/export handler instance, per the given handler type key.

See also get_designated_import_handlers() if you want the full set of designated handlers.

Parameters:
  • key – A “handler type key”, e.g. 'to_rattail.from_rattail.import'.

  • require – Specify True here if you want an error to be raised should no handler be found.

Returns:

The import/export handler instance corresponding to the given key. If no handler can be found, then None is returned, unless require param is true, in which case error is raised.

get_label_handler(**kwargs)[source]

Get the configured “label” handler.

See also Label Handler.

Returns:

The LabelHandler instance for the app.

get_luigi_handler(**kwargs)[source]

Get the configured “luigi” handler.

Returns:

The LuigiHandler instance for the app.

get_member(obj, **kwargs)[source]

Convenience method to locate a Member record for the given object. This delegates to the MembershipHandler for actual lookup logic.

get_member_key_field()[source]

Returns the configured fieldname for member key, e.g. 'id'.

get_member_key_label(field=None)[source]

Returns the configured field label for member key, e.g. 'ID'.

get_membership_handler(**kwargs)[source]

Get the configured “membership” handler.

See also Membership Handler.

Returns:

The MembershipHandler instance for the app.

get_node_title(default='Rattail')[source]

Returns the configured title for the local app node.

get_org_handler(**kwargs)[source]

Get the configured “org” handler.

Returns:

The OrgHandler instance for the app.

get_people_handler(**kwargs)[source]

Get the configured “people” handler.

See also People Handler.

Returns:

The PeopleHandler instance for the app.

get_person(obj, **kwargs)[source]

Convenience method to locate a Person record for the given object. This delegates to the PeopleHandler for actual lookup logic.

get_poser_handler(**kwargs)[source]

Get the configured “poser” handler.

Returns:

The PoserHandler instance for the app.

get_problem_report_handler(**kwargs)[source]

Get the configured “problem reports” handler.

Returns:

The ProblemReportHandler instance for the app.

get_product_key_field()[source]

Returns the configured fieldname for product key, e.g. 'upc'.

get_product_key_label(field=None)[source]

Returns the configured field label for product key, e.g. 'UPC'.

get_products_handler(**kwargs)[source]

Get the configured “products” handler.

Returns:

The ProductsHandler instance for the app.

get_project_handler(**kwargs)[source]

Get the configured “project” handler.

Returns:

The ProjectHandler instance for the app.

get_report_handler(**kwargs)[source]

Get the configured “reports” handler.

Returns:

The ReportHandler instance for the app.

get_session(obj)[source]

Returns the SQLAlchemy session with which the given object is associated. Simple convenience wrapper around sqlalchemy.orm.object_session().

get_setting(session, name, typ=None, **kwargs)[source]

Get a setting value from the DB.

This is mostly the same as upstream get_setting() but is customized for Rattail in the following way:

Parameters:

typ – Most values are treated as simple strings, but if you specify 'utctime' here, then the return value will be converted to a UTC-based datetime object

Returns:

Usually a string, but can be some other type, depending on the typ param.

get_table_prefix(default=None)[source]

Returns the “table prefix” for the app, used when naming tables etc.

get_tailbone_handler(**kwargs)[source]

Get the configured “tailbone” handler.

Returns:

The TailboneHandler instance for the app.

get_telemetry_handler(**kwargs)[source]

Get the configured “telemetry” handler.

Returns:

The TelemetryHandler instance for the app.

get_timezone(key='default')[source]

Returns a configured time zone.

Default logic invokes rattail.time.timezone() to obtain the time zone object.

Parameters:

key – Unique key designating which time zone should be returned. Note that most apps have only one (“default”), but may have others defined.

get_title(default='Rattail')[source]

Returns the configured title (name) of the app.

Parameters:

default – Value to be returned if there is no app title configured.

Returns:

Title for the app.

get_trainwreck_handler(**kwargs)[source]

Get the configured “trainwreck” handler.

Returns:

The TrainwreckHandler instance for the app.

get_upgrade_handler(**kwargs)[source]

Get the configured “upgrade” handler.

Returns:

The UpgradeHandler instance for the app.

get_user(obj, **kwargs)[source]

Convenience method to locate a User record for the given object. This delegates to the AuthHandler for actual lookup logic.

get_vendor_handler(**kwargs)[source]

Get the configured “vendor” handler.

Returns:

The VendorHandler instance for the app.

get_version()[source]

Returns the current app version.

get_workorder_handler(**kwargs)[source]

Get the configured “work order” handler.

Returns:

The WorkOrderHandler instance for the app.

json_friendly(value)[source]

Coerce a Python value to one which is JSON-serializable.

So, this does not return a JSON string, but rather a Python object which can then be safely converted via json.dumps().

If the value is a container, it will be crawled recursively and all values it contains will be coerced.

load_object(spec)[source]

Import and/or load and return the object designated by the given spec string.

Default logic invokes rattail.util.load_object() to obtain the object.

The syntax of the spec string is not unique to Rattail, but is not a universal standard, so deserves a note here. The spec is basically just modulepath:objname where modulepath is the dotted name of the full module where the object resides, and objname is the name of the object within that module. For instance, rattail.app:AppHandler would be the spec for this class.

Note also that the use of the word “object” may be confusing, as it does not signify an “instance” but rather an object in the generic sense. Most often a spec will either refer to a class or function within the module, although any valid named object is possible.

Parameters:

spec – String like modulepath:objname as described above.

Returns:

The object referred to by spec. If the module could not be imported, or did not contain an object of the given name, then an error will raise.

localtime(*args, **kwargs)[source]

Produce or convert a timestamp in the default time zone.

Default logic invokes rattail.time.localtime() to obtain the timestamp. All args and kwargs are passed directly to that function.

Returns:

A datetime.datetime object. Usually this will be timezone-aware but this will depend on the args and kwargs you specify.

make_appdir(path, subfolders=None, **kwargs)[source]

Establish an appdir at the given path.

This is mostly the same as upstream make_appdir() but (for now) for compatibility Rattail extends this by adding more subfolders to the default list.

make_config_file(file_type, output_path, template=None, template_path=None, **kwargs)[source]

Write a new config file of given type to specified location.

Parameters:
  • file_type – The “type” of config file to create. This is used to locate the file template, if template_path is not specified. It also is used as default output filename, if output_path is a folder.

  • output_path – Path to which new config file should be written. If this is a folder, then the filename is deduced from the file_type.

  • template – Optional reference to a Mako template instance.

  • template_path – Optional path to config file template to use. If not specified, it will be looked up dynamically based on the file_type. Note that the first template found to match will be used. Mako (*.mako) templates are preferred, otherwise the template is assumed to be “plain” and will be copied as-is to the output path.

  • **kwargs – Context to be passed to the Mako template, if applicable.

Returns:

Final path to which new config file was written.

make_counter(session, key, **kwargs)[source]

Create a new counter sequence in the DB, if needed.

This should only be needed with PostgreSQL back-end. For others, the sequence should be auto-created as needed when calling next_counter_value().

Parameters:
  • session – Current session for Rattail DB.

  • key – Unique key indicating the counter which should be created.

make_engine_from_config(config_dict, prefix='sqlalchemy.', **kwargs)[source]

This is the same as wuttjamaican.app.AppHandler.make_engine_from_config() except Rattail may customize the engine a bit further:

The engine can be told to “record changes” for sake of datasync; for instance:

[rattail.db]
default.url = sqlite:///
default.record_changes = true

And/or the engine can be told to log its SQLAlchemy connection pool status:

[rattail.db]
default.url = sqlite:///
default.log_pool_status = true
make_gpc(value, **kwargs)[source]

Make and return a GPC instance from the given value.

Default logic will invoke make_gpc() of the products handler; see also get_products_handler().

make_object(**kwargs)[source]

Create and return a generic object. All kwargs will be assigned as attributes to the object.

make_session(user=None, **kwargs)[source]

Creates and returns a new SQLAlchemy session for the Rattail DB.

Parameters:

user – A “user-ish” object which should be considered responsible for changes made during the session. Can be either a User object, or just a (string) username. If none is specified then the config will be consulted for a default.

Returns:

A rattail.db.Session instance.

make_supervisorctl_proxy(url=None, **kwargs)[source]

Create and return a XML-RPC server proxy for the Supervisor process manager.

make_temp_dir(**kwargs)[source]

Create a temporary directory. This is mostly a convenience wrapper around the built-in tempfile.mkdtemp(). However by default it will attempt to place the temp folder underneath the configured “workdir”, e.g.:

[rattail]
workdir = /srv/envs/poser/app/work
make_temp_file(**kwargs)[source]

Reserve a temporary filename. This is mostly a convenience wrapper around the built-in tempfile.mkstemp(). However by default it will attempt to place the temp file underneath the configured “workdir”, e.g.:

[rattail]
workdir = /srv/envs/poser/app/work
make_utc(*args, **kwargs)[source]

Produce or convert a timestamp to UTC time zone.

Default logic invokes rattail.time.make_utc() to obtain the timestamp. All args and kwargs are passed directly to that function.

Returns:

A datetime.datetime object. Usually this will be timezone-naive but this will depend on the args and kwargs you specify.

make_uuid()[source]

Generate a new UUID value.

Returns:

UUID value as 32-character string.

maxlen(attr)[source]

Return the max size (length) for the given model attribute.

Note that you must pass the attribute proper, not just the name of one etc. For example:

size = app.maxlen(model.Product.description)
Parameters:

attr – Any column-based property of a model class.

Returns:

Max length as integer.

property model

Property which returns a reference to the DB model module.

Ultimately this is the same as calling rattail.config.RattailConfig.get_model().

next_counter_value(session, key, create=False, **kwargs)[source]

Return the next counter value for the given key.

Parameters:
  • session – Current session for Rattail DB.

  • key – Unique key indicating the counter for which the next value should be fetched.

  • create – Automatically create the sequence if needed. This only applies to PostgreSQL; sequences are always auto-created as needed for other back-ends.

Returns:

Next value as integer.

normalize_phone_number(number, **kwargs)[source]

Normalize the given phone number, to a “common” format that can be more easily worked with for sync logic etc. In practice this usually just means stripping all non-digit characters from the string. The idea is that phone number data from any system can be “normalized” and thereby compared directly to see if they differ etc.

Default logic will invoke rattail.db.util.normalize_phone_number().

Parameters:

number – Raw phone number string e.g. as found in some data source.

Returns:

Normalized string.

parse_date(value, **kwargs)[source]

Parse a date value from the given string, which is assumed to be in ISO format.

parse_utctime(value, local=False, tzinfo=None, **kwargs)[source]

Parse a datetime value from the given string, which is assumed to be in UTC timezone and formatted “typically” for Rattail.

phone_number_is_invalid(number)[source]

This method should validate the given phone number string, and if the number is not considered valid, this method should return the reason.

Parameters:

number – Raw phone number string e.g. as found in some data source.

Returns:

String describing reason the number is invalid, or None if the number is deemed valid.

progress_loop(*args, **kwargs)[source]

Run a given function for a given sequence, and optionally show a progress indicator.

Default logic invokes the rattail.util.progress_loop() function; see that for more details.

render_cases_units(cases, units)[source]

Render a human-friendly string showing the given number of cases and/or units. For instance:

>>> app.render_cases_units(1, None)
'1 case'

>>> app.render_cases_units(None, 1)
'1 unit'

>>> app.render_cases_units(3, 2)
'3 cases + 2 units'
Parameters:
  • cases – Number of cases (can be zero or None).

  • units – Number of units (can be zero or None).

Returns:

Display string for the given values.

render_currency(value, scale=2, **kwargs)[source]

Must return a human-friendly display string for the given currency value, e.g. Decimal('4.20') becomes "$4.20".

Parameters:
Returns:

Display string for the value.

render_date(value, **kwargs)[source]

Return a human-friendly display string for the given date.

Parameters:

value – A datetime.date instance.

Returns:

Display string for the date.

render_datetime(value, **kwargs)[source]

Return a human-friendly display string for the given datetime.

render_duration(delta=None, hours=None, seconds=None, **kwargs)[source]

Render a time duration for human eyes, e.g. “1:30” for 1.5 hours.

Note that you must specify either delta, hours or seconds.

Parameters:
  • delta – If specified, should be a datetime.timedelta object representing the duration.

  • hours – If specified, should be the number of hours elapsed for the duration, as decimal.

  • seconds – If specified, should be the number of seconds elapsed for the duration, as integer.

Returns:

Duration rendered as human-friendly string. Note that if all params are empty, this will return an empty string.

render_gpc(value, **kwargs)[source]

Returns a human-friendly display string for the given GPC value.

Parameters:

value – A GPC instance.

Returns:

Display string for the GPC, or None if the value provided is not a GPC.

render_mako_template(template_path, context, template=None, output_path=None, **kwargs)[source]

Convenience method to render any (specified) Mako template.

render_percent(value, places=2, from_decimal=False, **kwargs)[source]

Render a human-friendly display string for the given percentage value.

Parameters:
  • value – Should be a decimal representation of the percentage, e.g. 0.80 would indicate 80%.

  • places – Number of decimal places to display in the rendered string.

  • from_decimal – If false (the default), then value should (normally) be between 0 - 100. But if true, then value is assumed to be between 0.0 and 1.0 instead.

render_quantity(value, **kwargs)[source]

Return a human-friendly display string for the given quantity value, e.g. 1.000 becomes "1".

Parameters:

value – The quantity to be rendered.

Returns:

Display string for the quantity.

render_time_ago(delta=None, seconds=None, fallback=<object object>, **kwargs)[source]

Return a human-friendly display string showing “how long ago” something happened.

You may specify either delta or seconds but in either case these are assumed to represent time elapsed compared to “now” - e.g. the number of seconds ago which something occurred.

This method is not suitable for displaying an arbitrary time duration contained in the past. It always assumes “now” is the endpoint for the time duration.

NB. this invokes humanize.naturaltime() under the hood.

Parameters:
  • delta – A datetime.timedelta instance representing a time duration.

  • seconds – Optional number of seconds to use for the time duration, instead of specifying the delta.

  • fallback – Optional string value to return, if the time duration was not valid.

Returns:

Human-friendly display string.

save_setting(session, name, value, typ=None, force_create=False, **kwargs)[source]

Save a setting value to the DB.

Parameters:
  • session – Current DB session.

  • name – Name of the setting to save.

  • value – Value to be saved for the setting.

  • typ – Most values are treated as simple strings, but if you specify 'utctime' here, then the value is assumed to be a UTC-based datetime object, and the final setting value will be formatted appropriately.

  • force_create – If False (the default) then logic will first try to locate an existing setting of the given name, and update it if found, or create if not. But if this param is True then logic will only try to create a new record, and not bother checking to see if it exists.

send_email(key, data={}, **kwargs)[source]

Send an email message of the given type.

See rattail.mail.send_email() for more info.

short_session(**kwargs)[source]

This is the same as upstream short_session() except Rattail customizes the default factory kwarg:

Normally the default factory is just make_session() but (in Rattail) that may imply a lookup of the configured “runas” user for sake of Continuum versioning. So this method modifies the default factory to avoid that lookup.

Note

The auto-lookup for runas user is a bit awkward, so this may change at some point.

today(**kwargs)[source]

Return the current date.

touch_object(session, obj)[source]

Mark the given object as having been changed, such that the datasync will pick it up and propagate the object to other nodes.

Note that this is minimal logic; only the given object will be “touched” in this way, i.e. no related records will be touched. So if those also need it, you must call this method for each related object separately.

update_email(contact, email_address, email_fields={}, slot=1)[source]

Update an email address record for the contact.

Parameters:
  • contact – Contact object, e.g. a Customer, Person, etc.

  • email_address – New/correct email address as string.

  • email_fields – Additional field values if applicable. The email will be updated to match as needed.

  • slot – Which email in the contact’s list should be updated. By default this will update (or add) the 1st email, but specify slot=2 for the 2nd etc.

update_phone(contact, phone_number, phone_fields={}, slot=1)[source]

Update a phone number record for the contact.

Parameters:
  • contact – Contact object, e.g. a Customer, Person, etc.

  • phone_number – New/correct phone number as string.

  • phone_fields – Additional field values if applicable. The phone will be updated to match as needed.

  • slot – Which phone in the contact’s list should be updated. By default this will update (or add) the 1st phone, but specify slot=2 for the 2nd etc.

yesterday(**kwargs)[source]

Return the date for yesterday.

class rattail.app.GenericHandler(config, **kwargs)[source]

Base class for misc. “generic” feature handlers.

Most handlers which exist for sake of business logic, should inherit from this.

class rattail.app.MergeMixin[source]

Mixin class for feature handlers supporting a record merge.

get_merge_preview_data(obj, **kwargs)[source]

Must return a data dictionary for the given object, which can be presented to the user during a merge preview.

get_merge_preview_fields(**kwargs)[source]

Returns a sequence of fields which will be used during a merge preview.

get_merge_resulting_data(removing, keeping, **kwargs)[source]

Must return a dictionary to represent what the final data would look like, should the proposed merge occur. Note that we’re still in preview mode here, this doesn’t actually cause any particular data to become final.

Parameters:
merge_update_keeping_object(removing, keeping)[source]

Update the object to be kept, with any relevant data from the object to be removed, in the context of a merge.

perform_merge(removing, keeping, **kwargs)[source]

Perform an actual merge of the 2 given objects.

Parameters:
  • removing – Object which should be removed.

  • keeping – Object which should be kept.

why_not_merge(removing, keeping, **kwargs)[source]

Evaluate the given merge candidates and if there is a reason not to merge them, return that reason.

Parameters:
  • removing – Object which will be removed, should the merge happen.

  • keeping – Object which will be kept, should the merge happen.

Returns:

String indicating reason not to merge, or None.

class rattail.app.RattailProvider(config)[source]

Base class for Rattail app providers.

This inherits from upstream AppProvider and adds the following to it:

enum

Reference to the enum module for the app.

model

Reference to the model module for the app.

handlers

Dictionary of “secondary” handlers used by the provider, if applicable.

load_object(*args, **kwargs)[source]

Convenience method which calls AppHandler.load_object().