gnucash stable: Multiple changes pushed
John Ralls
jralls at code.gnucash.org
Fri Sep 25 19:12:43 EDT 2026
Updated via https://github.com/Gnucash/gnucash/commit/3cf1352c (commit)
via https://github.com/Gnucash/gnucash/commit/0dc41c12 (commit)
from https://github.com/Gnucash/gnucash/commit/fbcb9f5e (commit)
commit 3cf1352cbb2aa8405bbd6df38c047bf3cee9f938
Merge: fbcb9f5e75 0dc41c1212
Author: John Ralls <jralls at ceridwen.us>
Date: Fri Sep 25 16:10:42 2026 -0700
Merge Noah Noerr's 'python-guard-price-set-source-string' into stable.
commit 0dc41c1212028c163c3717235c182fe34d08ed4c
Author: Noerr <Noerr at users.noreply.github.com>
Date: Wed Sep 23 02:06:17 2026 -0700
[bindings/python] Deprecate set_source_string; remove it from the Guile bindings
gnc_price_set_source_string maps a source string to the PriceSource enum and
silently leaves the source unchanged for anything it doesn't recognize -- a
silent no-op a naive Python or Guile script can hit. Steer callers to
set_source() with a PriceSource member (added in #2317) instead.
Python bindings:
- Deprecate GncPrice.set_source_string(): it now emits a DeprecationWarning
pointing at set_source(PriceSource.<...>). It still works during the
deprecation period and still guards -- if the string is not recognized (the
round-tripped source no longer equals the input) it raises ValueError rather
than silently doing nothing.
- Fix the deprecated() decorator in deprecation.py: it referenced the undefined
DeprecationWarnig and inspect.current_frame(), so it raised instead of
warning (the one existing @deprecated use was latently broken).
Guile bindings:
- mark gnc-price-set-source-string deprecated in engine.i.
(Python and Guile use separate SWIG interface files, so Python is
handled separately). The only in-tree Guile caller is the QIF importer, updated to
gnc-price-set-source with PRICE-SOURCE-USER-PRICE; the redundant
set-source-string in test-engine-extras.scm's fixture helper is dropped.
Tests (test_price_and_wrapping.py):
- TestSetSourceStringGuard covers the guard (still raises on an unrecognized
string) and the new DeprecationWarning.
Removing set_source_string from the Python bindings is a follow-up.
diff --git a/bindings/engine.i b/bindings/engine.i
index 6610e6f651..2c42daec20 100644
--- a/bindings/engine.i
+++ b/bindings/engine.i
@@ -56,6 +56,7 @@
#include <numeric>
#include <unordered_set>
+#include <libguile/deprecation.h>
%}
#if defined(SWIGGUILE) //Always C++
%{
@@ -359,6 +360,14 @@ functions. */
%include <policy.h>
%include <gnc-pricedb.h>
+%feature("shadow") gnc_price_set_source_string %{
+ (define (gnc_price_set_source_string price str)
+ (issue-deprecation_warning
+ "gnc-price-set-source-string is deprecated and will be removed in GnuCash 6."
+ "Use gnc-price-set-source and the appropriate enum value instead.")
+ ($action price str))
+%}
+
QofSession * qof_session_new (QofBook* book);
QofBook * qof_session_get_book (QofSession *session);
// TODO: Unroll/remove
diff --git a/bindings/guile/test/test-engine-extras.scm b/bindings/guile/test/test-engine-extras.scm
index e641c6a073..778fde2304 100644
--- a/bindings/guile/test/test-engine-extras.scm
+++ b/bindings/guile/test/test-engine-extras.scm
@@ -151,7 +151,6 @@
(gnc-price-set-currency price currency)
(gnc-price-set-time64 price time64)
(gnc-price-set-source price PRICE-SOURCE-XFER-DLG-VAL)
- (gnc-price-set-source-string price "test-price")
(gnc-price-set-typestr price "test")
(gnc-price-set-value price value)
(gnc-price-commit-edit price)
diff --git a/bindings/python/deprecation.py b/bindings/python/deprecation.py
index 46d0a71f0b..288594bffa 100644
--- a/bindings/python/deprecation.py
+++ b/bindings/python/deprecation.py
@@ -24,10 +24,10 @@ def deprecated(message):
def wrapper(*args, **kwargs):
warning_msg = 'Call to deprecated function {}. {}'.format(
func.__name__, message)
- frame = inspect.current_frame().f_back
+ frame = inspect.currentframe().f_back
- warn_explicit(message,
- category=DeprecationWarnig,
+ warn_explicit(warning_msg,
+ category=DeprecationWarning,
filename=inspect.getfile(frame.f_code),
lineno=frame.f_lineno)
return func(*args, **kwargs)
diff --git a/bindings/python/gnucash_core.py b/bindings/python/gnucash_core.py
index acd6c1198c..ad15f89ff1 100644
--- a/bindings/python/gnucash_core.py
+++ b/bindings/python/gnucash_core.py
@@ -744,12 +744,9 @@ class GncPrice(GnuCashCoreClass):
* currency: the denomination of the value of the item being priced.
* value: the value of the item being priced.
* time: the time the price was valid.
- * source: a string describing the source of the quote. These strings will be something like this:
- "Finance::Quote", "user:misc", "user:foo", etc. If the quote came from a user, as a matter of policy,
- you *must* prefix the string you give with "user:". For now, the only other reserved values are
- "Finance::Quote" and "old-file-import". Any string used must be added to the source_list array in
- dialog-price-edit-db.c so that it can be properly translated. (There are unfortunately many strings
- in users' databases, so this string must be translated on output instead of always being used in untranslated form).
+ * source: describes how the price was created. The string form used by
+ set_source_string() / get_source_string() must be one of the recognized
+ PriceSource values; set_source_string() raises ValueError otherwise.
* type: the type of quote - types possible right now are bid, ask, last, nav, and
unknown.Each price in the database represents an "instantaneous" quote for a given
commodity with respect to another commodity.
@@ -760,6 +757,30 @@ class GncPrice(GnuCashCoreClass):
_new_instance = 'gnc_price_create'
GncPrice.add_methods_with_prefix('gnc_price_')
+# Deprecate set_source_string() in favour of set_source() with a PriceSource
+# member. While it exists, guard it: the C setter maps a fixed set of canonical
+# strings to the PriceSource enum and silently leaves the source unchanged for
+# anything else, so a typo or obsolete string would change nothing -- detect
+# that (the round-tripped source no longer equals the input) and raise instead.
+_gnc_price_set_source_string = GncPrice.set_source_string
+def _deprecated_set_source_string(self, source):
+ """Deprecated: use set_source() with a PriceSource member.
+
+ Still raises ValueError if `source` is not a recognized PriceSource string
+ (the underlying C setter would otherwise leave the source unchanged)."""
+ _gnc_price_set_source_string(self, source)
+ if self.get_source_string() != source:
+ raise ValueError(
+ "%r is not a recognized price source string, so set_source_string() "
+ "left the source unchanged. Use set_source() with a PriceSource "
+ "member, e.g. set_source(PriceSource.FINANCE_QUOTE)." % (source,))
+# Report the deprecation under the public method name, not the wrapper's.
+_deprecated_set_source_string.__name__ = 'set_source_string'
+_deprecated_set_source_string.__qualname__ = 'GncPrice.set_source_string'
+GncPrice.set_source_string = deprecated(
+ "use set_source() with a PriceSource member, e.g. "
+ "price.set_source(PriceSource.FINANCE_QUOTE)")(_deprecated_set_source_string)
+
class GncPriceDB(GnuCashCoreClass):
'''
diff --git a/bindings/python/tests/test_price_and_wrapping.py b/bindings/python/tests/test_price_and_wrapping.py
index acee15b229..cb60831ba3 100644
--- a/bindings/python/tests/test_price_and_wrapping.py
+++ b/bindings/python/tests/test_price_and_wrapping.py
@@ -488,5 +488,52 @@ class TestPriceSourceEnum(TestCase):
ses.end()
+# ---------------------------------------------------------------------------
+# Test: GncPrice.set_source_string -- deprecated, but still guards (raises on
+# an unrecognized source) during the deprecation period
+# ---------------------------------------------------------------------------
+class TestSetSourceStringGuard(PriceSession):
+ """set_source_string() is deprecated in favour of set_source(PriceSource.*),
+ but while it exists it must fail loud on an unrecognized source string
+ instead of silently leaving the source unchanged (the C setter no-ops).
+ These tests ignore the DeprecationWarning and check the guard behaviour;
+ the warning itself is covered by test_emits_deprecation_warning."""
+
+ def setUp(self):
+ super().setUp()
+ # These tests deliberately call the deprecated method.
+ self._warn_ctx = warnings.catch_warnings()
+ self._warn_ctx.__enter__()
+ warnings.simplefilter("ignore", DeprecationWarning)
+
+ def tearDown(self):
+ self._warn_ctx.__exit__(None, None, None)
+ super().tearDown()
+
+ def test_canonical_source_is_accepted(self):
+ self.price1.set_source_string("Finance::Quote")
+ self.assertEqual(self.price1.get_source_string(), "Finance::Quote")
+
+ def test_unknown_source_on_fresh_price_raises(self):
+ price = GncPrice(self.book)
+ with self.assertRaises(ValueError):
+ price.set_source_string("not-a-real-source")
+
+ def test_unknown_source_does_not_clobber_existing(self):
+ # The C setter no-ops on an unknown string; on a price that already has
+ # a valid source that leaves the old value in place (so a bare "is the
+ # source INVALID now?" check would miss it). The guard must still raise.
+ self.price1.set_source_string("Finance::Quote")
+ with self.assertRaises(ValueError):
+ self.price1.set_source_string("totally-bogus")
+ self.assertEqual(self.price1.get_source_string(), "Finance::Quote")
+
+ def test_emits_deprecation_warning(self):
+ with warnings.catch_warnings():
+ warnings.simplefilter("error", DeprecationWarning)
+ with self.assertRaises(DeprecationWarning):
+ self.price1.set_source_string("Finance::Quote")
+
+
if __name__ == '__main__':
main()
diff --git a/gnucash/import-export/qif-imp/qif-to-gnc.scm b/gnucash/import-export/qif-imp/qif-to-gnc.scm
index 41a1164a77..b2d1ffa844 100644
--- a/gnucash/import-export/qif-imp/qif-to-gnc.scm
+++ b/gnucash/import-export/qif-imp/qif-to-gnc.scm
@@ -1438,7 +1438,7 @@
(gnc-price-begin-edit gnc-price)
(gnc-price-set-commodity gnc-price commodity)
(gnc-price-set-currency gnc-price default-currency)
- (gnc-price-set-source-string gnc-price "user:price")
+ (gnc-price-set-source gnc-price PRICE-SOURCE-USER-PRICE)
;; other options for type are "last" or "nav" which are
;; the last known price for a stock or the net asset value
Summary of changes:
bindings/engine.i | 9 +++++
bindings/guile/test/test-engine-extras.scm | 1 -
bindings/python/deprecation.py | 6 +--
bindings/python/gnucash_core.py | 33 ++++++++++++++---
bindings/python/tests/test_price_and_wrapping.py | 47 ++++++++++++++++++++++++
gnucash/import-export/qif-imp/qif-to-gnc.scm | 2 +-
6 files changed, 87 insertions(+), 11 deletions(-)
More information about the gnucash-changes
mailing list