ssb-sgis 1.1.4__py3-none-any.whl → 1.1.6__py3-none-any.whl

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.
@@ -101,18 +101,18 @@ def coverage_clean(
101
101
 
102
102
  _cleaning_checks(gdf, tolerance, duplicate_action)
103
103
 
104
- if not gdf.index.is_unique:
105
- gdf = gdf.reset_index(drop=True)
104
+ # if not gdf.index.is_unique:
105
+ # gdf = gdf.reset_index(drop=True)
106
106
 
107
- gdf = make_all_singlepart(gdf).loc[
108
- lambda x: x.geom_type.isin(["Polygon", "MultiPolygon"])
109
- ]
107
+ # gdf = make_all_singlepart(gdf).loc[
108
+ # lambda x: x.geom_type.isin(["Polygon", "MultiPolygon"])
109
+ # ]
110
110
 
111
- gdf = safe_simplify(gdf, PRECISION)
111
+ # gdf = safe_simplify(gdf, PRECISION)
112
112
 
113
113
  gdf = (
114
114
  clean_geoms(gdf)
115
- .pipe(make_all_singlepart)
115
+ .pipe(make_all_singlepart, ignore_index=True)
116
116
  .loc[lambda x: x.geom_type.isin(["Polygon", "MultiPolygon"])]
117
117
  )
118
118
 
@@ -475,14 +475,14 @@ def _dissolve_thick_double_and_update(gdf, double, thin_double):
475
475
  large = (
476
476
  double.loc[~double["_double_idx"].isin(thin_double["_double_idx"])]
477
477
  .drop(columns="_double_idx")
478
- # .pipe(sort_large_first)
479
- .sort_values("_poly_idx")
478
+ .pipe(sort_small_first)
479
+ # .sort_values("_poly_idx")
480
480
  .pipe(update_geometries, geom_type="polygon")
481
481
  )
482
482
  return (
483
- clean_overlay(gdf, large, how="update")
484
- # .pipe(sort_large_first)
485
- .sort_values("_poly_idx").pipe(update_geometries, geom_type="polygon")
483
+ clean_overlay(gdf, large, how="update").pipe(sort_small_first)
484
+ # .sort_values("_poly_idx")
485
+ .pipe(update_geometries, geom_type="polygon")
486
486
  )
487
487
 
488
488
 
@@ -534,7 +534,8 @@ def split_and_eliminate_by_longest(
534
534
  **kwargs,
535
535
  ) -> GeoDataFrame | tuple[GeoDataFrame]:
536
536
  if not len(to_eliminate):
537
- return gdf
537
+ gdf = (gdf,) if isinstance(gdf, GeoDataFrame) else gdf
538
+ return (*gdf, to_eliminate)
538
539
 
539
540
  if not isinstance(gdf, (GeoDataFrame, GeoSeries)):
540
541
  as_gdf = pd.concat(gdf, ignore_index=True)
@@ -596,7 +597,10 @@ def split_by_neighbors(df, split_by, tolerance, grid_size=None) -> GeoDataFrame:
596
597
 
597
598
  intersecting_lines = (
598
599
  clean_overlay(
599
- to_lines(split_by), buff(df, tolerance), how="identity", grid_size=grid_size
600
+ to_lines(split_by.explode(ignore_index=True)[lambda x: x.length > 0]),
601
+ buff(df, tolerance),
602
+ how="identity",
603
+ grid_size=grid_size,
600
604
  )
601
605
  .pipe(get_line_segments)
602
606
  .reset_index(drop=True)
@@ -307,7 +307,7 @@ def _get_intersecting_geometries(
307
307
  right["idx_right"] = right.index
308
308
 
309
309
  left = (
310
- gdf
310
+ gdf.copy()
311
311
  if not any("index_" in str(col) for col in gdf)
312
312
  else gdf.loc[:, lambda x: x.columns.difference({"index_right", "index_left"})]
313
313
  )
@@ -594,8 +594,9 @@ def to_lines(
594
594
  """
595
595
  gdf = (
596
596
  pd.concat(df.assign(**{"_df_idx": i}) for i, df in enumerate(gdfs))
597
- .pipe(make_all_singlepart, ignore_index=True)
597
+ .pipe(make_all_singlepart)
598
598
  .pipe(clean_geoms)
599
+ .pipe(make_all_singlepart, ignore_index=True)
599
600
  )
600
601
  geom_col = gdf.geometry.name
601
602
 
@@ -607,7 +608,9 @@ def to_lines(
607
608
  if (geoms.geom_type == "Polygon").all():
608
609
  geoms = polygons_to_lines(geoms, copy=copy)
609
610
  elif (geoms.geom_type != "LineString").any():
610
- raise ValueError("Point geometries not allowed in 'to_lines'.")
611
+ raise ValueError(
612
+ f"Point geometries not allowed in 'to_lines'. {geoms.geom_type.value_counts()}"
613
+ )
611
614
 
612
615
  gdf.geometry.loc[:] = geoms
613
616
 
@@ -86,6 +86,9 @@ def read_geopandas(
86
86
  """
87
87
  file_system = _get_file_system(file_system, kwargs)
88
88
 
89
+ if isinstance(gcs_path, (Path | os.PathLike)):
90
+ gcs_path = str(gcs_path)
91
+
89
92
  if not isinstance(gcs_path, (str | Path | os.PathLike)):
90
93
  return _read_geopandas_from_iterable(
91
94
  gcs_path,
@@ -664,7 +667,7 @@ def _read_geopandas(
664
667
  return read_func(file, **kwargs)
665
668
  except ValueError as e:
666
669
  if "Missing geo metadata" not in str(e) and "geometry" not in str(e):
667
- raise e
670
+ raise e.__class__(f"{e.__class__.__name__}: {e} for {file}. ") from e
668
671
  df = getattr(pd, f"read_{file_format}")(file, **kwargs)
669
672
  if not len(df):
670
673
  return GeoDataFrame(df)
sgis/maps/explore.py CHANGED
@@ -441,11 +441,10 @@ class Explore(Map):
441
441
  self.cmap_start = self.kwargs.pop("cmap_start", 0)
442
442
  self.cmap_stop = self.kwargs.pop("cmap_stop", 256)
443
443
 
444
- # if self._gdf.crs is None:
445
- # self.kwargs["crs"] = "Simple"
446
-
447
444
  self.original_crs = self.gdf.crs
448
445
 
446
+ self._to_categorical()
447
+
449
448
  def __repr__(self) -> str:
450
449
  """Representation."""
451
450
  return f"{self.__class__.__name__}({len(self)})"
sgis/maps/httpserver.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import os
2
+ import socket
2
3
  import webbrowser
3
4
  from http.server import BaseHTTPRequestHandler
4
5
  from http.server import HTTPServer
@@ -7,8 +8,19 @@ from IPython.display import HTML
7
8
  from IPython.display import display
8
9
 
9
10
 
11
+ def find_available_port(start_port: int, max_attempts: int = 10) -> int:
12
+ """Find an available port starting from `start_port`."""
13
+ for port in range(start_port, start_port + max_attempts):
14
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
15
+ if sock.connect_ex(("127.0.0.1", port)) != 0:
16
+ return port # Port is available
17
+ raise RuntimeError("No available ports found in range.")
18
+
19
+
10
20
  def run_html_server(contents: str | None = None, port: int = 3000) -> None:
11
21
  """Run a simple, temporary http web server for serving static HTML content."""
22
+ port = find_available_port(port)
23
+
12
24
  if "JUPYTERHUB_SERVICE_PREFIX" in os.environ:
13
25
  # Create a link using the https://github.com/jupyterhub/jupyter-server-proxy
14
26
  display_address = os.environ["JUPYTERHUB_SERVICE_PREFIX"] + f"proxy/{port}/"
sgis/maps/map.py CHANGED
@@ -110,6 +110,7 @@ class Map:
110
110
  nan_color="#c2c2c2",
111
111
  scheme: str = DEFAULT_SCHEME,
112
112
  cmap: str | None = None,
113
+ categorical: bool | None = None,
113
114
  **kwargs,
114
115
  ) -> None:
115
116
  """Initialiser.
@@ -124,6 +125,7 @@ class Map:
124
125
  scheme: Classification scheme to be used.
125
126
  cmap (str): Colormap of the plot. See:
126
127
  https://matplotlib.org/stable/tutorials/colors/colormaps.html
128
+ categorical: Set to True to convert 'column' to string values.
127
129
  **kwargs: Arbitrary keyword arguments.
128
130
  """
129
131
  gdfs, column, kwargs = self._separate_args(gdfs, column, kwargs)
@@ -198,9 +200,13 @@ class Map:
198
200
  f"length as gdfs ({len(gdfs)}). Got len {len(show)}"
199
201
  )
200
202
 
203
+ if categorical is not None:
204
+ self._is_categorical = categorical
205
+
201
206
  if not self._gdfs or not any(len(gdf) for gdf in self._gdfs):
202
207
  self._gdfs = []
203
- self._is_categorical = True
208
+ if categorical is None:
209
+ self._is_categorical = True
204
210
  self._unique_values = []
205
211
  self._nan_idx = []
206
212
  return
@@ -209,7 +215,8 @@ class Map:
209
215
  self._set_labels()
210
216
 
211
217
  self._gdfs = self._to_common_crs_and_one_geom_col(self._gdfs)
212
- self._is_categorical = self._check_if_categorical()
218
+ if categorical is None:
219
+ self._is_categorical = self._check_if_categorical()
213
220
 
214
221
  if self._column:
215
222
  self._fillna_if_col_is_missing()
@@ -231,6 +238,29 @@ class Map:
231
238
 
232
239
  self._nan_idx = self._gdf[self._column].isna()
233
240
  self._get_unique_values()
241
+ self._to_categorical()
242
+
243
+ def _to_categorical(self):
244
+ if not (self._is_categorical and self.column is not None):
245
+ return
246
+
247
+ def to_string_via_int(series):
248
+ if not pd.api.types.is_numeric_dtype(series):
249
+ return series.astype("string")
250
+ try:
251
+ series = series.astype(float)
252
+ except ValueError:
253
+ return series
254
+ no_decimals: bool = (series.dropna() % 1 == 0).all()
255
+ if no_decimals:
256
+ return series.astype("Int64").astype("string")
257
+ else:
258
+ return series.astype("string")
259
+
260
+ for i, gdf in enumerate(self._gdfs):
261
+ if self.column in gdf:
262
+ self._gdfs[i][self.column] = to_string_via_int(gdf[self.column])
263
+ self._gdf[self.column] = to_string_via_int(self._gdf[self.column])
234
264
 
235
265
  def __getattr__(self, attr: str) -> Any:
236
266
  """Search for attribute in kwargs."""
sgis/maps/wms.py CHANGED
@@ -54,6 +54,7 @@ class NorgeIBilderWms(WmsLoader):
54
54
  years: Iterable[int | str] = DEFAULT_YEARS
55
55
  contains: str | Iterable[str] | None = None
56
56
  not_contains: str | Iterable[str] | None = None
57
+ show: bool | Iterable[int] | int = False
57
58
 
58
59
  def load_tiles(self) -> None:
59
60
  """Load all Norge i bilder tiles into self.tiles."""
@@ -122,6 +123,11 @@ class NorgeIBilderWms(WmsLoader):
122
123
 
123
124
  bbox = to_shapely(bbox)
124
125
 
126
+ if isinstance(self.show, bool):
127
+ show = self.show
128
+ else:
129
+ show = False
130
+
125
131
  for tile in self.tiles:
126
132
  if not tile["bbox"] or not tile["bbox"].intersects(bbox):
127
133
  continue
@@ -150,10 +156,18 @@ class NorgeIBilderWms(WmsLoader):
150
156
  transparent=True, # Allow transparency
151
157
  version="1.3.0", # WMS version
152
158
  attr="&copy; <a href='https://www.geonorge.no/'>Geonorge</a>",
153
- show=False,
159
+ show=show,
154
160
  max_zoom=max_zoom,
155
161
  )
156
162
 
163
+ if isinstance(self.show, int):
164
+ tile = all_tiles[list(all_tiles)[self.show]]
165
+ tile.show = True
166
+ elif isinstance(self.show, Iterable):
167
+ for i in self.show:
168
+ tile = all_tiles[list(all_tiles)[i]]
169
+ tile.show = True
170
+
157
171
  return all_tiles
158
172
 
159
173
  def __post_init__(self) -> None:
@@ -0,0 +1 @@
1
+ from .parallel import chunkwise
sgis/parallel/parallel.py CHANGED
@@ -1117,7 +1117,6 @@ def chunkwise(
1117
1117
  iterable_chunked: list[Iterable] = [
1118
1118
  to_type(chunk) for chunk in np.array_split(list(iterable), n_chunks)
1119
1119
  ]
1120
-
1121
1120
  return Parallel(processes, backend=backend).map(
1122
1121
  func,
1123
1122
  iterable_chunked,
@@ -8,6 +8,7 @@ import re
8
8
  import time
9
9
  from abc import abstractmethod
10
10
  from collections.abc import Callable
11
+ from collections.abc import Generator
11
12
  from collections.abc import Iterable
12
13
  from collections.abc import Iterator
13
14
  from collections.abc import Sequence
@@ -86,6 +87,14 @@ except ImportError:
86
87
  raise ImportError("xarray")
87
88
 
88
89
 
90
+ try:
91
+ from gcsfs.core import GCSFile
92
+ except ImportError:
93
+
94
+ class GCSFile:
95
+ """Placeholder."""
96
+
97
+
89
98
  from ..geopandas_tools.bounds import get_total_bounds
90
99
  from ..geopandas_tools.conversion import to_bbox
91
100
  from ..geopandas_tools.conversion import to_gdf
@@ -2645,9 +2654,10 @@ class ImageCollection(_ImageBase):
2645
2654
 
2646
2655
  other = to_shapely(other)
2647
2656
 
2648
- intersects_list: pd.Series = GeoSeries(
2649
- [img.union_all() for img in self]
2650
- ).intersects(other)
2657
+ with ThreadPoolExecutor() as executor:
2658
+ bounds_iterable: Generator[Polygon] = executor.map(_union_all, self)
2659
+
2660
+ intersects_list: pd.Series = GeoSeries(list(bounds_iterable)).intersects(other)
2651
2661
 
2652
2662
  self.images = [
2653
2663
  image
@@ -3479,6 +3489,10 @@ def _open_raster(path: str | Path) -> rasterio.io.DatasetReader:
3479
3489
  return rasterio.open(file)
3480
3490
 
3481
3491
 
3492
+ def _union_all(obj: _ImageBase) -> Polygon:
3493
+ return obj.union_all()
3494
+
3495
+
3482
3496
  def _read_mask_array(self: Band | Image, **kwargs) -> np.ndarray:
3483
3497
  mask_band_id = self.masking["band_id"]
3484
3498
  mask_paths = [path for path in self._all_file_paths if mask_band_id in path]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ssb-sgis
3
- Version: 1.1.4
3
+ Version: 1.1.6
4
4
  Summary: GIS functions used at Statistics Norway.
5
5
  Home-page: https://github.com/statisticsnorway/ssb-sgis
6
6
  License: MIT
@@ -6,10 +6,10 @@ sgis/geopandas_tools/__init__.py,sha256=bo8lFMcltOz7TtWAi52_ekR2gd3mjfBfKeMDV5zu
6
6
  sgis/geopandas_tools/bounds.py,sha256=YJyF0gp78hFAjLLZmDquRKCBAtbt7QouG3snTcJeNQs,23822
7
7
  sgis/geopandas_tools/buffer_dissolve_explode.py,sha256=t9GJqRMDsHEU74RIlqeMr4QBgbTK0hYlXL4af1RKIks,19955
8
8
  sgis/geopandas_tools/centerlines.py,sha256=Q65Sx01SeAlulBEd9oaZkB2maBBNdLcJwAbTILg4SPU,11848
9
- sgis/geopandas_tools/cleaning.py,sha256=_V3KrJBaL8hZk1Iv6HBfTMTe7GCgcRbWfelkWOxqaIg,24116
9
+ sgis/geopandas_tools/cleaning.py,sha256=0j7_bfuAjWVBUImbPTXuwNdYRJ_By6HAwaOdw5Dh4vc,24315
10
10
  sgis/geopandas_tools/conversion.py,sha256=o3QJZLfaqqpJNdWWNKfQn_dS77uJxxRxWZxhf18vPXs,25505
11
- sgis/geopandas_tools/duplicates.py,sha256=qtcwMg310QytXBTV7XIJpPghZKz5Zyt7P59BHqc93gw,14919
12
- sgis/geopandas_tools/general.py,sha256=_XpQf792JqkvnMvEqtUMkPGVhjsct2SHSAyDYFdCyuQ,39885
11
+ sgis/geopandas_tools/duplicates.py,sha256=MTduclsUZlYifFsc7g9KOJyh6P4EkixZlcZmFH-bgYo,14926
12
+ sgis/geopandas_tools/general.py,sha256=UPtmgEMhTZw-qMiCCjeTtyBlJWoVE96SSanufPK8MLs,39976
13
13
  sgis/geopandas_tools/geocoding.py,sha256=n47aFQMm4yX1MsPnTM4dFjwegCA1ZmGUDj1uyu7OJV4,691
14
14
  sgis/geopandas_tools/geometry_types.py,sha256=ijQDbQaZPqPGjBl707H4yooNXpk21RXyatI7itnvqLk,7603
15
15
  sgis/geopandas_tools/neighbors.py,sha256=vduQlHeoZjHyD5pxDbjfonQ3-LAHGfPETxV7-L6Sg4M,16634
@@ -21,20 +21,20 @@ sgis/geopandas_tools/sfilter.py,sha256=SLcMYprQwnY5DNo0R7TGXk4m6u26H8o4PRn-RPhme
21
21
  sgis/helpers.py,sha256=_h7ke9hJrRNhHW-ZX3gA95fOrX2s1ADKBMxc94p2F4Q,9627
22
22
  sgis/io/__init__.py,sha256=uyBr20YDqB2bQttrd5q1JuGOvX32A-MSvS7Wmw5f5qg,177
23
23
  sgis/io/_is_dapla.py,sha256=wmfkSe98IrLhUg3dtXZusV6OVC8VlY1kbc5EQDf3P-Q,358
24
- sgis/io/dapla_functions.py,sha256=nH0aIC7LsyP9SQ_y8iz1ALbqoqq6WK_LqZ9dg3Yvq20,29851
24
+ sgis/io/dapla_functions.py,sha256=bhdOw12qIZqKYn8TXPaDcvEOGZYhwv8VE62ESZmv7bM,29998
25
25
  sgis/io/opener.py,sha256=HWO3G1NB6bpXKM94JadCD513vjat1o1TFjWGWzyVasg,898
26
26
  sgis/io/read_parquet.py,sha256=FvZYv1rLkUlrSaUY6QW6E1yntmntTeQuZ9ZRgCDO4IM,3776
27
27
  sgis/maps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
28
  sgis/maps/examine.py,sha256=Pb0dH8JazU5E2svfQrzHO1Bi-sjy5SeyY6zoeMO34jE,9369
29
- sgis/maps/explore.py,sha256=AxgaUNAKnGY_b7T5e3mLfysvF8fpJshHxsmEQih8oBw,47846
30
- sgis/maps/httpserver.py,sha256=7Od9JMCtntcIQKk_TchetojMHzFHT9sPw7GANahI97c,1982
29
+ sgis/maps/explore.py,sha256=Vdt1-vFKWkJxL-odh3rn2YlKpWw6Ew0bu8U3KURThNc,47797
30
+ sgis/maps/httpserver.py,sha256=eCDoB9x74kSLiGEj2X3O91t3oscY_ia17UNuaaJ6tCc,2472
31
31
  sgis/maps/legend.py,sha256=lVRVCkhPmJRjGK23obFJZAO3qp6du1LYnobkkN7DPkc,26279
32
- sgis/maps/map.py,sha256=smaf9i53EoRZWmZjn9UuqlhzUvVs1XKo2ItIpHxyuik,29592
32
+ sgis/maps/map.py,sha256=S2SrOCbVesS8Y5KlziGCmCi85_LIumL8CH8z4MdOEXc,30744
33
33
  sgis/maps/maps.py,sha256=gxu0rgcVygjudRtM1dVRmsUMilMUIg3vG-UgvASM91E,23072
34
34
  sgis/maps/norge_i_bilder.json,sha256=W_mFfte3DxugWbEudZ5fadZ2JeFYb0hyab2Quf4oJME,481311
35
35
  sgis/maps/thematicmap.py,sha256=w6q4_gIr8BubQgsPJkc6WXk-tmplDLGcKyjphhFp7ng,21873
36
36
  sgis/maps/tilesources.py,sha256=F4mFHxPwkiPJdVKzNkScTX6xbJAMIUtlTq4mQ83oguw,1746
37
- sgis/maps/wms.py,sha256=Sely3Pt-cym9kRlrK0JTjtMe21kTxWY6ucD2dAoWHI0,6442
37
+ sgis/maps/wms.py,sha256=y8xJSWCqE1SZPInWKiTGdGLI015hOFrdwUyPVouU1LU,6885
38
38
  sgis/networkanalysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
39
  sgis/networkanalysis/_get_route.py,sha256=9I3t9pnccUPr4mozy3TJCOpGCCf3UOIojmsbifubZbA,6368
40
40
  sgis/networkanalysis/_od_cost_matrix.py,sha256=zkyPX7ObT996ahaFJ2oI0D0SqQWbWyfy_qLtXwValPg,3434
@@ -49,16 +49,17 @@ sgis/networkanalysis/networkanalysis.py,sha256=-g7slZLFNxUZSUMvVmf7zax-9IOXz1NGC
49
49
  sgis/networkanalysis/networkanalysisrules.py,sha256=9sXigaCzvKhXFwpeVNMtOiIK3_Hzp9yDpFklmEEAPak,12956
50
50
  sgis/networkanalysis/nodes.py,sha256=atFSpqz-_uJHMrf6MC0zhrrcWIydRMFZrsaHC2xr1GU,3374
51
51
  sgis/networkanalysis/traveling_salesman.py,sha256=Jjo6bHY4KJ-eK0LycyTy0sWxZjgITs5MBllZ_G9FhTE,5655
52
- sgis/parallel/parallel.py,sha256=eyIXPp6nhUhLh1rwkfPLayG5hAi3i8PxmwFHxGCo-k4,39677
52
+ sgis/parallel/__init__.py,sha256=fw_Fl3IJk1bKzrRBhZIoOpznJqwd09NVHJJFj2ZLeIU,32
53
+ sgis/parallel/parallel.py,sha256=CzHetSAr9wvSrEDFTqDq2xAsNuG1ig22-vcEOIoUVv4,39676
53
54
  sgis/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
55
  sgis/raster/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
56
  sgis/raster/base.py,sha256=tiZEuMcVK6hOm_aIjWhQ1WGshcjsxT1fFkuBSLFiMC0,7785
56
- sgis/raster/image_collection.py,sha256=STPh8m2WRAkuQfuJC1VNA2XLZ6FHT8I7qjcAntVWi2o,122573
57
+ sgis/raster/image_collection.py,sha256=FfsBgLtne9_pcCm6FynrMx90NpHLulcshj5ALT08zOA,122888
57
58
  sgis/raster/indices.py,sha256=-J1HYmnT240iozvgagvyis6K0_GHZHRuUrPOgyoeIrY,223
58
59
  sgis/raster/regex.py,sha256=kYhVpRYzoXutx1dSYmqMoselWXww7MMEsTPmLZwHjbM,3759
59
60
  sgis/raster/sentinel_config.py,sha256=nySDqn2R8M6W8jguoBeSAK_zzbAsqmaI59i32446FwY,1268
60
61
  sgis/raster/zonal.py,sha256=D4Gyptw-yOLTCO41peIuYbY-DANsJCG19xXDlf1QAz4,2299
61
- ssb_sgis-1.1.4.dist-info/LICENSE,sha256=np3IfD5m0ZUofn_kVzDZqliozuiO6wrktw3LRPjyEiI,1073
62
- ssb_sgis-1.1.4.dist-info/METADATA,sha256=lPqCX4slMY8NR7PPVDLRLYdkFOstiSMvUN6NTWXX_8M,11740
63
- ssb_sgis-1.1.4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
64
- ssb_sgis-1.1.4.dist-info/RECORD,,
62
+ ssb_sgis-1.1.6.dist-info/LICENSE,sha256=np3IfD5m0ZUofn_kVzDZqliozuiO6wrktw3LRPjyEiI,1073
63
+ ssb_sgis-1.1.6.dist-info/METADATA,sha256=hKTyyKXLiExr5vbMEoiz4F2BHEz-ktdKu58Eu1Ck8kg,11740
64
+ ssb_sgis-1.1.6.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
65
+ ssb_sgis-1.1.6.dist-info/RECORD,,