Repository navigation
Open
Description
Description
__construct_mixin_classes is quite brittle. It would be better if each subpackage could register into __construct_mixin_classes. To prevent weird import-order issues, maybe this could use entry points.
Additional context
astropy/astropy/table/serialize.py
Lines 25 to 57 in 0f896a7
| __construct_mixin_classes = ( | |
| 'astropy.time.core.Time', | |
| 'astropy.time.core.TimeDelta', | |
| 'astropy.units.quantity.Quantity', | |
| 'astropy.units.function.logarithmic.Magnitude', | |
| 'astropy.units.function.logarithmic.Decibel', | |
| 'astropy.units.function.logarithmic.Dex', | |
| 'astropy.coordinates.angles.Latitude', | |
| 'astropy.coordinates.angles.Longitude', | |
| 'astropy.coordinates.angles.Angle', | |
| 'astropy.coordinates.distances.Distance', | |
| 'astropy.coordinates.earth.EarthLocation', | |
| 'astropy.coordinates.sky_coordinate.SkyCoord', | |
| 'astropy.table.ndarray_mixin.NdarrayMixin', | |
| 'astropy.table.table_helpers.ArrayWrapper', | |
| 'astropy.table.column.Column', | |
| 'astropy.table.column.MaskedColumn', | |
| 'astropy.coordinates.representation.CartesianRepresentation', | |
| 'astropy.coordinates.representation.UnitSphericalRepresentation', | |
| 'astropy.coordinates.representation.RadialRepresentation', | |
| 'astropy.coordinates.representation.SphericalRepresentation', | |
| 'astropy.coordinates.representation.PhysicsSphericalRepresentation', | |
| 'astropy.coordinates.representation.CylindricalRepresentation', | |
| 'astropy.coordinates.representation.CartesianDifferential', | |
| 'astropy.coordinates.representation.UnitSphericalDifferential', | |
| 'astropy.coordinates.representation.SphericalDifferential', | |
| 'astropy.coordinates.representation.UnitSphericalCosLatDifferential', | |
| 'astropy.coordinates.representation.SphericalCosLatDifferential', | |
| 'astropy.coordinates.representation.RadialDifferential', | |
| 'astropy.coordinates.representation.PhysicsSphericalDifferential', | |
| 'astropy.coordinates.representation.CylindricalDifferential', | |
| 'astropy.utils.masked.core.MaskedNDArray', | |
| ) |
Activity
nstarman commentedon Sep 17, 2022
With entry points we don't have to import any other package if the information is encoded in the entry point itself.
And we can filter to only select ones from known packages, like
astropy, andastropy-healpix(I made up the
HEALlPixRepresentation).taldcroft commentedon Sep 19, 2022
I have a custom subclass of
Timethat I want to be able to serialize as a trusted mixin class. Do you have an idea for how we could support that with entry points? Right now I am just inserting my custom class name into the existing list, which is certainly not ideal.nstarman commentedon Sep 19, 2022
My suggestion for entry points should work for 3rd party libraries if we want to open it up, right?
In your library's
pyproject.tomladdin
astropy/astropy/table/serialize.pywe'd do something like (I haven't worked out the details in https://docs.python.org/3/library/importlib.metadata.html)Notes:
path.to:class, notpath.to.classand change howtabledeals with the str.try: Except:protections toentry_point_functaldcroft commentedon Sep 19, 2022
And despite having expressed a desire for allowing 3rd party classes, now I'm wondering if this exposes a security risk in allowing arbitrary code to be executed if:
So this is a 2-factor attack requiring both a package and a data file. Maybe we could have a configuration setting to opt-in to allowing external classes?
mhvk commentedon Sep 19, 2022
I like the idea of using entry points. To reduce the security risk, we could have a white list of packages that are allowed (just
astropyby default), and warn if a class is attempted to be written or read from a non-whitelisted package (with instructions on how to fix that).p.s. I guess for one-off, if we keep the
__construct_mixin_classesset, one can just continue to hack that.taldcroft commentedon Sep 19, 2022
I'm not super-excited about a design that pretty much requires suppressing a warning. At some level maybe all we need to guard against is astropy automatically importing a 3rd party package that the user has not already imported. From a security perspective as soon as you do that import then it's game over.
So this goes back to a configuration variable which is the user-defined allow list. Maybe with that we can automatically trust any class within the astropy namespace (i.e. all the entry points that start with
astropy.)? Then my subclass module would tell astropy to trust it by adding the class to that configuration setting. Again this is taking the approach that once a user has specifically imported a package then it must be trusted because arbitrary code can run on import.mhvk commentedon Sep 19, 2022
Note that I wanted the warning only if a class was actually attempted to be used, so most people would never see it.
That said, I like the idea of the user having imported a package being sufficient. Probably still needs a warning if a class is encountered that is an entry point of a package that is not yet imported.
taldcroft commentedon Sep 19, 2022
I was thinking that if the class is not in the configuration allowed list then encountering that class while constructing a table would be an exception. So it either works (silently) or raises an exception. This would be independent of import. E.g.
Doing
from cxotime import CxoTimewould probably do the same configuration update, but it would not be required if the user set themixin_class_allow_listthemselves.@mhvk - were you thinking something different?
p.s. and I remembered that "allow list" and "block list" are the preferred terms now.
mhvk commentedon Sep 19, 2022
@taldcroft - sorry, yes, not having the class in the whitelist should just raise, not warn! I guess really what I meant was that the exception message could depend on whether there is an entry point for the class.
nstarman commentedon Sep 19, 2022
Just dropping in a note, https://packaging.python.org/en/latest/specifications/entry-points/#data-model
The name of the entry point can contain dots and dashes and underscores, so we can encode information not just in the value of the entry point, but also the name. I'm thinking this is useful for backward compatibility, like when a class is moved. We can use the entry point as a mapping of the old location to the new. And then we can have pytests that will pick up on the deprecations, so they are cleaned up after an appropriate period.
samaloney commentedon Apr 22, 2026
We just ran into something similar in sunpy, it would be handy to have a minimal way to register subclasses rather than hacking
__attributes as in sunpy/sunpy#8548neutrinoceros commentedon Apr 23, 2026
another note from 2026 (in the midst of the rise of free-threading): any kind of global registry would require to be designed with thread safety in mind from the get go.
I could probably take this on at some point since it looks like there is still a need for it.