Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,19 @@ dependencies = [
]

[project.optional-dependencies]
doc = [
"pdoc3 >= 0.10.0"
]

dev = [
"black",
"pre-commit >3,<4"
]

test = [
"pytest >= 7.1.2",
"coverage >= 7.0.5"
]
doc = [
"pdoc3 >= 0.10.0"
]

[project.urls]
"Homepage" = "https://rok4.github.io/core-python"
Expand Down
3 changes: 3 additions & 0 deletions src/rok4/Exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ def __init__(self, path, missing):
self.missing = missing
super().__init__(f"Missing attribute {missing} in '{path}'")


class MissingEnvironmentError(Exception):
"""
Exception raised when a needed environment variable is not defined
Expand All @@ -17,6 +18,7 @@ def __init__(self, missing):
self.missing = missing
super().__init__(f"Missing environment variable {missing}")


class StorageError(Exception):
"""
Exception raised when an issue occured when using a storage
Expand All @@ -27,6 +29,7 @@ def __init__(self, type, issue):
self.issue = issue
super().__init__(f"Issue occured using a {type} storage : {issue}")


class FormatError(Exception):
"""
Exception raised when a format is expected but not respected
Expand Down
74 changes: 37 additions & 37 deletions src/rok4/Layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from rok4.Storage import *
from rok4.Utils import *


class Layer:
"""A data layer, raster or vector

Expand All @@ -34,7 +35,7 @@ class Layer:
"""

@classmethod
def from_descriptor(cls, descriptor: str) -> 'Layer':
def from_descriptor(cls, descriptor: str) -> "Layer":
"""Create a layer from its descriptor

Args:
Expand All @@ -58,7 +59,7 @@ def from_descriptor(cls, descriptor: str) -> 'Layer':
layer = cls()

storage_type, path, root, base_name = get_infos_from_path(descriptor)
layer.__name = base_name[:-5] # on supprime l'extension.json
layer.__name = base_name[:-5] # on supprime l'extension.json

try:
# Attributs communs
Expand All @@ -71,7 +72,6 @@ def from_descriptor(cls, descriptor: str) -> 'Layer':
for k in data["keywords"]:
layer.__keywords.append(k)


if layer.type == PyramidType.RASTER:
if "resampling" in data:
layer.__resampling = data["resampling"]
Expand All @@ -83,7 +83,12 @@ def from_descriptor(cls, descriptor: str) -> 'Layer':

# Les bbox, native et géographique
if "bbox" in data:
layer.__geobbox = (data["bbox"]["south"], data["bbox"]["west"], data["bbox"]["north"], data["bbox"]["east"])
layer.__geobbox = (
data["bbox"]["south"],
data["bbox"]["west"],
data["bbox"]["north"],
data["bbox"]["east"],
)
layer.__bbox = reproject_bbox(layer.__geobbox, "EPSG:4326", layer.__tms.srs, 5)
# On force l'emprise de la couche, on recalcule donc les tuiles limites correspondantes pour chaque niveau
for l in layer.__levels.values():
Expand All @@ -95,11 +100,10 @@ def from_descriptor(cls, descriptor: str) -> 'Layer':
except KeyError as e:
raise MissingAttributeError(descriptor, e)


return layer

@classmethod
def from_parameters(cls, pyramids: List[Dict[str, str]], name: str, **kwargs) -> 'Layer':
def from_parameters(cls, pyramids: List[Dict[str, str]], name: str, **kwargs) -> "Layer":
"""Create a default layer from parameters

Args:
Expand All @@ -121,7 +125,9 @@ def from_parameters(cls, pyramids: List[Dict[str, str]], name: str, **kwargs) ->

# Informations obligatoires
if not re.match("^[A-Za-z0-9_-]*$", name):
raise Exception(f"Layer's name have to contain only letters, number, hyphen and underscore, to be URL and storage compliant ({name})")
raise Exception(
f"Layer's name have to contain only letters, number, hyphen and underscore, to be URL and storage compliant ({name})"
)

layer.__name = name
layer.__load_pyramids(pyramids)
Expand Down Expand Up @@ -156,7 +162,6 @@ def from_parameters(cls, pyramids: List[Dict[str, str]], name: str, **kwargs) ->

return layer


def __init__(self) -> None:
self.__format = None
self.__tms = None
Expand All @@ -181,7 +186,6 @@ def __load_pyramids(self, pyramids: List[Dict[str, str]]) -> None:
## Toutes les pyramides doivent avoir les même caractéristiques
channels = None
for p in pyramids:

pyramid = Pyramid.from_descriptor(p["path"])
bottom_level = p.get("bottom_level", None)
top_level = p.get("top_level", None)
Expand All @@ -193,18 +197,24 @@ def __load_pyramids(self, pyramids: List[Dict[str, str]]) -> None:
top_level = pyramid.top_level.id

if self.__format is not None and self.__format != pyramid.format:
raise Exception(f"Used pyramids have to own the same format : {self.__format} != {pyramid.format}")
raise Exception(
f"Used pyramids have to own the same format : {self.__format} != {pyramid.format}"
)
else:
self.__format = pyramid.format

if self.__tms is not None and self.__tms.id != pyramid.tms.id:
raise Exception(f"Used pyramids have to use the same TMS : {self.__tms.id} != {pyramid.tms.id}")
raise Exception(
f"Used pyramids have to use the same TMS : {self.__tms.id} != {pyramid.tms.id}"
)
else:
self.__tms = pyramid.tms

if self.type == PyramidType.RASTER:
if channels is not None and channels != pyramid.raster_specifications["channels"]:
raise Exception(f"Used RASTER pyramids have to own the same number of channels : {channels} != {pyramid.raster_specifications['channels']}")
raise Exception(
f"Used RASTER pyramids have to own the same number of channels : {channels} != {pyramid.raster_specifications['channels']}"
)
else:
channels = pyramid.raster_specifications["channels"]
self.__resampling = pyramid.raster_specifications["interpolation"]
Expand All @@ -215,11 +225,9 @@ def __load_pyramids(self, pyramids: List[Dict[str, str]]) -> None:
raise Exception(f"Level {l.id} is present in two used pyramids")
self.__levels[l.id] = l

self.__pyramids.append({
"pyramid": pyramid,
"bottom_level": bottom_level,
"top_level": top_level
})
self.__pyramids.append(
{"pyramid": pyramid, "bottom_level": bottom_level, "top_level": top_level}
)

self.__best_level = sorted(self.__levels.values(), key=lambda l: l.resolution)[0]

Expand All @@ -237,38 +245,30 @@ def serializable(self) -> Dict:
"title": self.__title,
"abstract": self.__abstract,
"keywords": self.__keywords,
"wmts": {
"authorized": True
},
"tms": {
"authorized": True
},
"wmts": {"authorized": True},
"tms": {"authorized": True},
"bbox": {
"south": self.__geobbox[0],
"west": self.__geobbox[1],
"north": self.__geobbox[2],
"east": self.__geobbox[3]
"east": self.__geobbox[3],
},
"pyramids": []
"pyramids": [],
}

for p in self.__pyramids:
serialization["pyramids"].append({
"bottom_level" : p["bottom_level"],
"top_level" : p["top_level"],
"path" : p["pyramid"].descriptor
})
serialization["pyramids"].append(
{
"bottom_level": p["bottom_level"],
"top_level": p["top_level"],
"path": p["pyramid"].descriptor,
}
)

if self.type == PyramidType.RASTER:
serialization["wms"] = {
"authorized": True,
"crs": [
"CRS:84",
"IGNF:WGS84G",
"EPSG:3857",
"EPSG:4258",
"EPSG:4326"
]
"crs": ["CRS:84", "IGNF:WGS84G", "EPSG:3857", "EPSG:4258", "EPSG:4326"],
}

if self.__tms.srs.upper() not in serialization["wms"]["crs"]:
Expand Down
Loading