mirror of
https://github.com/Gnucash/gnucash.git
synced 2026-11-04 13:17:29 -06:00
PR #2187 made GncPrice.get_value() return a GncNumeric wrapper and clone() a fully wrapped GncPrice. The price example scripts still used the pre-5.15 raw _gnc_numeric idiom and broke -- reported as Bug 799796 (cloned prices silently kept the original value). Example scripts (bindings/python/example_scripts/): * quotes_historic.py -- reworked to the modern idiom; it now actually runs on 5.x (it had further latent breakage beyond the reported one): - Construct each price directly with GncPrice(book) + setters instead of cloning an existing price, so the script no longer needs a pre-existing price in the book. Look the pricing currency (USD) up from the commodity table rather than deriving it from a split. - Build the value with the double->GncNumeric constructor at GnuCash's standard price precision -- the pricing currency's SCU * COMMODITY_DENOM_MULT rounded HALF_UP (gnc-pricedb.h "Price policy") -- dropping the Fraction.from_float().limit_denominator(100000) dance and its import. - Set the source with the PriceSource enum -- set_source(PriceSource.FINANCE_QUOTE) (the enum added in #2317). The original set_source("Finance::Quotes::Historic") passed a string to what has been an enum setter since 2.6, which raises TypeError on modern bindings. - Open with Session(url), which defaults to SESSION_NORMAL_OPEN. The old Session(url, True, False, False) passed the deprecated ignore_lock=True, silently bypassing the book's lock file. * priceDB_test.py, price_database_example.py -- num/denom are methods now, so read v.num() / v.denom(). Prevent silent recurrence (gnucash_core.py): The write path failed *silently*, which is how this slipped through review and CI. num/denom are read-only accessor methods, so assigning to them merely shadows the method and changes nothing. Add a GncNumeric.__setattr__ that raises AttributeError on assignment to num/denom, pointing at the correct idiom GncNumeric(num, denom). Test (bindings/python/tests/test_numeric.py): New test_num_denom_read_only covering the guard. It needs no backend, so it runs in the existing python-bindings CTest on all platforms. The wiki page Stocks/get_prices, which the reporter copied from, is being updated separately.
93 lines
3.1 KiB
Python
Executable File
93 lines
3.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# Another test file for price database stuff
|
|
# To update the price database call
|
|
# $PATH/gnucash-cli --quotes get $PATHTOFILE
|
|
# before running this.
|
|
# Adding to a calling bash script would be better
|
|
# Although calling it from here would be even better!
|
|
# OR: export PYTHONPATH=<path-to-gnucash-inst-dir>/lib/python3.7/site-packages:$PYTHONPATH
|
|
# You may have to adjust the above path to your local system (lib->lib64, python3.7->...)
|
|
# Then: ipython3
|
|
# The account file is not saved but always use a disposable copy.
|
|
# Thanks for contributions by Christoph Holtermann and Mark Jenkins
|
|
|
|
## @file
|
|
# @brief Test file for price database stuff
|
|
# @author Mike Evans, Christoph Holtermann, Mark Jenkins
|
|
# @ingroup python_bindings_examples
|
|
|
|
from gnucash import Session
|
|
|
|
# -------------------------------------------
|
|
# Configuration options can be changed here :
|
|
|
|
cur_mnemonic="EUR" # Currency that prices are shown in. Possibilities include "EUR","GBP",...
|
|
namespace_name = "" # If no namespace_name is set, all namespaces will be shown
|
|
show_prices = True # If True, all prices for commodity are shown
|
|
commodity_fullname = "" # If no name is given, all commoditys in namespace will be shown
|
|
FILE = "PATH_TO_YOUR_TEST_FILE" # File is not saved but use a copy anyway
|
|
|
|
# Configuration end
|
|
# -------------------------------------------
|
|
|
|
session = Session(FILE, True, False, False)
|
|
|
|
root = session.book.get_root_account()
|
|
book = session.book
|
|
pdb = book.get_price_db()
|
|
comm_table = book.get_table()
|
|
|
|
cur = comm_table.lookup("CURRENCY", cur_mnemonic)
|
|
cur_name = cur.get_fullname()
|
|
|
|
|
|
if namespace_name != "": # Show single namespace
|
|
namespaces [ comm_table.find_namespace(namespace_name) ]
|
|
|
|
else: # Show all namespaces
|
|
namespaces=comm_table.get_namespaces_list()
|
|
|
|
for namespace in namespaces:
|
|
|
|
namespace_name=namespace.get_name()
|
|
|
|
|
|
# Get a list of all commodities in namespace
|
|
commodities=comm_table.get_commodities(namespace_name)
|
|
|
|
|
|
if len(commodities) == 0 :
|
|
|
|
print("No commodity in namespace "+namespace_name+".")
|
|
else:
|
|
if commodity_fullname:
|
|
print("Searching commodity '"+commodity_fullname+"' in namespace "+namespace_name)
|
|
else:
|
|
print("Commoditys in namespace "+namespace_name+":")
|
|
|
|
|
|
for i, c in enumerate(commodities):
|
|
|
|
c_fullname = c.get_fullname()
|
|
|
|
if not(commodity_fullname) or (commodity_fullname == c_fullname):
|
|
print("["+str(i)+"] Full Name :", c.get_fullname())
|
|
if show_prices:
|
|
pl = pdb.get_prices(c,cur)
|
|
|
|
if len(pl) > 0 :
|
|
print("{0} {1:20}{2:>10} {3}".format("Time ","Source","Price","Currency"))
|
|
for pr in pl:
|
|
|
|
source = pr.get_source()
|
|
time = pr.get_time64()
|
|
v=pr.get_value()
|
|
price = float(v.num())/v.denom()
|
|
|
|
print("{0} {1:20}{2:10.4f} {3}".format(time,source,price,cur_name))
|
|
# I didn't find out how to format the time option...
|
|
|
|
session.end()
|
|
session.destroy()
|
|
quit()
|