pyproj: CRS comparison no longer equal with pyproj 3.2

Code Sample, a copy-pastable example if possible

A “Minimal, Complete and Verifiable Example” will make it much easier for maintainers to help you: http://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports

from pyproj import CRS
proj_str = "+proj=omerc +lat_0=50 +alpha=50.0 +no_rot +a=6378144.0 +b=6356759.0 +lon_0=8.0"
crs = CRS.from_string(proj_str)

crs == CRS(crs.to_wkt())
# False

crs == CRS(crs.to_wkt("WKT1_GDAL"))
# True

Extra context:

crs.to_wkt()
# 'PROJCRS["unknown",BASEGEOGCRS["unknown",DATUM["unknown",ELLIPSOID["unknown",6378144,298.253168108487,LENGTHUNIT["metre",1,ID["EPSG",9001]]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8901]]],CONVERSION["unknown",METHOD["PROJ omerc no_rot"],PARAMETER["lat_0",50,ANGLEUNIT["degree",0.0174532925199433,ID["EPSG",9122]]],PARAMETER["alpha",50,ANGLEUNIT["degree",0.0174532925199433,ID["EPSG",9122]]],PARAMETER["lon_0",8,ANGLEUNIT["degree",0.0174532925199433,ID["EPSG",9122]]]],CS[Cartesian,2],AXIS["(E)",east,ORDER[1],LENGTHUNIT["metre",1,ID["EPSG",9001]]],AXIS["(N)",north,ORDER[2],LENGTHUNIT["metre",1,ID["EPSG",9001]]],REMARK["PROJ CRS string: +proj=omerc +lat_0=50 +alpha=50.0 +no_rot +a=6378144.0 +b=6356759.0 +lon_0=8.0"]]'

CRS(crs.to_wkt()).to_wkt()
# 'PROJCRS["unknown",BASEGEOGCRS["unknown",DATUM["unknown",ELLIPSOID["unknown",6378144,298.253168108487,LENGTHUNIT["metre",1,ID["EPSG",9001]]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8901]]],CONVERSION["unknown",METHOD["PROJ omerc no_rot"],PARAMETER["lat_0",50,ANGLEUNIT["degree",0.0174532925199433,ID["EPSG",9122]]],PARAMETER["alpha",50,ANGLEUNIT["degree",0.0174532925199433,ID["EPSG",9122]]],PARAMETER["lon_0",8,ANGLEUNIT["degree",0.0174532925199433,ID["EPSG",9122]]]],CS[Cartesian,2],AXIS["(E)",east,ORDER[1],LENGTHUNIT["metre",1,ID["EPSG",9001]]],AXIS["(N)",north,ORDER[2],LENGTHUNIT["metre",1,ID["EPSG",9001]]],REMARK["PROJ CRS string: +proj=omerc +lat_0=50 +alpha=50.0 +no_rot +a=6378144.0 +b=6356759.0 +lon_0=8.0"]]'

crs.to_wkt() == CRS(crs.to_wkt()).to_wkt()
# True

Problem description

In older versions of pyproj/PROJ this equality used to work fine. This conversion to/from WKT is something we do in pyresample to support older versions of pyproj where CRS/Proj objects were not thread-safe.

Expected Output

The two versions of the CRS are considered equal. I’m not sure the easiest way to find out why they are unequal since the WKT is the same.

Environment Information

  • Output from: pyproj -v
pyproj info:
    pyproj: 3.2.1
      PROJ: 8.1.1
  data dir: /home/davidh/miniconda3/envs/satpy_py39/share/proj
user_data_dir: /home/davidh/.local/share/proj

System:
    python: 3.9.7 | packaged by conda-forge | (default, Sep 14 2021, 01:17:55)  [GCC 9.4.0]
executable: /home/davidh/miniconda3/envs/satpy_py39/bin/python
   machine: Linux-5.13.0-7614-generic-x86_64-with-glibc2.33

Python deps:
   certifi: 2021.05.30
       pip: 21.2.4
setuptools: 58.0.4
    Cython: None

Installation method

  • conda with conda-forge packages

Conda environment information (if you installed with conda):


Environment (conda list):
$ conda list proj
# packages in environment at /home/davidh/miniconda3/envs/satpy_py39:
#
# Name                    Version                   Build  Channel
proj                      8.1.1                h277dcde_2    conda-forge
pyproj                    3.2.1            py39ha81a305_2    conda-forge

Details about conda and system ( conda info ):
$ conda info

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 19 (19 by maintainers)

Most upvoted comments

Ok new discovery, PROJ 8.1.1 seems to now include a “REMARK” in the WKT and it seems this effects comparison results. However, it is very touchy. For example, not only does the order of the dictionary parameters matter (since they python dicts are ordered now), but also floats versus ints in the numeric parameters.

from pyproj import CRS
proj_str = "+proj=omerc +lat_0=50 +alpha=50.0 +no_rot +a=6378144.0 +b=6356759.0 +lon_0=8.0"
crs = CRS.from_string(proj_str)

CRS(crs.to_wkt()) == CRS(CRS({'proj': 'omerc', 'a': 6378144.0, 'b': 6356759.0, 'lat_0': 50.0, 'lon_0': 8.0, 'alpha': 50.0, 'no_rot': True}).to_wkt())


CRS(CRS({'proj': 'omerc', 'a': 6378144.0, 'b': 6356759.0, 'lat_0': 50.0, 'alpha': 50.0, 'lon_0': 8.0, 'no_rot': True}).to_wkt()).to_wkt()
# 'PROJCRS["unknown",BASEGEOGCRS["unknown",DATUM["unknown",ELLIPSOID["unknown",6378144,298.253168108487,LENGTHUNIT["metre",1,ID["EPSG",9001]]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8901]]],CONVERSION["unknown",METHOD["PROJ omerc no_rot"],PARAMETER["lat_0",50,ANGLEUNIT["degree",0.0174532925199433,ID["EPSG",9122]]],PARAMETER["alpha",50,ANGLEUNIT["degree",0.0174532925199433,ID["EPSG",9122]]],PARAMETER["lon_0",8,ANGLEUNIT["degree",0.0174532925199433,ID["EPSG",9122]]]],CS[Cartesian,2],AXIS["(E)",east,ORDER[1],LENGTHUNIT["metre",1,ID["EPSG",9001]]],AXIS["(N)",north,ORDER[2],LENGTHUNIT["metre",1,ID["EPSG",9001]]],REMARK["PROJ CRS string: +proj=omerc +a=6378144.0 +b=6356759.0 +lat_0=50.0 +alpha=50.0 +lon_0=8.0 +no_rot"]]'

CRS(crs.to_wkt()).to_wkt()
# 'PROJCRS["unknown",BASEGEOGCRS["unknown",DATUM["unknown",ELLIPSOID["unknown",6378144,298.253168108487,LENGTHUNIT["metre",1,ID["EPSG",9001]]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8901]]],CONVERSION["unknown",METHOD["PROJ omerc no_rot"],PARAMETER["lat_0",50,ANGLEUNIT["degree",0.0174532925199433,ID["EPSG",9122]]],PARAMETER["alpha",50,ANGLEUNIT["degree",0.0174532925199433,ID["EPSG",9122]]],PARAMETER["lon_0",8,ANGLEUNIT["degree",0.0174532925199433,ID["EPSG",9122]]]],CS[Cartesian,2],AXIS["(E)",east,ORDER[1],LENGTHUNIT["metre",1,ID["EPSG",9001]]],AXIS["(N)",north,ORDER[2],LENGTHUNIT["metre",1,ID["EPSG",9001]]],REMARK["PROJ CRS string: +proj=omerc +lat_0=50 +alpha=50.0 +no_rot +a=6378144.0 +b=6356759.0 +lon_0=8.0"]]'

CRS(crs.to_wkt()) == CRS(CRS({'proj': 'omerc', 'lat_0': 50, 'alpha': 50.0, 'no_rot': True, 'a': 6378144.0, 'b': 6356759.0, 'lon_0': 8.0}).to_wkt())
# True

The CI jobs just started failing on pyresample. I made a PR pass all CI on Friday and updated it today and it started failing.

Looks like the Friday job that passed was using pyproj 3.2.1 (build 1) and proj 8.1.0 from conda-forge. New job that fails is using pyproj 3.2.1 (build 2) and proj 8.1.1. However, I have an even older environment on my system where my unit test passes but my example code in this issue fails (the == is false). Let me try coming up with a more accurate example snippet. I’ll also try downgrading proj to 8.1.0 and see if that fixes things.