gnucash stable: Multiple changes pushed

John Ralls jralls at code.gnucash.org
Thu Sep 24 16:28:25 EDT 2026


Updated	 via  https://github.com/Gnucash/gnucash/commit/5b687ae1 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/f21fec06 (commit)
	from  https://github.com/Gnucash/gnucash/commit/c8317b15 (commit)



commit 5b687ae193648337f8b602a1956cb09c97f804c9
Merge: c8317b15a0 f21fec06be
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Sep 24 13:26:12 2026 -0700

    Merge Noah Noerr's 'python-pricesource-enum' into stable.


commit f21fec06be967c4017ba7538c7ea28bb6dfddfa7
Author: Noerr <Noerr at users.noreply.github.com>
Date:   Thu Sep 24 00:06:16 2026 -0700

    [bindings/python] Add a PriceSource enum for gnc_price_set_source()
    
    Setting a price's source from Python meant reaching into gnucash_core_c for the
    raw PRICE_SOURCE_* constants. Add a PriceSource(IntEnum) alongside SessionOpenMode,
    with values sourced from the C enum (via gnucash_core_c) so they can't drift, so a
    script can write price.set_source(PriceSource.FINANCE_QUOTE) with a plain top-level
    import.
    
    Add test_price_and_wrapping.TestPriceSourceEnum:
     - test_values_match_c_enum asserts the Python enum covers the C PRICE_SOURCE_*
       value set exactly, so adding, removing, or renumbering a C value fails CI until
       PriceSource is updated to match. (Member names are a Python-side choice --
       FINANCE_QUOTE spells out FQ -- so the check is on values.)
     - test_set_source_accepts_enum confirms a member flows through set_source() and
       round-trips.

diff --git a/bindings/python/gnucash_core.py b/bindings/python/gnucash_core.py
index 563ceee0d8..acd6c1198c 100644
--- a/bindings/python/gnucash_core.py
+++ b/bindings/python/gnucash_core.py
@@ -275,6 +275,25 @@ class SessionOpenMode(IntEnum):
     Open the session, taking over any existing lock."""
 
 
+class PriceSource(IntEnum):
+    """Price source, mirroring the C PriceSource enum in gnc-pricedb.h.
+
+    Pass a member to GncPrice.set_source().
+    """
+
+    EDIT_DLG          = gnucash_core_c.PRICE_SOURCE_EDIT_DLG
+    FINANCE_QUOTE     = gnucash_core_c.PRICE_SOURCE_FQ
+    USER_PRICE        = gnucash_core_c.PRICE_SOURCE_USER_PRICE
+    XFER_DLG_VAL      = gnucash_core_c.PRICE_SOURCE_XFER_DLG_VAL
+    SPLIT_REG         = gnucash_core_c.PRICE_SOURCE_SPLIT_REG
+    SPLIT_IMPORT      = gnucash_core_c.PRICE_SOURCE_SPLIT_IMPORT
+    STOCK_SPLIT       = gnucash_core_c.PRICE_SOURCE_STOCK_SPLIT
+    STOCK_TRANSACTION = gnucash_core_c.PRICE_SOURCE_STOCK_TRANSACTION
+    INVOICE           = gnucash_core_c.PRICE_SOURCE_INVOICE
+    TEMP              = gnucash_core_c.PRICE_SOURCE_TEMP
+    INVALID           = gnucash_core_c.PRICE_SOURCE_INVALID
+
+
 class Session(GnuCashCoreClass):
     """A GnuCash book editing session
 
diff --git a/bindings/python/tests/test_price_and_wrapping.py b/bindings/python/tests/test_price_and_wrapping.py
index b889b7a8c6..acee15b229 100644
--- a/bindings/python/tests/test_price_and_wrapping.py
+++ b/bindings/python/tests/test_price_and_wrapping.py
@@ -14,6 +14,7 @@ from gnucash import (
     GncCommodity,
     GncNumeric,
     GncPrice,
+    PriceSource,
     Session,
     Split,
     Transaction,
@@ -453,5 +454,39 @@ class TestDoubleWrapProtection(TestCase):
         self.assertEqual(val.denom(), 2)
 
 
+# ---------------------------------------------------------------------------
+# Test: PriceSource enum stays in sync with the C PRICE_SOURCE_* enum
+# ---------------------------------------------------------------------------
+class TestPriceSourceEnum(TestCase):
+    """PriceSource must cover the C PRICE_SOURCE_* enum exactly, so it can't
+    drift if a value is added, removed, or renumbered on the C side. Member
+    names are a Python-side choice (e.g. FINANCE_QUOTE spells out FQ), so the
+    check is on the set of values, which come straight from the C enum."""
+
+    def test_values_match_c_enum(self):
+        from gnucash import gnucash_core_c as c
+        c_values = sorted(getattr(c, n) for n in dir(c)
+                          if n.startswith("PRICE_SOURCE_"))
+        py_values = sorted(m.value for m in PriceSource)
+        self.assertEqual(py_values, c_values,
+                         "PriceSource is out of sync with the C PRICE_SOURCE_* "
+                         "enum -- add/remove members to match.")
+
+    def test_set_source_accepts_enum(self):
+        ses = Session()
+        book = ses.get_book()
+        table = book.get_table()
+        usd = table.lookup("CURRENCY", "USD")
+        stock = GncCommodity(book, "Test Stock", "NASDAQ", "TSTK", "TSTK", 10000)
+        table.insert(stock)
+        price = GncPrice(book)
+        price.set_commodity(stock)
+        price.set_currency(usd)
+        price.set_source(PriceSource.FINANCE_QUOTE)
+        self.assertEqual(price.get_source(), PriceSource.FINANCE_QUOTE)
+        self.assertEqual(price.get_source_string(), "Finance::Quote")
+        ses.end()
+
+
 if __name__ == '__main__':
     main()



Summary of changes:
 bindings/python/gnucash_core.py                  | 19 +++++++++++++
 bindings/python/tests/test_price_and_wrapping.py | 35 ++++++++++++++++++++++++
 2 files changed, 54 insertions(+)



More information about the gnucash-changes mailing list