[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.
This commit is contained in:
Noerr authored and John Ralls committed 2026-09-25 16:05:19 -07:00
1 parent 973a64ceda
commit 0dc41c1212
6 files changed
+87 -11

No files matched your search

+9
View File
@@ -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
@@ -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)
+3 -3
View File
@@ -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)
+27 -6
View File
@@ -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):
'''
@@ -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()
+1 -1
View File
@@ -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