This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Is there a way to provide destructor for module written using C API?
Type: Stage: resolved
Components: C API Versions: Python 3.11, Python 3.10, Python 3.9
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: lukasz.langa, lycantropos, miss-islington, petr.viktorin, vstinner
Priority: normal Keywords: patch

Created on 2021-06-03 16:13 by lycantropos, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 27581 merged petr.viktorin, 2021-08-03 15:37
PR 27596 merged miss-islington, 2021-08-04 18:02
PR 27597 merged miss-islington, 2021-08-04 18:02
Messages (6)
msg395012 - (view) Author: Azat Ibrakov (lycantropos) Date: 2021-06-03 16:13
I'm reimplementing `fractions.Fraction` class using C API (https://github.com/lycantropos/cfractions).

And the problem is that I want to use `numbers.Rational` interface in my type checks to add support for user-defined rational numbers.

I see how it's done for `decimal.Decimal` class:
https://github.com/python/cpython/blob/142e5c5445c019542246d93fe2f9e195d3131686/Modules/_decimal/_decimal.c#L2916
but the problem is: I don't see when/where we call `Py_DECREF(Rational)`, so it looks like this class will not be "freed" until the  end of the program.

So my question is: is there any way to define some function which will be called once module is not used?
msg395013 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2021-06-03 16:19
Hi, you should use the multiphase initialization API which has clear and free functions.
https://www.python.org/dev/peps/pep-0489/#the-proposal

See for example the source code of the Modules/_abc.c extension.
msg395034 - (view) Author: Azat Ibrakov (lycantropos) Date: 2021-06-03 19:04
With this setup
https://gist.github.com/lycantropos/f9243dc98e104a13ddd991316e93d31a
I get prompt about module being initialized but that's it: it never gets deleted and reference count for `Rational` keeps increasing. What am I missing?
msg398826 - (view) Author: Petr Viktorin (petr.viktorin) * (Python committer) Date: 2021-08-03 13:29
You are missing m_free.
The clear function is used to break reference counts. In this case, there are no reference counts to be broken, so it is not called.

Your custom_clear function is idempotent, so you can use it in both free and clear and let Python call it either once or twice:
    .m_clear = custom_clear,
    .m_free = custom_clear,

I agree that this is not at all clear from the documentation. I'm going to spend some time organizing the info around the GC API and writing it up.
msg398929 - (view) Author: Łukasz Langa (lukasz.langa) * (Python committer) Date: 2021-08-04 18:24
Thanks for your report, Azat! ✨ 🍰 ✨
msg398979 - (view) Author: Petr Viktorin (petr.viktorin) * (Python committer) Date: 2021-08-05 09:20
I see that I wrote "counts" rather than "cycles" before; that line should be:

   The clear function is used to break reference cycles. In this case, there are no reference cycles to be broken, so it is not called.



Thanks to Pablo for the review & Łukasz for the merges!
History
Date User Action Args
2022-04-11 14:59:46adminsetgithub: 88467
2021-08-05 09:20:08petr.viktorinsetmessages: + msg398979
2021-08-04 18:24:59lukasz.langasetnosy: + lukasz.langa
messages: + msg398929
2021-08-04 18:24:37lukasz.langasetstatus: open -> closed
stage: patch review -> resolved
resolution: fixed
versions: + Python 3.10, Python 3.11
2021-08-04 18:02:23miss-islingtonsetpull_requests: + pull_request26098
2021-08-04 18:02:15miss-islingtonsetnosy: + miss-islington
pull_requests: + pull_request26097
2021-08-03 15:37:22petr.viktorinsetkeywords: + patch
stage: patch review
pull_requests: + pull_request26085
2021-08-03 13:29:45petr.viktorinsetnosy: + petr.viktorin
messages: + msg398826
2021-06-04 21:00:18terry.reedysetversions: - Python 3.6, Python 3.7, Python 3.8
2021-06-03 19:04:06lycantropossetmessages: + msg395034
2021-06-03 16:19:54vstinnersetnosy: + vstinner
messages: + msg395013
2021-06-03 16:13:29lycantroposcreate