Ticket #153 (closed defect: fixed)

Opened 6 years ago

Last modified 6 years ago

Incompatible non-empty rpm.mi boolean value change in 4.8.0, len/count() issue


Reported by: scop Assigned to: pmatilai Priority: major Milestone:
Component: rpm-python Version: RPM Development Keywords: Cc:


Description

The following script demonstrates what I think are two problems with non-empty rpm.mi boolean value and len/count():

import rpm
ts = rpm.TransactionSet()
mi = ts.dbMatch()
mi.pattern("name", rpm.RPMMIRE_GLOB, "r*")
if mi:
    print "mi true"
else:
    print "mi false"
try:
    print "len: %d" % len(mi)
except:
    pass
print "count(): %d" % mi.count()
c = 0
for m in mi:
    c += 1
print "real: %d" % c

With 4.4.2.3 on CentOS 5 I get:

mi true
count(): 0
real: 15

With 4.7.2 on Fedora 12 I get:

mi true
count(): 0
real: 37

With 4.8.0 on Fedora 13 I get:

mi false
len: 0
count(): 0
real: 25

Observations:

  • The boolean value of non-empty mi changed incompatibly between 4.7.2 and 4.8.0 (breaks for example installed package globbing in rpmlint)
  • I think both mi.count() and len(mi) are (and have been) somehow broken in this case, they should return the same number as the "real" IMO but return 0

On the other hand, mi's returned from for example ts.dbMatch("name", "rpm") behave like I'd expect in all these versions, both truth value and len/count() wise.

Change History

03/20/10 10:42:46 changed by pmatilai

Hmm, the behavior change here is not intentional, I'll need to check where that comes from. The python bindings saw quite a churn between 4.7.x and 4.8.x so, its more surprising that there has been so few (reported) breakages than the other way around :)

The iterator count has always been rather broken (on C-level too): it only works on exact matches against index tags. Eg:

mi = ts.dbMatch('name') mi.count()

0

mi = ts.dbMatch('name', 'kernel') mi.count()

3

03/20/10 11:39:54 changed by pmatilai

  • owner changed from RpmTickets to pmatilai.
  • status changed from new to assigned.

Right... this is the cause: http://docs.python.org/library/stdtypes.html#truth-value-testing

instances of user-defined classes, if the class defines a nonzero() or len() method, when that method returns the integer zero or bool value False.

Now that the iterator implements __len__(), that's what gets used for truth value whereas any mi instance previously always returned True, just like "foo = object()" evals to True. Reverting to former behavior is easily achieved by adding __nonzero__() which always returns True, which is probably the less surprising behavior, considering how unusable the __len__() method is due to its unreliability.

03/21/10 20:46:49 changed by scop

Thanks for looking into this. Let me know if you find a "fix" and intend to ship it for Fedora 13 - I have a trivial fix for this already in rpmlint svn but won't bother shipping an update for this purpose if you intend to push a rpm update.

03/24/10 08:20:29 changed by pmatilai

  • status changed from assigned to closed.
  • resolution set to fixed.

Okay, fixed now: https://rpm.org/gitweb?p=rpm.git;a=commitdiff;h=40f788a7bf3741f9c613ff302d4e1b0ceec2658c

This is not actually 100% identical behavior to pre-4.8.0 which returned True no matter what, whereas now the truth value actually sorta means something (you get False when it knows there are no matches at all)

On the Fedora-side of things: fixed now in rawhide and will pull to F13 in near future, there are a few other fixes pending for 13 too.