Skip to content

Sample Project Setup

valhuber edited this page Sep 11, 2021 · 6 revisions

The easiest way to configure Logic Bank is to use ApiLogicCreator. This page shows the underlying details if you want to use Logic Bank with an existing project.

Here we focus on the practicalities of installation and configuration, with 2 (unrelated) samples:

This page shows the common install / configure tasks common to both. In both cases, they use fab-quickstart, which is optional but recommended since it makes it really easy to explore your database.

Installing logicbankexamples

You can install this pre-configured example as described below.

Install Python Pre-reqs

To get started, you will need:

  • Pythonv3.8 (Relies on from __future__ import annotations, so requires Python 3.8)

    • Run the windows installer; on mac/Unix, consider using brew
  • virtualenv - see here (e.g., pip install virtualenv)

  • An IDE - any will do (I've used PyCharm and VSCode, install notes here), though different install / generate / run instructions apply for running programs.

Issues? Try here.

Installing this sample

Using your IDE or command line:

# fork https://github.com/valhuber/logicbank-examples.git -> yourname
git clone https://github.com/yourname/logicbankexamples.git
cd logicbankexamples
virtualenv venv
source venv/bin/activate
(venv)$ pip install -r requirements.txt

Verification

Either in your IDE or the command line, you can run tests and examine the logs that depict logic execution and chaining:

(venv)$ cd examples/nw/trans_tests
(venv)$ python upd_order_reuse.py

You can also run the pre-created fab application:

(venv)$ cd ../../nw_app
(venv)$ python run.py

Start your browser here, login as admin, p.

Project Setup Cookbook

This project has already been set up. Here's how we did it. We'll be using nw as an example.

Create Environment

# create your project root (check this into scs)
mkdir nw
cd nw
virtualenv venv
# configure SCS to ignore venv
# windows .env\Scripts\activate
source venv/bin/activate

(venv)$ pip install -i https://test.pypi.org/simple/ logicbank
(venv)$ pip install SQLAlchemy
(venv)$ pip install sqlacodegen

# if using fab
(venv)$ pip install flask-appbuilder
(venv)$ pip install fab-quick-start

Creating a New Project

We'll recreate the logicbankexamples. We'll follow the same structure to make things definite, so you can compare. Of course, use whatever structure you like, here's how we did it for nw and banking:

# in nw...
(venv)$ mkdir nw_logic
(venv)$ mkdir db

Create Models

There are many ways to create models.

  • You can create the models file by hand, and use that to generate the database, or
  • You can use an existing database, and create a models file to match it.

For existing databases, consider using sqlacodegen. Here, we'll use nw as our example; we already have a sqlite database in our examples/nw/db folder (download a copy) so:

(venv)$ cd db
(venv)$ sqlacodegen sqlite:///nw.db --noviews > examples/nw/nw_logic/app/models.py
(venv)$ sqlacodegen sqlite:///Northwind_small.sqlite --noviews > ../nw_logic/models.py

The first parameter identifies your database location; consult the sqlacodegen documentation.

Important notes about models - mind the relationships

Both logicbank and fab-quickstart depend on relationships. Ideally, they exist in your database, in which as sqlcodegen will find them. If that's not practical, SQLAlchemy also lets to define them in your models:

  • declare the foreign keys, eg, Orders has a foreign key to customers
    • CustomerId = Column(ForeignKey('Customer.Id'))
  • declare the references in the parent (not child), eg, declare orders for customer like this
    • OrderDetailList = relationship("OrderDetail", backref="OrderHeader", cascade_backrefs=True)

Declaring Logic as Spreadsheet-like Rules

To illustrate, let's use an adaption of the Northwind database, with a few rollup columns added. For those not familiar, this is basically Customers, Orders, OrderDetails and Products, as shown in the diagrams below.

Declare rules using Python

Logic is declared as spreadsheet-like rules as shown below from examples/nw/nw_logic/logic.py, which implements the check credit requirement:

def activate_basic_check_credit_rules():
    """ Check Credit Requirement:
        * the balance must not exceed the credit limit,
        * where the balance is the sum of the unshipped order totals
        * which is the rollup of OrderDetail Price * Quantities:
    """

    Rule.constraint(validate=Customer, as_condition=lambda row: row.Balance <= row.CreditLimit,
                    error_msg="balance ({row.Balance}) exceeds credit ({row.CreditLimit})")
    Rule.sum(derive=Customer.Balance, as_sum_of=Order.AmountTotal,
             where=lambda row: row.ShippedDate is None)  # *not* a sql select sum
    
    Rule.sum(derive=Order.AmountTotal, as_sum_of=OrderDetail.Amount)
   
    Rule.formula(derive=OrderDetail.Amount, as_expression=lambda row: row.UnitPrice * row.Quantity)
    Rule.copy(derive=OrderDetail.UnitPrice, from_parent=Product.UnitPrice)
Activate Rules

To test our rules, we use examples/nw/trans_tests/add_order.py. It activates the rules using this import:

from examples.nw import session  # opens db, activates logic listener <--

This executes examples/nw/logic/__init__.py, which sets up the rule engine:

by_rules = True  # True => use rules, False => use hand code (for comparison)
if by_rules:
    LogicBank.activate(session=session, activator=declare_logic)
else:
    # ... conventional after_flush listeners (to see rules/code contrast)

Status

nw running, banking under development