Tutorial : using existing objects

Opening an existing Book

To open an existing GnuCash document (and get the related Book), use the open_book() function:

import piecash

# for a sqlite3 document
book = piecash.open_book("existing_file.gnucash")

# or through an URI connection string for sqlite3
book = piecash.open_book(uri_conn="sqlite:///existing_file.gnucash")
# or for postgres
book = piecash.open_book(uri_conn="postgres://user:passwd@localhost/existing_gnucash_db")

The documents are open as readonly per default. To allow RW access, specify explicitly readonly=False as:

book = piecash.open_book("existing_file.gnucash", readonly=False)

When opening in full access (readonly=False), piecash will automatically create a backup file named filename.piecash_YYYYMMDD_HHMMSS with the original file. To avoid creating the backup file, specificy do_backup=False as:

book = piecash.open_book("existing_file.gnucash", readonly=False, do_backup=False)

To force opening the file even through there is a lock on it, use the open_if_lock=True argument:

book = piecash.open_book("existing_file.gnucash", open_if_lock=True)

Access to objects

Once a GnuCash book is opened through a piecash.core.book.Book, GnuCash objects can be accessed through two different patterns:

The object model

In this mode, we access elements through their natural relations, starting from the book and jumping from one object to the other:

In [1]: book = open_book(gnucash_books + "default_book.gnucash")

In [2]: book.root_account # accessing the root_account
Out[2]: Account<[EUR]>

In [3]: # looping through the children accounts of the root_account
   ...: for acc in book.root_account.children:
   ...:     print(acc)
   ...: 
Account<Assets[EUR]>
Account<Liabilities[EUR]>
Account<Income[EUR]>
Account<Expenses[EUR]>
Account<Equity[EUR]>

# accessing children accounts
In [4]: 
   ...: root = book.root_account              # select the root_account
   ...: assets = root.children(name="Assets")   # select child account by name
   ...: cur_assets = assets.children[0]         # select child account by index
   ...: cash = cur_assets.children(type="CASH") # select child account by type
   ...: print(cash)
   ...: 
Account<Assets:Current Assets:Cash in Wallet[EUR]>

In [5]: # get the commodity of an account
   ...: commo = cash.commodity
   ...: print(commo)
   ...: 
Commodity<CURRENCY:EUR>

In [6]: # get first ten accounts linked to the commodity commo
   ...: for acc in commo.accounts[:10]:
   ...:     print(acc)
   ...: 
Account<[EUR]>
Account<Assets[EUR]>
Account<Assets:Current Assets[EUR]>
Account<Assets:Current Assets:Checking Account[EUR]>
Account<Assets:Current Assets:Savings Account[EUR]>
Account<Assets:Current Assets:Cash in Wallet[EUR]>
Account<Liabilities[EUR]>
Account<Liabilities:Credit Card[EUR]>
Account<Income[EUR]>
Account<Income:Bonus[EUR]>

The “table” access

In this mode, we access elements through collections directly accessible from the book:

In [7]: book = open_book(gnucash_books + "default_book.gnucash")

# accessing all accounts
In [8]: book.accounts
Out[8]: 
[Account<Assets[EUR]>,
 Account<Assets:Current Assets[EUR]>,
 Account<Assets:Current Assets:Checking Account[EUR]>,
 Account<Assets:Current Assets:Savings Account[EUR]>,
 Account<Assets:Current Assets:Cash in Wallet[EUR]>,
 Account<Liabilities[EUR]>,
 Account<Liabilities:Credit Card[EUR]>,
 Account<Income[EUR]>,
 Account<Income:Bonus[EUR]>,
 Account<Income:Gifts Received[EUR]>,
 Account<Income:Interest Income[EUR]>,
 Account<Income:Interest Income:Checking Interest[EUR]>,
 Account<Income:Interest Income:Other Interest[EUR]>,
 Account<Income:Interest Income:Savings Interest[EUR]>,
 Account<Income:Other Income[EUR]>,
 Account<Income:Salary[EUR]>,
 Account<Expenses[EUR]>,
 Account<Expenses:Adjustment[EUR]>,
 Account<Expenses:Auto[EUR]>,
 Account<Expenses:Auto:Fees[EUR]>,
 Account<Expenses:Auto:Gas[EUR]>,
 Account<Expenses:Auto:Parking[EUR]>,
 Account<Expenses:Auto:Repair and Maintenance[EUR]>,
 Account<Expenses:Bank Service Charge[EUR]>,
 Account<Expenses:Books[EUR]>,
 Account<Expenses:Cable[EUR]>,
 Account<Expenses:Charity[EUR]>,
 Account<Expenses:Clothes[EUR]>,
 Account<Expenses:Computer[EUR]>,
 Account<Expenses:Dining[EUR]>,
 Account<Expenses:Education[EUR]>,
 Account<Expenses:Entertainment[EUR]>,
 Account<Expenses:Entertainment:Music/Movies[EUR]>,
 Account<Expenses:Entertainment:Recreation[EUR]>,
 Account<Expenses:Entertainment:Travel[EUR]>,
 Account<Expenses:Gifts[EUR]>,
 Account<Expenses:Groceries[EUR]>,
 Account<Expenses:Hobbies[EUR]>,
 Account<Expenses:Insurance[EUR]>,
 Account<Expenses:Insurance:Auto Insurance[EUR]>,
 Account<Expenses:Insurance:Health Insurance[EUR]>,
 Account<Expenses:Insurance:Life Insurance[EUR]>,
 Account<Expenses:Laundry/Dry Cleaning[EUR]>,
 Account<Expenses:Medical Expenses[EUR]>,
 Account<Expenses:Miscellaneous[EUR]>,
 Account<Expenses:Online Services[EUR]>,
 Account<Expenses:Phone[EUR]>,
 Account<Expenses:Public Transportation[EUR]>,
 Account<Expenses:Subscriptions[EUR]>,
 Account<Expenses:Supplies[EUR]>,
 Account<Expenses:Taxes[EUR]>,
 Account<Expenses:Taxes:Federal[EUR]>,
 Account<Expenses:Taxes:Medicare[EUR]>,
 Account<Expenses:Taxes:Other Tax[EUR]>,
 Account<Expenses:Taxes:Social Security[EUR]>,
 Account<Expenses:Taxes:State/Province[EUR]>,
 Account<Expenses:Utilities[EUR]>,
 Account<Expenses:Utilities:Electric[EUR]>,
 Account<Expenses:Utilities:Garbage collection[EUR]>,
 Account<Expenses:Utilities:Gas[EUR]>,
 Account<Expenses:Utilities:Water[EUR]>,
 Account<Equity[EUR]>,
 Account<Equity:Opening Balances[EUR]>]

# accessing all commodities
In [9]: book.commodities
Out[9]: [Commodity<CURRENCY:EUR>]

# accessing all transactions
In [10]: book.transactions
Out[10]: []

Each of these collections can be either iterated or accessed through some indexation or filter mechanism (return first element of collection satisfying some criteria(s)):

# iteration
In [11]: for acc in book.accounts:
   ....:     if acc.type == "ASSET": print(acc)
   ....: 
Account<Assets[EUR]>
Account<Assets:Current Assets[EUR]>

# indexation (not very meaningful)
In [12]: book.accounts[10]
Out[12]: Account<Income:Interest Income[EUR]>

# filter by name
In [13]: book.accounts(name="Garbage collection")
Out[13]: Account<Expenses:Utilities:Garbage collection[EUR]>

# filter by type
In [14]: book.accounts(type="EXPENSE")
Out[14]: Account<Expenses[EUR]>

# filter by fullname
In [15]: book.accounts(fullname="Expenses:Taxes:Social Security")
Out[15]: Account<Expenses:Taxes:Social Security[EUR]>

# filter by multiple criteria
In [16]: book.accounts(commodity=book.commodities[0], name="Gas")
Out[16]: Account<Expenses:Auto:Gas[EUR]>

The “SQLAlchemy” access (advanced users)

In this mode, we access elements through SQLAlchemy queries on the SQLAlchemy session:

# retrieve underlying SQLAlchemy session object
In [1]: session = book.session

# get all account with name >= "T"
In [2]: session.query(Account).filter(Account.name>="T").all()
Out[2]: 
[Account<Expenses:Entertainment:Travel[EUR]>,
 Account<Expenses:Taxes[EUR]>,
 Account<Expenses:Utilities[EUR]>,
 Account<Expenses:Utilities:Water[EUR]>,
 Account<>]

# display underlying query
In [3]: str(session.query(Account).filter(Account.name>="T"))
Out[3]: 'SELECT accounts.account_type AS accounts_account_type, accounts.commodity_scu AS accounts_commodity_scu, accounts.non_std_scu AS accounts_non_std_scu, accounts.placeholder AS accounts_placeholder, accounts.guid AS accounts_guid, accounts.name AS accounts_name, accounts.commodity_guid AS accounts_commodity_guid, accounts.parent_guid AS accounts_parent_guid, accounts.code AS accounts_code, accounts.description AS accounts_description, accounts.hidden AS accounts_hidden \nFROM accounts \nWHERE accounts.name >= ?'

Accounts

Accessing the accounts (piecash.core.account.Account):

In [1]: book = open_book(gnucash_books + "simple_sample.gnucash", open_if_lock=True)

# accessing the root_account
In [2]: root = book.root_account

In [3]: print(root)
Account<>

# accessing the first children account of a book
In [4]: acc = root.children[0]

In [5]: print(acc)
Account<Asset[EUR]>

# accessing attributes of an account
In [6]: print(f"Account name={acc.name}\n"
   ...:       f"        commodity={acc.commodity.namespace}/{acc.commodity.mnemonic}\n"
   ...:       f"        fullname={acc.fullname}\n"
   ...:       f"        type={acc.type}")
   ...: 
Account name=Asset
        commodity=CURRENCY/EUR
        fullname=Asset
        type=ASSET

# calculating the balance of the accounts:
In [7]: for acc in root.children:
   ...:     print(f"Account balance for {acc.name}: {acc.get_balance()} (without sign reversal: {acc.get_balance(natural_sign=False)}")
   ...: 
Account balance for Asset: 1320 (without sign reversal: 1320
Account balance for Liability: 900 (without sign reversal: -900
Account balance for Income: 150 (without sign reversal: -150
Account balance for Expense: 230 (without sign reversal: 230
Account balance for Equity: 500 (without sign reversal: -500

# accessing all splits related to an account
In [8]: for sp in acc.splits:
   ...:     print(f"account <{acc.fullname}> is involved in transaction '{sp.transaction.description}'")
   ...: 

Commodities and Prices

The list of all commodities in the book can be retrieved via the commodities attribute:

In [1]: book = open_book(gnucash_books + "book_prices.gnucash", open_if_lock=True)

# all commodities
In [2]: print(book.commodities)
[Commodity<CURRENCY:EUR>, Commodity<NASDAQ:FB>, Commodity<template:template>, Commodity<PAR:ENGI.PA>, Commodity<NYQ:KO>, Commodity<CURRENCY:USD>]

In [3]: cdty = book.commodities[0]

# accessing attributes of a commodity
In [4]: print("Commodity namespace={cdty.namespace}\n"
   ...:       "          mnemonic={cdty.mnemonic}\n"
   ...:       "          cusip={cdty.cusip}\n"
   ...:       "          fraction={cdty.fraction}".format(cdty=cdty))
   ...: 
Commodity namespace=CURRENCY
          mnemonic=EUR
          cusip=978
          fraction=100

The prices (piecash.core.commodity.Price) of a commodity can be iterated through the prices attribute:

# loop on the prices
In [1]: for cdty in book.commodities:
   ...:     for pr in cdty.prices:
   ...:         print("Price date={pr.date}"
   ...:               "      value={pr.value} {pr.currency.mnemonic}/{pr.commodity.mnemonic}".format(pr=pr))
   ...: 
Price date=2018-02-10      value=1.730120457024597578303288749E-7 EUR/FB
Price date=2018-02-11      value=54 EUR/FB
Price date=2018-02-13      value=3.808073 EUR/FB
Price date=2018-02-12      value=5 EUR/FB
Price date=2018-02-15      value=3.923077 EUR/FB

Transactions and Splits

The list of all transactions in the book can be retrieved via the transactions attribute:

In [1]: book = open_book(gnucash_books + "book_schtx.gnucash", open_if_lock=True)

# all transactions (including transactions part of a scheduled transaction description)
In [2]: for tr in book.transactions:
   ...:     print(tr)
   ...: 
Transaction<[EUR] 'Monthly utility bill' on 2015-01-02>
Transaction<[EUR] 'Insurance' on 2015-01-02>
Transaction<[EUR] 'Monthly utility bill' on 2013-12-31 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2014-02-02 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2014-03-02 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2014-03-31 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2014-04-30 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2014-06-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2014-06-30 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2014-07-31 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2014-08-31 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2014-09-30 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2014-11-02 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2014-11-30 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2014-12-31 (from sch tx)>
Transaction<[EUR] 'Insurance' on 2013-05-31 (from sch tx)>
Transaction<[EUR] 'Insurance' on 2014-05-29 (from sch tx)>
Transaction<[EUR] 'Opening balance' on 2013-01-02>
Transaction<[EUR] 'Monthly utility bill' on 2015-02-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2015-03-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2015-03-31 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2015-04-30 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2015-05-31 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2015-06-30 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2015-08-02 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2015-08-31 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2015-09-30 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2015-11-01 (from sch tx)>
Transaction<[EUR] 'Insurance' on 2015-05-31 (from sch tx)>
Transaction<[EUR] 'test' on 2015-11-17>
Transaction<[EUR] 'salary' on 2013-12-31>
Transaction<[EUR] 'salary' on 2014-12-31>
Transaction<[EUR] 'Monthly utility bill' on 2015-12-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2016-01-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2016-02-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2016-03-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2016-04-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2016-05-02 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2016-06-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2016-07-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2016-08-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2016-09-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2016-10-03 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2016-11-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2016-12-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2017-01-02 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2017-02-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2017-03-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2017-04-03 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2017-05-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2017-06-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2017-07-03 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2017-08-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2017-09-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2017-10-02 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2017-11-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2017-12-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2018-01-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2018-02-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2018-03-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2018-04-02 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2018-05-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2018-06-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2018-07-02 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2018-08-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2018-09-03 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2018-10-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2018-11-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2018-12-03 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2019-01-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2019-02-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2019-03-01 (from sch tx)>
Transaction<[EUR] 'Monthly utility bill' on 2019-04-01 (from sch tx)>
Transaction<[EUR] 'Insurance' on 2016-06-01 (from sch tx)>
Transaction<[EUR] 'Insurance' on 2017-06-01 (from sch tx)>
Transaction<[EUR] 'Insurance' on 2018-06-01 (from sch tx)>

# selecting first transaction generated from a scheduled transaction
In [3]: tr = [ tr for tr in book.transactions if tr.scheduled_transaction ][0]

For a given transaction, the following attributes are accessible:

# accessing attributes of a transaction
In [1]: print("Transaction description='{tr.description}'\n"
   ...:       "            currency={tr.currency}\n"
   ...:       "            post_date={tr.post_date}\n"
   ...:       "            enter_date={tr.enter_date}".format(tr=tr))
   ...: 
Transaction description='Monthly utility bill'
            currency=Commodity<CURRENCY:EUR>
            post_date=2013-12-31
            enter_date=2015-01-03 08:18:13+00:00

# accessing the splits of the transaction
In [2]: tr.splits
Out[2]: 
[Split<Account<Assets:Current Assets:Checking Account[EUR]> -70 EUR>,
 Split<Account<Expenses:Utilities:Electric[EUR]> 30 EUR>,
 Split<Account<Expenses:Utilities:Gas[EUR]> 40 EUR>]

# identifying which split is a credit or a debit
In [3]: for sp in tr.splits:
   ...:     split_type = "credit" if sp.is_credit else "debit"
   ...:     print(f"{sp} is a {split_type}")
   ...: 
Split<Account<Assets:Current Assets:Checking Account[EUR]> -70 EUR> is a credit
Split<Account<Expenses:Utilities:Electric[EUR]> 30 EUR> is a debit
Split<Account<Expenses:Utilities:Gas[EUR]> 40 EUR> is a debit

# accessing the scheduled transaction
In [4]: [ sp for sp in tr.scheduled_transaction.template_account.splits]
Out[4]: 
[SplitTemplate<Account<Assets:Current Assets:Checking Account[EUR]> credit=70 >,
 SplitTemplate<Account<Expenses:Utilities:Electric[EUR]>  debit=30>,
 SplitTemplate<Account<Expenses:Utilities:Gas[EUR]>  debit=40>]

# closing the book
In [5]: book.close()

Invoices

The list of all invoices in the book can be retrieved via the invoices attribute:

In [1]: book = open_book(gnucash_books + "invoices.gnucash", open_if_lock=True)

# all invoices
In [2]: for invoice in book.invoices:
   ...:     print(invoice)
   ...: 
Invoice<000001>

Other objects

In fact, any object can be retrieved from the session through a generic get(**kwargs) method:

In [1]: book = open_book(gnucash_books + "invoices.gnucash", open_if_lock=True)

In [2]: from piecash import Account, Commodity, Budget, Vendor

# accessing specific objects through the get method
In [3]: book.get(Account, name="Assets", parent=book.root_account)
Out[3]: Account<Assets[EUR]>

In [4]: book.get(Commodity, namespace="CURRENCY", mnemonic="EUR")
Out[4]: Commodity<CURRENCY:EUR>

In [5]: book.get(Budget, name="my first budget")
Out[5]: Budget<my first budget() for 12 periods following pattern 'month*1 from 2019-04-01 [none]' >

In [6]: book.get(Vendor, name="Looney")
Out[6]: Vendor<000001:Looney>

If you know SQLAlchemy, you can get access to the underlying Session as book.session and execute queries using the piecash classes:

In [7]: from piecash import Account, Commodity, Budget, Vendor

# get the SQLAlchemy session
In [8]: session = book.session

# loop through all invoices
In [9]: for invoice in session.query(Invoice).all():
   ...:     print(invoice.notes)
   ...: 

Note

Easy access to objects from piecash.business and piecash.budget could be given directly from the session in future versions if deemed useful.

Working with slots

With regard to slots, GnuCash objects and Frames behave as dictionaries and all values are automatically converted back and forth to python objects:

In [1]: import datetime, decimal

In [2]: book = create_book()

# retrieve list of slots
In [3]: print(book.slots)
[]

# set slots
In [4]: book["myintkey"] = 3

In [5]: book["mystrkey"] = "hello"

In [6]: book["myboolkey"] = True

In [7]: book["mydatekey"] = datetime.datetime.today().date()

In [8]: book["mydatetimekey"] = datetime.datetime.today()

In [9]: book["mynumerickey"] = decimal.Decimal("12.34567")

In [10]: book["account"] = book.root_account

# iterate over all slots
In [11]: for k, v in book.iteritems():
   ....:     print("slot={v} has key={k} and value={v.value} of type {t}".format(k=k,v=v,t=type(v.value)))
   ....: 
slot=<SlotInt myintkey=3> has key=myintkey and value=3 of type <class 'int'>
slot=<SlotString mystrkey='hello'> has key=mystrkey and value=hello of type <class 'str'>
slot=<SlotInt myboolkey=True> has key=myboolkey and value=True of type <class 'bool'>
slot=<SlotDate mydatekey=datetime.date(2020, 10, 24)> has key=mydatekey and value=2020-10-24 of type <class 'datetime.date'>
slot=<SlotTime mydatetimekey=datetime.datetime(2020, 10, 24, 19, 14, 9, 274380)> has key=mydatetimekey and value=2020-10-24 19:14:09.274380 of type <class 'datetime.datetime'>
slot=<SlotNumeric mynumerickey=Decimal('12.34567')> has key=mynumerickey and value=12.34567 of type <class 'decimal.Decimal'>
slot=<SlotGUID account=Account<[EUR]>> has key=account and value=Account<[EUR]> of type <class 'piecash.core.account.Account'>

# delete a slot
In [12]: del book["myintkey"]

# delete all slots
In [13]: del book[:]

# create a key/value in a slot frames (and create them if they do not exist)
In [14]: book["options/Accounts/Use trading accounts"]="t"

# access a slot in frame in whatever notations
In [15]: s1=book["options/Accounts/Use trading accounts"]

In [16]: s2=book["options"]["Accounts/Use trading accounts"]

In [17]: s3=book["options/Accounts"]["Use trading accounts"]

In [18]: s4=book["options"]["Accounts"]["Use trading accounts"]

In [19]: assert s1==s2==s3==s4

Slots of type GUID use the name of the slot to do the conversion back and forth between an object and its guid. For these slots, there is an explicit mapping between slot names and object types.