morecantile 5.1.0__tar.gz → 5.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. {morecantile-5.1.0 → morecantile-5.2.1}/.bumpversion.cfg +1 -1
  2. {morecantile-5.1.0 → morecantile-5.2.1}/PKG-INFO +1 -1
  3. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/__init__.py +1 -1
  4. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/models.py +61 -47
  5. {morecantile-5.1.0 → morecantile-5.2.1}/.gitignore +0 -0
  6. {morecantile-5.1.0 → morecantile-5.2.1}/.pre-commit-config.yaml +0 -0
  7. {morecantile-5.1.0 → morecantile-5.2.1}/LICENSE +0 -0
  8. {morecantile-5.1.0 → morecantile-5.2.1}/README.md +0 -0
  9. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/commons.py +0 -0
  10. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/data/CDB1GlobalGrid.json +0 -0
  11. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/data/CanadianNAD83_LCC.json +0 -0
  12. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/data/EuropeanETRS89_LAEAQuad.json +0 -0
  13. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/data/GNOSISGlobalGrid.json +0 -0
  14. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/data/LINZAntarticaMapTilegrid.json +0 -0
  15. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/data/NZTM2000Quad.json +0 -0
  16. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/data/README.md +0 -0
  17. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/data/UPSAntarcticWGS84Quad.json +0 -0
  18. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/data/UPSArcticWGS84Quad.json +0 -0
  19. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/data/UTM31WGS84Quad.json +0 -0
  20. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/data/WGS1984Quad.json +0 -0
  21. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/data/WebMercatorQuad.json +0 -0
  22. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/data/WorldCRS84Quad.json +0 -0
  23. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/data/WorldMercatorWGS84Quad.json +0 -0
  24. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/defaults.py +0 -0
  25. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/errors.py +0 -0
  26. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/py.typed +0 -0
  27. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/scripts/__init__.py +0 -0
  28. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/scripts/cli.py +0 -0
  29. {morecantile-5.1.0 → morecantile-5.2.1}/morecantile/utils.py +0 -0
  30. {morecantile-5.1.0 → morecantile-5.2.1}/pyproject.toml +0 -0
@@ -1,5 +1,5 @@
1
1
  [bumpversion]
2
- current_version = 5.1.0
2
+ current_version = 5.2.1
3
3
  commit = True
4
4
  tag = True
5
5
  tag_name = {new_version}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: morecantile
3
- Version: 5.1.0
3
+ Version: 5.2.1
4
4
  Summary: Construct and use map tile grids (a.k.a TileMatrixSet / TMS).
5
5
  Keywords: GIS,TMS,TileMatrixSet,Map Tile
6
6
  Author-email: Vincent Sarago <vincent@developmentseed.com>
@@ -8,7 +8,7 @@ Refs:
8
8
 
9
9
  """
10
10
 
11
- __version__ = "5.1.0"
11
+ __version__ = "5.2.1"
12
12
 
13
13
  from .commons import BoundingBox, Coords, Tile # noqa
14
14
  from .defaults import TileMatrixSets, tms # noqa
@@ -6,6 +6,7 @@ import warnings
6
6
  from functools import cached_property
7
7
  from typing import Any, Dict, Iterator, List, Literal, Optional, Sequence, Tuple, Union
8
8
 
9
+ import pyproj
9
10
  from pydantic import (
10
11
  AnyHttpUrl,
11
12
  AnyUrl,
@@ -16,7 +17,6 @@ from pydantic import (
16
17
  field_validator,
17
18
  model_validator,
18
19
  )
19
- from pyproj import CRS, Transformer
20
20
  from pyproj.exceptions import CRSError, ProjError
21
21
 
22
22
  from morecantile.commons import BoundingBox, Coords, Tile
@@ -44,7 +44,7 @@ else:
44
44
  NumType = Union[float, int]
45
45
  BoundsType = Tuple[NumType, NumType]
46
46
  LL_EPSILON = 1e-11
47
- WGS84_CRS = CRS.from_epsg(4326)
47
+ WGS84_CRS = pyproj.CRS.from_epsg(4326)
48
48
  axesInfo = Annotated[List[str], Field(min_length=2, max_length=2)]
49
49
 
50
50
 
@@ -64,30 +64,28 @@ class CRSUri(BaseModel):
64
64
 
65
65
 
66
66
  class CRSWKT(BaseModel):
67
- """Coordinate Reference System (CRS) from WKT."""
67
+ """Coordinate Reference System (CRS) from WKT encoded as PROJJSON Object."""
68
68
 
69
69
  wkt: Annotated[
70
- str,
70
+ Dict,
71
71
  Field(
72
- description="Reference to one coordinate reference system (CRS) as WKT string",
73
- examples=[
74
- 'GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]',
75
- ],
72
+ description="An object defining the CRS using the JSON encoding for Well-known text representation of coordinate reference systems 2.0",
76
73
  ),
77
74
  ]
78
75
 
79
76
 
80
- # NOT SUPPORTED
81
- # class CRSRef(BaseModel):
82
- # """CRS from referenceSystem."""
83
- #
84
- # referenceSystem: Dict[str, Any] = Field(
85
- # ...,
86
- # description="A reference system data structure as defined in the MD_ReferenceSystem of the ISO 19115",
87
- # )
77
+ class CRSRef(BaseModel):
78
+ """CRS from referenceSystem."""
79
+
80
+ referenceSystem: Annotated[
81
+ Dict[str, Any],
82
+ Field(
83
+ description="A reference system data structure as defined in the MD_ReferenceSystem of the ISO 19115",
84
+ ),
85
+ ]
88
86
 
89
87
 
90
- class CRSType(RootModel[Union[str, Union[CRSUri, CRSWKT]]]):
88
+ class CRS(RootModel[Union[str, Union[CRSUri, CRSWKT, CRSRef]]]):
91
89
  """CRS model.
92
90
 
93
91
  Ref: https://github.com/opengeospatial/ogcapi-tiles/blob/master/openapi/schemas/common-geodata/crs.yaml
@@ -95,12 +93,25 @@ class CRSType(RootModel[Union[str, Union[CRSUri, CRSWKT]]]):
95
93
  Code generated using https://github.com/koxudaxi/datamodel-code-generator/
96
94
  """
97
95
 
98
- _pyproj_crs: CRS = PrivateAttr()
96
+ _pyproj_crs: pyproj.CRS = PrivateAttr()
99
97
 
100
98
  def model_post_init(self, __context: Any) -> None:
101
99
  """Post Init: Set private attr."""
102
100
  super().model_post_init(__context)
103
- self._pyproj_crs = CRS.from_user_input(self.root)
101
+
102
+ if isinstance(self.root, str):
103
+ self._pyproj_crs = pyproj.CRS.from_user_input(self.root)
104
+
105
+ elif isinstance(self.root, CRSUri):
106
+ self._pyproj_crs = pyproj.CRS.from_user_input(str(self.root.uri))
107
+
108
+ elif isinstance(self.root, CRSWKT):
109
+ self._pyproj_crs = pyproj.CRS.from_json_dict(self.root.wkt)
110
+
111
+ elif isinstance(self.root, CRSRef):
112
+ raise NotImplementedError(
113
+ "Morecantile does not support `MD_ReferenceSystem` defined CRS"
114
+ )
104
115
 
105
116
  @property
106
117
  def srs(self) -> str:
@@ -128,7 +139,11 @@ class CRSType(RootModel[Union[str, Union[CRSUri, CRSWKT]]]):
128
139
  return self._pyproj_crs.to_json(*args, **kwargs)
129
140
 
130
141
 
131
- def CRS_to_uri(crs: CRS) -> str:
142
+ # For compatibility
143
+ CRSType = CRS
144
+
145
+
146
+ def CRS_to_uri(crs: pyproj.CRS) -> str:
132
147
  """Convert CRS to URI."""
133
148
  authority = "EPSG"
134
149
  code = None
@@ -140,10 +155,11 @@ def CRS_to_uri(crs: CRS) -> str:
140
155
  # if we have a version number in the authority, split it out
141
156
  if "_" in authority:
142
157
  authority, version = authority.split("_")
158
+
143
159
  return f"http://www.opengis.net/def/crs/{authority}/{version}/{code}"
144
160
 
145
161
 
146
- def crs_axis_inverted(crs: CRS) -> bool:
162
+ def crs_axis_inverted(crs: pyproj.CRS) -> bool:
147
163
  """Check if CRS has inverted AXIS (lat,lon) instead of (lon,lat)."""
148
164
  return crs.axis_info[0].abbrev.upper() in ["Y", "LAT", "N"]
149
165
 
@@ -169,7 +185,7 @@ class TMSBoundingBox(BaseModel, arbitrary_types_allowed=True):
169
185
  Field(description="A 2D Point in the CRS indicated elsewhere"),
170
186
  ]
171
187
  crs: Annotated[
172
- Optional[CRSType],
188
+ Optional[CRS],
173
189
  Field(description="Coordinate Reference System (CRS)"),
174
190
  ] = None
175
191
  orderedAxes: Annotated[
@@ -252,17 +268,17 @@ class TileMatrix(BaseModel, extra="forbid"):
252
268
  Field(description="Cell size of this tile matrix"),
253
269
  ]
254
270
  cornerOfOrigin: Annotated[
255
- Optional[Literal["topLeft", "bottomLeft"]],
271
+ Literal["topLeft", "bottomLeft"],
256
272
  Field(
257
273
  description="The corner of the tile matrix (_topLeft_ or _bottomLeft_) used as the origin for numbering tile rows and columns. This corner is also a corner of the (0, 0) tile.",
258
274
  ),
259
- ] = None
275
+ ] = "topLeft"
260
276
  pointOfOrigin: Annotated[
261
277
  BoundsType,
262
278
  Field(
263
279
  description="Precise position in CRS coordinates of the corner of origin (e.g. the top-left corner) for this tile matrix. This position is also a corner of the (0, 0) tile. In previous version, this was 'topLeftCorner' and 'cornerOfOrigin' did not exist.",
264
280
  ),
265
- ] = None
281
+ ]
266
282
  tileWidth: Annotated[
267
283
  int,
268
284
  Field(
@@ -363,7 +379,7 @@ class TileMatrixSet(BaseModel, arbitrary_types_allowed=True):
363
379
  Field(description="Ordered list of names of the dimensions defined in the CRS"),
364
380
  ] = None
365
381
  crs: Annotated[
366
- CRSType,
382
+ CRS,
367
383
  Field(description="Coordinate Reference System (CRS)"),
368
384
  ]
369
385
  wellKnownScaleSet: Annotated[
@@ -382,9 +398,9 @@ class TileMatrixSet(BaseModel, arbitrary_types_allowed=True):
382
398
  ]
383
399
 
384
400
  # Private attributes
385
- _geographic_crs: CRS = PrivateAttr(default=WGS84_CRS)
386
- _to_geographic: Transformer = PrivateAttr()
387
- _from_geographic: Transformer = PrivateAttr()
401
+ _geographic_crs: pyproj.CRS = PrivateAttr(default=WGS84_CRS)
402
+ _to_geographic: pyproj.Transformer = PrivateAttr()
403
+ _from_geographic: pyproj.Transformer = PrivateAttr()
388
404
 
389
405
  def __init__(self, **data):
390
406
  """Set private attributes."""
@@ -393,10 +409,10 @@ class TileMatrixSet(BaseModel, arbitrary_types_allowed=True):
393
409
  self._geographic_crs = data.get("_geographic_crs", WGS84_CRS)
394
410
 
395
411
  try:
396
- self._to_geographic = Transformer.from_crs(
412
+ self._to_geographic = pyproj.Transformer.from_crs(
397
413
  self.crs._pyproj_crs, self._geographic_crs, always_xy=True
398
414
  )
399
- self._from_geographic = Transformer.from_crs(
415
+ self._from_geographic = pyproj.Transformer.from_crs(
400
416
  self._geographic_crs, self.crs._pyproj_crs, always_xy=True
401
417
  )
402
418
  except ProjError:
@@ -444,12 +460,10 @@ class TileMatrixSet(BaseModel, arbitrary_types_allowed=True):
444
460
 
445
461
  def __repr__(self):
446
462
  """Simplify default pydantic model repr."""
447
- return (
448
- f"<TileMatrixSet title='{self.title}' id='{self.id}' crs='{self.crs.root}>"
449
- )
463
+ return f"<TileMatrixSet title='{self.title}' id='{self.id}' crs='{CRS_to_uri(self.crs._pyproj_crs)}>"
450
464
 
451
465
  @cached_property
452
- def geographic_crs(self) -> CRS:
466
+ def geographic_crs(self) -> pyproj.CRS:
453
467
  """Return the TMS's geographic CRS."""
454
468
  return self._geographic_crs
455
469
 
@@ -489,7 +503,7 @@ class TileMatrixSet(BaseModel, arbitrary_types_allowed=True):
489
503
 
490
504
  Attributes
491
505
  ----------
492
- supportedCRS: CRSType
506
+ supportedCRS: CRS
493
507
  Tile Matrix Set coordinate reference system
494
508
  title: str
495
509
  Title of TMS
@@ -523,7 +537,7 @@ class TileMatrixSet(BaseModel, arbitrary_types_allowed=True):
523
537
  v2_tms["crs"] = v2_tms.pop("supportedCRS")
524
538
  v2_tms["tileMatrices"] = v2_tms.pop("tileMatrix")
525
539
  v2_tms["id"] = v2_tms.pop("identifier")
526
- mpu = meters_per_unit(CRS.from_user_input(v2_tms["crs"]))
540
+ mpu = meters_per_unit(pyproj.CRS.from_user_input(v2_tms["crs"]))
527
541
  for i in range(len(v2_tms["tileMatrices"])):
528
542
  v2_tms["tileMatrices"][i]["cellSize"] = (
529
543
  v2_tms["tileMatrices"][i]["scaleDenominator"] * 0.28e-3 / mpu
@@ -542,17 +556,17 @@ class TileMatrixSet(BaseModel, arbitrary_types_allowed=True):
542
556
  def custom(
543
557
  cls,
544
558
  extent: List[float],
545
- crs: CRS,
559
+ crs: pyproj.CRS,
546
560
  tile_width: int = 256,
547
561
  tile_height: int = 256,
548
562
  matrix_scale: Optional[List] = None,
549
- extent_crs: Optional[CRS] = None,
563
+ extent_crs: Optional[pyproj.CRS] = None,
550
564
  minzoom: int = 0,
551
565
  maxzoom: int = 24,
552
566
  title: Optional[str] = None,
553
567
  id: Optional[str] = None,
554
568
  ordered_axes: Optional[List[str]] = None,
555
- geographic_crs: CRS = WGS84_CRS,
569
+ geographic_crs: pyproj.CRS = WGS84_CRS,
556
570
  screen_pixel_size: float = 0.28e-3,
557
571
  **kwargs: Any,
558
572
  ):
@@ -604,7 +618,7 @@ class TileMatrixSet(BaseModel, arbitrary_types_allowed=True):
604
618
  is_inverted = crs_axis_inverted(crs)
605
619
 
606
620
  if extent_crs:
607
- transform = Transformer.from_crs(extent_crs, crs, always_xy=True)
621
+ transform = pyproj.Transformer.from_crs(extent_crs, crs, always_xy=True)
608
622
  extent = transform.transform_bounds(*extent, densify_pts=21)
609
623
 
610
624
  bbox = BoundingBox(*extent)
@@ -636,20 +650,20 @@ class TileMatrixSet(BaseModel, arbitrary_types_allowed=True):
636
650
  )
637
651
 
638
652
  if crs.to_authority(min_confidence=20):
639
- crs_str = CRS_to_uri(crs)
653
+ crs_data: Any = CRS_to_uri(crs)
640
654
 
641
655
  # Some old Proj version might not support URI
642
656
  # so we fall back to wkt
643
657
  try:
644
- CRS.from_user_input(crs_str)
658
+ pyproj.CRS.from_user_input(crs_data)
645
659
  except CRSError:
646
- crs_str = crs.to_wkt()
660
+ crs_data = {"wkt": crs.to_json_dict()}
647
661
 
648
662
  else:
649
- crs_str = crs.to_wkt()
663
+ crs_data = {"wkt": crs.to_json_dict()}
650
664
 
651
665
  return cls(
652
- crs=crs_str,
666
+ crs=crs_data,
653
667
  tileMatrices=tile_matrices,
654
668
  id=id,
655
669
  title=title,
@@ -1236,7 +1250,7 @@ class TileMatrixSet(BaseModel, arbitrary_types_allowed=True):
1236
1250
  "properties": {
1237
1251
  "title": f"XYZ tile {xyz}",
1238
1252
  "grid_name": self.id,
1239
- "grid_crs": self.crs.root,
1253
+ "grid_crs": CRS_to_uri(self.crs._pyproj_crs),
1240
1254
  },
1241
1255
  }
1242
1256
 
File without changes
File without changes
File without changes
File without changes