-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use property()
& implement Abstract Base Class PangoObject
#47
Conversation
First of all, great work! I do like the PangoObject refactoring. I've ran the GitHub Actions just to see if the tests would run. Looks like there's a few issues that need to be fixed.
(On another note, I really should split linting and tests into two different GitHub Action workflows) I've also checked out the code on my machine as well and I can replicate the segfault errors you mentioned. I've not looked too closely at the new pointer logic, but I'm only guessing it's because a PangoObject is being freed when it's not supposed to be. Unrelated to the SegFault stuff, I also noticed you fixed a typo made by a contributor in the |
yeah, i saw the i'll try to see if i can figure out why the segfault is happening, even though i don't have a lot of experience with C haha; the pointer logic really shouldn't be any different from the pre-existing classes, but it's probably a small detail that i missed. i'll also fix the linting issues; i ran i noticed the weird error when copying a Color, but i forgot to mention it. it does seem like i also see another test case that asserts that a NotImplementedError is raised in |
some updates:
from pangocffi import ffi, pango
color = ffi.new("PangoColor *")
color.red = 55
color.green = 155
color.blue = 255
copy = pango.pango_color_copy(color)
print(color.blue, copy.blue) # 255, 0 in addition to that, other methods like spec = ffi.new("char[]", "#102030".encode("utf8"))
new_color = ffi.new("PangoColor *")
pango.pango_color_parse(new_color, spec)
print(new_color.blue, ffi.string(pango.pango_color_to_string(new_color))) # 0, b"#101020203030"
if i comment these function calls out (e.g. |
Yeah, I think manually creating a new
Yeah, I think you are right, returning false should be fine. Just update the test to check |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi there! I spent some time trying to find the SegFault error and I believe I found the issue.
Basically it appears the _GC_METHOD
for color.py
and glyph_item_iter.py
are not required. Don't ask me why it's not required, but that's the way I set it up originally in master apparently.
I've also left some comments suggesting some changes which should fix some of the other tests and also increase code coverage a tiny bit.
There are also a few lines of code that need changing, but annoyingly GitHub doesn't allow me to comment on them directly. So here's a list:
- In
test_attributes.py
modify line 75 to readmarkup_texts = ('pango.apply_markup(\'...\')', 'Attribute.from_shape()')
(i.e. s/set_markup/apply_markup) - In
test_attr_list.py
modify line 72 to readassert a != 2
- In
test_attribute.py
modify line 263 to readassert a != 6
All these changes pass on my machine, so hopefully it'll pass in the GitHub Actions as well.
thank you so much for finding the issue! i spent some time messing with the classes and GC methods but it was pretty confusing so i couldn't get it to work, and i haven't had a lot of time during the week. i'd actually implemented the three small fixes you said you couldn't comment on, but completely forgot to commit/push them! also, i fixed the copy method, but directly modified i hope everything's alright now, and i'm very sorry for the messy PR and amount of commits. the segfault when testing really hindered my ability to... you know... test the code, so i kind of just trusted myself. i'll make sure to be more careful when contributing further :) |
Ran the checks again... Looks like one more change is required. (Hopefully 😅) I think testing def __eq__(self, other) -> bool:
if isinstance(other, PangoObject):
return bool(
pango.pango_attr_list_equal(self.pointer, other.pointer)
)
return False The alternative is to change the test to assert |
you're right! while thinking of the concept of if self._EQ_METHOD:
return bool(self._EQ_METHOD(self.pointer, other.pointer))
else:
return self.pointer == other.pointer and considering that most classes don't have an |
Codecov ReportBase: 99.27% // Head: 99.25% // Decreases project coverage by
Additional details and impacted files@@ Coverage Diff @@
## master #47 +/- ##
==========================================
- Coverage 99.27% 99.25% -0.02%
==========================================
Files 18 19 +1
Lines 965 940 -25
==========================================
- Hits 958 933 -25
Misses 7 7
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. ☔ View full report at Codecov. |
Hmm, I think this can all be improved by flipping the order of operations. In other words, check for pointer equality first, then use the def __eq__(self, other) -> bool:
if isinstance(other, PangoObject):
if self.pointer == other.pointer:
return True
if self._EQ_METHOD:
return bool(self._EQ_METHOD(self.pointer, other.pointer))
return False and remove the override if That way, all PangoObjects correctly do pointer comparisons regardless of whether the object has Other than that, I think this is good for merging. Coverage is going down by a tiny percentage, but that's okay. At the end of the day it's still 99% 😂 |
sure, that makes sense! but won't adding |
Yep, you're right, I forgot about that! 🤦 So yeah, keep the override in |
coverage is now |
I think a lower code coverage was always inevitable because you refactored redundant code neatly into But this all looks great. I'll get this merged in a few minutes (unless you have any last minute additions) and I'll prepare a new release today if possible. I'll also be updating Thanks again for this contribution, I really appreciate the amount of work that went the refactoring all the objects into |
thank you too! this was a nice experience and i'll probably make a PR to implement more classes from the Pango API soon. :) |
hey! this PR closes #44. i ended up going with
property()
since i completely agree that it ties the methods better, buuut i decided to keep@property
for read-only properties, since otherwise it's unnecessarily verbose.while writing this simple-ish PR, though, i realized that there was a lot of repetition between every single class, as they all need to interact with the underlying C APIs and pointers... so i created an abstract base class:
PangoObject
. this class implements the following methods/members, which removes a lot of repetition:__init__()
pointer
_init_pointer()
from_pointer()
copy()
/_copy_()
/__deepcopy_()
__eq__()
__repr__()
it works by utilizing these abstract properties, which are supposed to be provided by its subclasses:
_INIT_METHOD
-- a CFFI function that initializes the object (i.e.pango.pango_..._new()
), alternatively,ffi.new
_INIT_CLASS
-- only if the method is set toffi.new
, a string representing the classname to initialize (e.g."PangoLayout")
_GC_METHOD
-- a CFFI function that frees the object (i.e.pango.pango_..._free()
)_COPY_METHOD
-- a CFFI function that copies the object (i.e.pango.pango_..._copy()
)_EQ_METHOD
-- a CFFI function that compares the object with another (i.e.pango.pango_..._equals()
)all of these are optional, and every base method is enabled or modified depending on these (i.e.,
__init__()
will error if there's no_INIT_...
properties;gc: bool
will be disabled if there's no_GC_METHOD
; comparisons (=
) will directly use pointers if an_EQ_METHOD
isn't provided, etc.) of course, these base methods can still be overwritten like in the case ofColor#__eq__()
.i'm sorry if this is kind of a sudden change, but it would've been pointless to make a PR that basically rewrites every class, to then make another one that rewrites them over again, and the current structure really needed a base class like this one. i believe the overall concept is good, but please let me know if there are any implementation details you'd like to change.
i updated all of the tests to conform to the changes and they should all be passing, but for some reason i'm geting seemingly random memory management errors (
Access violation
/Segmentation fault
) only when running the test suite (if i run the same functions from a simple test file nothing happens), and the errors happen on code that's basically untouched (get_iter()
->pango_layout_get_iter
;apply_markup()
->pango_layout_set_markup
). i'll try to see what's causing it because i'm not even sure if it has to do with my machine or what.