nefino-geosync 0.1.0__py3-none-any.whl → 0.2.1__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.

Potentially problematic release.


This version of nefino-geosync might be problematic. Click here for more details.

@@ -65,4 +65,4 @@ def compose_single_request(state: str,
65
65
  scope=scope,
66
66
  requests=requests,
67
67
  operations=DUMMY_OPERATIONS)
68
- return GeoAnalysisInput(name=f'sync_{state}', specs=[spec])
68
+ return GeoAnalysisInput(name=f'sync_{state}', specs=spec)
@@ -1,22 +1,25 @@
1
1
  import os
2
2
  import re
3
- from shutil import move, rmtree
4
- from urllib.request import urlretrieve
5
3
  import zipfile
4
+ from .config import Config
6
5
  from .get_downloadable_analyses import AnalysisResult
7
6
  from .journal import Journal
8
- from .config import Config
9
- from .storage import get_download_directory
7
+ from .storage import get_download_directory
10
8
  from datetime import datetime
9
+ from shutil import move, rmtree
10
+ from urllib.request import urlretrieve
11
+
11
12
 
12
13
  def download_analysis(analysis: AnalysisResult) -> None:
13
14
  """Downloads the analysis to the local machine."""
14
15
  journal = Journal.singleton()
15
16
  download_dir = get_download_directory(analysis.pk)
16
17
  download_file = os.path.join(download_dir, "download.zip")
17
- if not os.path.exists(download_file):
18
- urlretrieve(analysis.url.replace(" ", "%20"), download_file)
19
- with zipfile.ZipFile(download_file, 'r') as zip_ref:
18
+ if os.path.exists(download_file):
19
+ # remove any failed download
20
+ os.remove(download_file)
21
+ urlretrieve(analysis.url.replace(" ", "%20"), download_file)
22
+ with zipfile.ZipFile(download_file, "r") as zip_ref:
20
23
  zip_ref.extractall(download_dir)
21
24
  zip_root = get_zip_root(download_dir)
22
25
  unpack_items(zip_root, analysis.pk, analysis.started_at)
@@ -29,42 +32,95 @@ def get_zip_root(download_dir: str) -> str:
29
32
  return download_dir
30
33
 
31
34
 
32
- FILE_NAME_PATTERN = re.compile(r"(?P<layer>^.*?)(?P<buffer>__[0-9]+m)?(?P<ext>\..{3,4}$)")
35
+ FILE_NAME_PATTERN = re.compile(
36
+ r"(?P<layer>^.*?)(?P<buffer>__[0-9]+m)?(?P<ext>\..{3,4}$)"
37
+ )
38
+
33
39
 
34
40
  def unpack_items(zip_root: str, pk: str, started_at: datetime) -> None:
35
- """Unpacks the layers from the zip file."""
41
+ """
42
+ Unpacks the layers from the zip file.
43
+
44
+ Args:
45
+ zip_root: Path to the root directory of the extracted zip
46
+ pk: Primary key of the analysis
47
+ started_at: Timestamp when the analysis started
48
+ """
36
49
  journal = Journal.singleton()
37
50
  config = Config.singleton()
51
+
38
52
  if pk not in journal.analysis_states:
39
53
  print(f"Analysis {pk} not found in journal; skipping download")
40
54
  return
55
+
41
56
  state = journal.get_state_for_analysis(pk)
42
- for cluster in (f for f in os.listdir(zip_root)
43
- if f != 'analysis_area'
44
- and os.path.isdir(os.path.join(zip_root, f))):
45
- cluster_dir = os.path.join(zip_root, cluster)
57
+ base_path = get_base_path(zip_root)
58
+
59
+ # Iterate through cluster folders inside the analysis subfolder
60
+ for cluster in (
61
+ f
62
+ for f in os.listdir(base_path)
63
+ if f != "analysis_area" and os.path.isdir(os.path.join(base_path, f))
64
+ ):
65
+ cluster_dir = os.path.join(base_path, cluster)
46
66
  layers = set()
67
+
47
68
  for file in os.listdir(cluster_dir):
48
69
  if journal.is_newer_than_saved(file, state, started_at):
49
70
  output_dir = os.path.join(config.output_path, state)
50
71
  if not os.path.exists(output_dir):
51
72
  os.makedirs(output_dir)
73
+
52
74
  file_path = os.path.join(cluster_dir, file)
53
75
  match = re.match(FILE_NAME_PATTERN, file)
54
76
  layer, ext = (match.group("layer"), match.group("ext"))
55
- # remove any existing files for the same layer
77
+
78
+ # Remove any existing files for the same layer
56
79
  # this is important to avoid confusion if the pre-buffer changes
57
- for matching_file in (f for f in os.listdir(output_dir)
58
- if f.startswith(layer)):
80
+ for matching_file in (
81
+ f for f in os.listdir(output_dir) if f.startswith(layer)
82
+ ):
59
83
  output_match = re.match(FILE_NAME_PATTERN, matching_file)
60
84
  # only remove files that match the layer and extension
61
85
  # otherwise, only the last extension to be unpacked would survive
62
86
  # also, we are double-checking the layer name here in case we have
63
87
  # a layer name which starts with a different layer's name
64
- if output_match.group("layer") == layer and \
65
- output_match.group("ext") == ext:
88
+ if (
89
+ output_match.group("layer") == layer
90
+ and output_match.group("ext") == ext
91
+ ):
66
92
  os.remove(os.path.join(output_dir, matching_file))
93
+
67
94
  move(file_path, output_dir)
68
95
  layers.add(layer)
96
+
69
97
  journal.record_layers_unpacked(layers, state, started_at)
70
- rmtree(zip_root)
98
+
99
+ rmtree(zip_root)
100
+
101
+
102
+ def get_base_path(zip_root: str) -> str:
103
+ """
104
+ Returns the base path for the analysis files in the ZIP structure.
105
+
106
+ Handles two different ZIP structures:
107
+ - Old structure: analysis_summary.xlsx and cluster folders directly in ZIP root
108
+ - New structure: analysis_summary.xlsx and cluster folders inside a dedicated subfolder
109
+
110
+ The presence of analysis_summary.xlsx in the root directory is used to determine
111
+ which structure we're dealing with.
112
+
113
+ Args:
114
+ zip_root: Path to the root directory of the extracted ZIP file
115
+
116
+ Returns:
117
+ str: Path to the directory containing the cluster folders and analysis_summary.xlsx
118
+ """
119
+ if "analysis_summary.xlsx" in os.listdir(zip_root):
120
+ # Old structure - use zip_root
121
+ return zip_root
122
+ # Get the analysis subfolder name (first and only directory in zip_root)
123
+ analysis_subfolder = next(
124
+ f for f in os.listdir(zip_root) if os.path.isdir(os.path.join(zip_root, f))
125
+ )
126
+ return os.path.join(zip_root, analysis_subfolder)
@@ -823,17 +823,9 @@
823
823
  "kind": "NON_NULL",
824
824
  "name": null,
825
825
  "ofType": {
826
- "kind": "LIST",
827
- "name": null,
828
- "ofType": {
829
- "kind": "NON_NULL",
830
- "name": null,
831
- "ofType": {
832
- "kind": "INPUT_OBJECT",
833
- "name": "GeoAnalysisObjectInput",
834
- "ofType": null
835
- }
836
- }
826
+ "kind": "INPUT_OBJECT",
827
+ "name": "GeoAnalysisObjectInput",
828
+ "ofType": null
837
829
  }
838
830
  }
839
831
  }
@@ -1206,16 +1198,6 @@
1206
1198
  "enumValues": null,
1207
1199
  "fields": null,
1208
1200
  "inputFields": [
1209
- {
1210
- "defaultValue": null,
1211
- "description": "Operation to be done on those layers. One of \"union\", \"union_negative\" or \"both\". Default is \"both\".",
1212
- "name": "type",
1213
- "type": {
1214
- "kind": "ENUM",
1215
- "name": "OperationType",
1216
- "ofType": null
1217
- }
1218
- },
1219
1201
  {
1220
1202
  "defaultValue": null,
1221
1203
  "description": "Name of the requested operation",
@@ -1254,35 +1236,6 @@
1254
1236
  "name": "GeoAnalysisOperationInput",
1255
1237
  "possibleTypes": null
1256
1238
  },
1257
- {
1258
- "description": "An enumeration.",
1259
- "enumValues": [
1260
- {
1261
- "deprecationReason": null,
1262
- "description": null,
1263
- "isDeprecated": false,
1264
- "name": "UNION"
1265
- },
1266
- {
1267
- "deprecationReason": null,
1268
- "description": null,
1269
- "isDeprecated": false,
1270
- "name": "UNION_NEGATIVE"
1271
- },
1272
- {
1273
- "deprecationReason": null,
1274
- "description": null,
1275
- "isDeprecated": false,
1276
- "name": "BOTH"
1277
- }
1278
- ],
1279
- "fields": null,
1280
- "inputFields": null,
1281
- "interfaces": null,
1282
- "kind": "ENUM",
1283
- "name": "OperationType",
1284
- "possibleTypes": null
1285
- },
1286
1239
  {
1287
1240
  "description": "Input for specs: Output format.",
1288
1241
  "enumValues": null,
nefino_geosync/schema.py CHANGED
@@ -24,11 +24,6 @@ ID = sgqlc.types.ID
24
24
 
25
25
  Int = sgqlc.types.Int
26
26
 
27
- class OperationType(sgqlc.types.Enum):
28
- __schema__ = schema
29
- __choices__ = ('BOTH', 'UNION', 'UNION_NEGATIVE')
30
-
31
-
32
27
  class OutputObjectType(sgqlc.types.Enum):
33
28
  __schema__ = schema
34
29
  __choices__ = ('GPKG', 'QGIS_AND_GPKG', 'QGIS_PRJ', 'SHP')
@@ -75,7 +70,7 @@ class GeoAnalysisInput(sgqlc.types.Input):
75
70
  __schema__ = schema
76
71
  __field_names__ = ('name', 'specs')
77
72
  name = sgqlc.types.Field(String, graphql_name='name')
78
- specs = sgqlc.types.Field(sgqlc.types.non_null(sgqlc.types.list_of(sgqlc.types.non_null('GeoAnalysisObjectInput'))), graphql_name='specs')
73
+ specs = sgqlc.types.Field(sgqlc.types.non_null('GeoAnalysisObjectInput'), graphql_name='specs')
79
74
 
80
75
 
81
76
  class GeoAnalysisLayerInput(sgqlc.types.Input):
@@ -97,8 +92,7 @@ class GeoAnalysisObjectInput(sgqlc.types.Input):
97
92
 
98
93
  class GeoAnalysisOperationInput(sgqlc.types.Input):
99
94
  __schema__ = schema
100
- __field_names__ = ('type', 'operation_name', 'input')
101
- type = sgqlc.types.Field(OperationType, graphql_name='type')
95
+ __field_names__ = ('operation_name', 'input')
102
96
  operation_name = sgqlc.types.Field(sgqlc.types.non_null(String), graphql_name='operationName')
103
97
  input = sgqlc.types.Field(sgqlc.types.non_null(sgqlc.types.list_of(String)), graphql_name='input')
104
98
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: nefino-geosync
3
- Version: 0.1.0
3
+ Version: 0.2.1
4
4
  Summary: Python package to access geographical data from Nefino.LI Geo
5
5
  Project-URL: Application, https://nefino.li
6
6
  Project-URL: API, https://api.nefino.li
@@ -267,5 +267,5 @@ pip install nefino-geosync
267
267
 
268
268
  ## Help
269
269
 
270
- - Open an [issue](https://github.com/your-org/geosync-py/issues) for bug reports or feature requests
270
+ - Open an [issue](https://github.com/nefino/geosync-py/issues) for bug reports or feature requests
271
271
  - Contact [Nefino](https://www.nefino.de/kontakt) for account-related inquiries
@@ -1,21 +1,21 @@
1
1
  nefino_geosync/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  nefino_geosync/access_rule_filter.py,sha256=mCSMBrXNkGojiW2Ly8D9w46emaigp9bkDSW7f2gVnBM,372
3
3
  nefino_geosync/api_client.py,sha256=ylVVEC1f6N8P77VVZ5RLp3lieVnLmrepMO1IjnBGU4o,3617
4
- nefino_geosync/compose_requests.py,sha256=qCvixY1Zxr47tMNm3juXQf0ZY4xFHrH4sUEXuHL8j1k,3742
4
+ nefino_geosync/compose_requests.py,sha256=oiVApnl-cxDBFeIoxaU_UREI4EXOHSCsad0i65Uh1BM,3740
5
5
  nefino_geosync/config.py,sha256=thVVMsw4-CGgYJj63sX6nQShSZ9n9zEuz_9RCNL1tIM,3491
6
- nefino_geosync/download_analysis.py,sha256=WhiC6XTe1My5E_yA9TAxmQ1NG3YPxUc_AAd8C_Kmllo,3311
6
+ nefino_geosync/download_analysis.py,sha256=Y4By5U5-ohks6VzjgSd_8RqZ_gIocukgWlN51NXdq_k,4751
7
7
  nefino_geosync/download_completed_analyses.py,sha256=ggCZGi8mOL2imT8iwfR8yTsdvnKHA6jyw6Dwil1TLU0,866
8
8
  nefino_geosync/get_downloadable_analyses.py,sha256=Om0Q6F7xRze-jvo865XN2qzRT91zmuA-TAKYmeVsGIE,1651
9
9
  nefino_geosync/graphql_errors.py,sha256=n92jAicdfeH7weUo1I1gTIC2JQKDybYlD9BVredSHQw,1512
10
10
  nefino_geosync/journal.py,sha256=5IbOBfIM-oWXCd7ZvMqx-8A069dDsW15DZ9YcnCzV0s,5271
11
11
  nefino_geosync/parse_args.py,sha256=75e8J7WDiueOnMuPQdvwj-w_dXMhrGCOLMNTRIFGOHA,937
12
12
  nefino_geosync/run.py,sha256=l4b-P5B3_CNqp6d13_ZjCBbGyp7MWIC1ZwgNfEvvZm8,914
13
- nefino_geosync/schema.json,sha256=bLli73Xr983x8Z83DKW-Zql4qJMsJSEE1aoBggqDDLM,72547
14
- nefino_geosync/schema.py,sha256=yWKOjSyUthGe0OnhX86iJkKKqK7Li3_-ZU5WCEiSNXg,9438
13
+ nefino_geosync/schema.json,sha256=yBHwVYsfF1ybUFthGUuNpkdGkBdx_DcqZgq0ul4TIYo,71104
14
+ nefino_geosync/schema.py,sha256=ALP9_2sKh75sXrYDmTiBEBLygZMiZF-B8hahcYYJZrE,9203
15
15
  nefino_geosync/start_analyses.py,sha256=xWicbXvJybKb8Yi756M2cRpfys0bzmri9_eByAot0sE,2063
16
16
  nefino_geosync/storage.py,sha256=_fnE-zQnNSMfgoUratUcDGbMUJA-oatf55AXbuftFyI,1424
17
- nefino_geosync-0.1.0.dist-info/METADATA,sha256=uthvy_QaflOzgCx2UWo-1-97hkRMhcZHuWy6k2Ub0Bc,15498
18
- nefino_geosync-0.1.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
19
- nefino_geosync-0.1.0.dist-info/entry_points.txt,sha256=zZ7Zrx1MyxZKd2iGrvRmHjYzY5C2EMgqY5TqzNOGYqo,59
20
- nefino_geosync-0.1.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
21
- nefino_geosync-0.1.0.dist-info/RECORD,,
17
+ nefino_geosync-0.2.1.dist-info/METADATA,sha256=P4iOxGtvCM9xkS3X1DszkbW-2U46RkDz8uBYYkRjG4Q,15496
18
+ nefino_geosync-0.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
19
+ nefino_geosync-0.2.1.dist-info/entry_points.txt,sha256=zZ7Zrx1MyxZKd2iGrvRmHjYzY5C2EMgqY5TqzNOGYqo,59
20
+ nefino_geosync-0.2.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
21
+ nefino_geosync-0.2.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.25.0
2
+ Generator: hatchling 1.27.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any