Skip to content

Fix deepcopy/pickle of CRS subclasses created from WKT - #2727

Merged
greglucas merged 1 commit into
SciTools:mainfrom
DavidVadnais:fix-#2571-deepcopy-NaturalEarthFeature
Sep 4, 2026
Merged

Fix deepcopy/pickle of CRS subclasses created from WKT#2727
greglucas merged 1 commit into
SciTools:mainfrom
DavidVadnais:fix-#2571-deepcopy-NaturalEarthFeature

Conversation

@DavidVadnais

Copy link
Copy Markdown
Contributor

Rationale

Fixes: #2571

The code to exercise:

import copy
import cartopy.crs as ccrs
from pyproj import CRS

copy.deepcopy(ccrs.Projection(CRS.from_epsg(4326)))

Before fix

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[1], line 5
      2 import cartopy.crs as ccrs
      3 from pyproj import CRS
----> 5 copy.deepcopy(ccrs.Projection(CRS.from_epsg(4326)))

File ~/micromamba/envs/pycodas/lib/python3.11/copy.py:172, in deepcopy(x, memo, _nil)
    170                 y = x
    171             else:
--> 172                 y = _reconstruct(x, memo, *rv)
    174 # If is its own copy, don't memoize.
    175 if y is not x:

File ~/micromamba/envs/pycodas/lib/python3.11/copy.py:265, in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    263 if deep and args:
    264     args = (deepcopy(arg, memo) for arg in args)
--> 265 y = func(*args)
    266 if deep:
    267     memo[id(x)] = y

File ~/project/cartopy/lib/cartopy/crs.py:670, in Projection.__init__(self, *args, **kwargs)
    669 def __init__(self, *args, **kwargs):
--> 670     super().__init__(*args, **kwargs)
    671     self.bounds = None
    672     if self.area_of_use:
    673         # Convert lat/lon bounds to projected bounds.
    674         # Geographic area of the entire dataset referenced to WGS 84
    675         # NB. We can't use a polygon transform at this stage because
    676         # that relies on the existence of the map boundary... the very
    677         # thing we're trying to work out! ;-)

TypeError: CRS.__init__() missing 1 required positional argument: 'proj4_params'

After Fix

Out[1]:
<Geographic 2D CRS: EPSG:4326>
Name: WGS 84
Axis Info [ellipsoidal]:
- Lat[north]: Geodetic latitude (degree)
- Lon[east]: Geodetic longitude (degree)
Area of Use:
- name: World.
- bounds: (-180.0, -90.0, 180.0, 90.0)
Datum: World Geodetic System 1984 ensemble
- Ellipsoid: WGS 84
- Prime Meridian: Greenwich

Implications

__new__ skips __init__, so any __init__ side effects run only from __setstate__ (which calls CRS.__init__).

@DavidVadnais

Copy link
Copy Markdown
Contributor Author

I think rerunning the job should fix this but I'm not certain.

@greglucas
greglucas merged commit fa088ea into SciTools:main Sep 4, 2026
38 of 39 checks passed
@greglucas

Copy link
Copy Markdown
Contributor

Thanks @DavidVadnais!

@QuLogic QuLogic added this to the 0.26 milestone Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

deepcopy of NaturalEarthFeature fails on some machines

3 participants