-
Notifications
You must be signed in to change notification settings - Fork 8
Sample Project Setup
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:
-
nw
(same as in logicbank) banking
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.
You can install this pre-configured example as described below.
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.
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
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.
This project has already been set up. Here's how we did it.
We'll be using nw
as an example.
# 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
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
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.
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)
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.
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)
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)
nw
running, banking
under development
User Project Operations
Logic Bank Internals