voxcity 0.6.18__py3-none-any.whl → 0.6.19__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 voxcity might be problematic. Click here for more details.

voxcity/utils/weather.py CHANGED
@@ -233,10 +233,15 @@ def get_nearest_epw_from_climate_onebuilding(longitude: float, latitude: float,
233
233
  If no stations within this distance, uses closest available.
234
234
  extract_zip (bool): Whether to extract the ZIP file (default True)
235
235
  load_data (bool): Whether to load the EPW data into a DataFrame (default True)
236
- region (str or List[str], optional): Specific region(s) to scan for stations.
237
- Options: "Africa", "Asia", "Japan", "India", "Argentina",
238
- "Canada", "USA", "Caribbean", "Southwest_Pacific",
239
- "Europe", "Antarctica", or "all".
236
+ region (str or List[str], optional): Specific region(s) or dataset(s) to scan for stations.
237
+ Regions: "Africa", "Asia", "South_America",
238
+ "North_and_Central_America", "Southwest_Pacific",
239
+ "Europe", "Antarctica".
240
+ Sub-datasets (can be used alone or auto-included by region):
241
+ "Japan", "India", "CSWD", "CityUHK", "PHIKO",
242
+ "Argentina", "INMET_TRY", "AMTUes", "BrazFuture",
243
+ plus legacy "Canada", "USA", "Caribbean" (Region 4).
244
+ Use "all" to scan every dataset.
240
245
  If None, will auto-detect region based on coordinates.
241
246
 
242
247
  Returns:
@@ -250,35 +255,83 @@ def get_nearest_epw_from_climate_onebuilding(longitude: float, latitude: float,
250
255
  requests.exceptions.RequestException: If network requests fail
251
256
  """
252
257
 
253
- # Regional KML sources from Climate.OneBuilding.Org
254
- # Each region maintains its own KML file with weather station locations and metadata
258
+ # Regional KML sources from Climate.OneBuilding.Org (2024+ TMYx structure)
259
+ # Each WMO region maintains a primary KML in /sources with the naming pattern:
260
+ # Region{N}_{Name}_TMYx_EPW_Processing_locations.kml
261
+ # Keep sub-region keys for backward compatibility (mapping to the Region KML where applicable)
255
262
  KML_SOURCES = {
256
- "Africa": "https://climate.onebuilding.org/WMO_Region_1_Africa/Region1_Africa_EPW_Processing_locations.kml",
257
- "Asia": "https://climate.onebuilding.org/WMO_Region_2_Asia/Region2_Asia_EPW_Processing_locations.kml",
263
+ # WMO Region 1
264
+ "Africa": "https://climate.onebuilding.org/sources/Region1_Africa_TMYx_EPW_Processing_locations.kml",
265
+ # WMO Region 2
266
+ "Asia": "https://climate.onebuilding.org/sources/Region2_Asia_TMYx_EPW_Processing_locations.kml",
267
+ # Subsets/datasets within Asia that still publish dedicated KMLs
258
268
  "Japan": "https://climate.onebuilding.org/sources/JGMY_EPW_Processing_locations.kml",
259
269
  "India": "https://climate.onebuilding.org/sources/ITMY_EPW_Processing_locations.kml",
270
+ "CSWD": "https://climate.onebuilding.org/sources/CSWD_EPW_Processing_locations.kml",
271
+ "CityUHK": "https://climate.onebuilding.org/sources/CityUHK_EPW_Processing_locations.kml",
272
+ "PHIKO": "https://climate.onebuilding.org/sources/PHIKO_EPW_Processing_locations.kml",
273
+ # WMO Region 3
274
+ "South_America": "https://climate.onebuilding.org/sources/Region3_South_America_TMYx_EPW_Processing_locations.kml",
275
+ # Historical/legacy dataset for Argentina maintained separately
260
276
  "Argentina": "https://climate.onebuilding.org/sources/ArgTMY_EPW_Processing_locations.kml",
277
+ "INMET_TRY": "https://climate.onebuilding.org/sources/INMET_TRY_EPW_Processing_locations.kml",
278
+ "AMTUes": "https://climate.onebuilding.org/sources/AMTUes_EPW_Processing_locations.kml",
279
+ "BrazFuture": "https://climate.onebuilding.org/sources/BrazFuture_EPW_Processing_locations.kml",
280
+ # WMO Region 4 (use subregion KMLs; umbrella selection expands to these)
281
+ # Note: There is no single unified Region 4 KML in /sources as of 2024.
282
+ # Use these three subregion KMLs instead.
261
283
  "Canada": "https://climate.onebuilding.org/sources/Region4_Canada_TMYx_EPW_Processing_locations.kml",
262
284
  "USA": "https://climate.onebuilding.org/sources/Region4_USA_TMYx_EPW_Processing_locations.kml",
263
285
  "Caribbean": "https://climate.onebuilding.org/sources/Region4_NA_CA_Caribbean_TMYx_EPW_Processing_locations.kml",
286
+ # WMO Region 5
264
287
  "Southwest_Pacific": "https://climate.onebuilding.org/sources/Region5_Southwest_Pacific_TMYx_EPW_Processing_locations.kml",
288
+ # WMO Region 6
265
289
  "Europe": "https://climate.onebuilding.org/sources/Region6_Europe_TMYx_EPW_Processing_locations.kml",
266
- "Antarctica": "https://climate.onebuilding.org/sources/Region7_Antarctica_TMYx_EPW_Processing_locations.kml"
290
+ # WMO Region 7
291
+ "Antarctica": "https://climate.onebuilding.org/sources/Region7_Antarctica_TMYx_EPW_Processing_locations.kml",
292
+ }
293
+
294
+ # Group region selections to include relevant sub-datasets automatically
295
+ REGION_DATASET_GROUPS = {
296
+ "Africa": ["Africa"],
297
+ "Asia": ["Asia", "Japan", "India", "CSWD", "CityUHK", "PHIKO"],
298
+ "South_America": ["South_America", "Argentina", "INMET_TRY", "AMTUes", "BrazFuture"],
299
+ "North_and_Central_America": ["North_and_Central_America", "Canada", "USA", "Caribbean"],
300
+ "Southwest_Pacific": ["Southwest_Pacific"],
301
+ "Europe": ["Europe"],
302
+ "Antarctica": ["Antarctica"],
267
303
  }
268
304
 
269
305
  # Define approximate geographical boundaries for automatic region detection
270
306
  # These bounds help determine which regional KML files to scan based on coordinates
271
307
  REGION_BOUNDS = {
272
- "Africa": {"lon_min": -20, "lon_max": 55, "lat_min": -35, "lat_max": 40},
273
- "Asia": {"lon_min": 25, "lon_max": 150, "lat_min": 0, "lat_max": 55},
308
+ # WMO Region 1 - Africa (includes islands in Indian Ocean and Spanish territories off N. Africa)
309
+ "Africa": {"lon_min": -25, "lon_max": 80, "lat_min": -55, "lat_max": 45},
310
+ # WMO Region 2 - Asia (includes SE Asia, West Asia, Asian Russia, and BIOT)
311
+ "Asia": {"lon_min": 20, "lon_max": 180, "lat_min": -10, "lat_max": 80},
312
+ # Subsets
274
313
  "Japan": {"lon_min": 127, "lon_max": 146, "lat_min": 24, "lat_max": 46},
275
314
  "India": {"lon_min": 68, "lon_max": 97, "lat_min": 6, "lat_max": 36},
315
+ # WMO Region 3 - South America (includes Falklands, South Georgia/Sandwich, Galapagos)
316
+ "South_America": {"lon_min": -92, "lon_max": -20, "lat_min": -60, "lat_max": 15},
317
+ # Legacy/compatibility subset
276
318
  "Argentina": {"lon_min": -75, "lon_max": -53, "lat_min": -55, "lat_max": -22},
319
+ # WMO Region 4 - North and Central America (includes Greenland and Caribbean)
320
+ "North_and_Central_America": {"lon_min": -180, "lon_max": 20, "lat_min": -10, "lat_max": 85},
321
+ # Backward-compatible subsets mapped to Region 4 KML
277
322
  "Canada": {"lon_min": -141, "lon_max": -52, "lat_min": 42, "lat_max": 83},
278
323
  "USA": {"lon_min": -170, "lon_max": -65, "lat_min": 20, "lat_max": 72},
279
324
  "Caribbean": {"lon_min": -90, "lon_max": -59, "lat_min": 10, "lat_max": 27},
280
- "Southwest_Pacific": {"lon_min": 110, "lon_max": 180, "lat_min": -50, "lat_max": 0},
281
- "Europe": {"lon_min": -25, "lon_max": 40, "lat_min": 35, "lat_max": 72},
325
+ # WMO Region 5 - Southwest Pacific (covers SE Asia + Pacific islands + Hawaii via antimeridian)
326
+ "Southwest_Pacific": {
327
+ "boxes": [
328
+ {"lon_min": 90, "lon_max": 180, "lat_min": -50, "lat_max": 25},
329
+ {"lon_min": -180, "lon_max": -140, "lat_min": -50, "lat_max": 25},
330
+ ]
331
+ },
332
+ # WMO Region 6 - Europe (includes Middle East countries listed and Greenland)
333
+ "Europe": {"lon_min": -75, "lon_max": 60, "lat_min": 25, "lat_max": 85},
334
+ # WMO Region 7 - Antarctica
282
335
  "Antarctica": {"lon_min": -180, "lon_max": 180, "lat_min": -90, "lat_max": -60}
283
336
  }
284
337
 
@@ -306,34 +359,45 @@ def get_nearest_epw_from_climate_onebuilding(longitude: float, latitude: float,
306
359
  elif lon > 180:
307
360
  lon_adjusted = lon - 360
308
361
 
309
- # Check if coordinates fall within any region bounds
362
+ # Helper to test point within a single box
363
+ def _in_box(bx: Dict[str, float], lon_v: float, lat_v: float) -> bool:
364
+ return (bx["lon_min"] <= lon_v <= bx["lon_max"] and
365
+ bx["lat_min"] <= lat_v <= bx["lat_max"])
366
+
367
+ # Check if coordinates fall within any region bounds (support multi-box)
310
368
  for region_name, bounds in REGION_BOUNDS.items():
311
- # Check if point is within region bounds
312
- if (bounds["lon_min"] <= lon_adjusted <= bounds["lon_max"] and
313
- bounds["lat_min"] <= lat <= bounds["lat_max"]):
314
- matching_regions.append(region_name)
369
+ if "boxes" in bounds:
370
+ for bx in bounds["boxes"]:
371
+ if _in_box(bx, lon_adjusted, lat):
372
+ matching_regions.append(region_name)
373
+ break
374
+ else:
375
+ if _in_box(bounds, lon_adjusted, lat):
376
+ matching_regions.append(region_name)
315
377
 
316
378
  # If no regions matched, find the closest regions by boundary distance
317
379
  if not matching_regions:
318
380
  # Calculate "distance" to each region's boundary (simplified metric)
319
381
  region_distances = []
320
382
  for region_name, bounds in REGION_BOUNDS.items():
321
- # Calculate distance to closest edge of region bounds
322
- lon_dist = 0
323
- if lon_adjusted < bounds["lon_min"]:
324
- lon_dist = bounds["lon_min"] - lon_adjusted
325
- elif lon_adjusted > bounds["lon_max"]:
326
- lon_dist = lon_adjusted - bounds["lon_max"]
327
-
328
- lat_dist = 0
329
- if lat < bounds["lat_min"]:
330
- lat_dist = bounds["lat_min"] - lat
331
- elif lat > bounds["lat_max"]:
332
- lat_dist = lat - bounds["lat_max"]
333
-
334
- # Simple Euclidean distance metric (not actual geographic distance)
335
- distance = (lon_dist**2 + lat_dist**2)**0.5
336
- region_distances.append((region_name, distance))
383
+ def _box_distance(bx: Dict[str, float]) -> float:
384
+ lon_dist = 0
385
+ if lon_adjusted < bx["lon_min"]:
386
+ lon_dist = bx["lon_min"] - lon_adjusted
387
+ elif lon_adjusted > bx["lon_max"]:
388
+ lon_dist = lon_adjusted - bx["lon_max"]
389
+ lat_dist = 0
390
+ if lat < bx["lat_min"]:
391
+ lat_dist = bx["lat_min"] - lat
392
+ elif lat > bx["lat_max"]:
393
+ lat_dist = lat - bx["lat_max"]
394
+ return (lon_dist**2 + lat_dist**2)**0.5
395
+
396
+ if "boxes" in bounds:
397
+ d = min(_box_distance(bx) for bx in bounds["boxes"])
398
+ else:
399
+ d = _box_distance(bounds)
400
+ region_distances.append((region_name, d))
337
401
 
338
402
  # Get 3 closest regions to ensure we find stations
339
403
  closest_regions = sorted(region_distances, key=lambda x: x[1])[:3]
@@ -511,6 +575,74 @@ def get_nearest_epw_from_climate_onebuilding(longitude: float, latitude: float,
511
575
 
512
576
  return metadata
513
577
 
578
+ def try_download_station_zip(original_url: str, timeout_s: int = 30) -> Optional[bytes]:
579
+ """
580
+ Try downloading station archive; on 404s, attempt smart fallbacks.
581
+
582
+ Fallback strategies:
583
+ - Country rename: /TUR_Turkey/ -> /TUR_Turkiye/ (per Oct 2024 site update)
584
+ - TMYx period variants: .2009-2023.zip, .2007-2021.zip, .zip, .2004-2018.zip
585
+
586
+ Args:
587
+ original_url: URL extracted from KML
588
+ timeout_s: request timeout seconds
589
+ Returns:
590
+ Bytes of the downloaded zip on success, otherwise None
591
+ """
592
+ def candidate_urls(url: str) -> List[str]:
593
+ urls = []
594
+ urls.append(url)
595
+ # Country rename variants
596
+ if "/TUR_Turkey/" in url:
597
+ urls.append(url.replace("/TUR_Turkey/", "/TUR_Turkiye/"))
598
+ if "/TUR_Turkiye/" in url:
599
+ urls.append(url.replace("/TUR_Turkiye/", "/TUR_Turkey/"))
600
+ # TMYx period variants
601
+ m = re.search(r"(.*_TMYx)(?:\.(\d{4}-\d{4}))?\.zip$", url)
602
+ if m:
603
+ base = m.group(1)
604
+ suffix = m.group(2)
605
+ variants = [
606
+ f"{base}.2009-2023.zip",
607
+ f"{base}.2007-2021.zip",
608
+ f"{base}.zip",
609
+ f"{base}.2004-2018.zip",
610
+ ]
611
+ for v in variants:
612
+ if v not in urls:
613
+ urls.append(v)
614
+ # Also apply country rename to each variant
615
+ extra = []
616
+ for v in variants:
617
+ if "/TUR_Turkey/" in url:
618
+ extra.append(v.replace("/TUR_Turkey/", "/TUR_Turkiye/"))
619
+ if "/TUR_Turkiye/" in url:
620
+ extra.append(v.replace("/TUR_Turkiye/", "/TUR_Turkey/"))
621
+ for v in extra:
622
+ if v not in urls:
623
+ urls.append(v)
624
+ return urls
625
+
626
+ tried = set()
627
+ for u in candidate_urls(original_url):
628
+ if u in tried:
629
+ continue
630
+ tried.add(u)
631
+ try:
632
+ resp = requests.get(u, timeout=timeout_s)
633
+ resp.raise_for_status()
634
+ return resp.content
635
+ except requests.exceptions.HTTPError as he:
636
+ # Only continue on 404; raise on other HTTP errors
637
+ if getattr(he.response, "status_code", None) == 404:
638
+ continue
639
+ else:
640
+ raise
641
+ except requests.exceptions.RequestException:
642
+ # On network errors, try next candidate
643
+ continue
644
+ return None
645
+
514
646
  def get_stations_from_kml(kml_url: str) -> List[Dict]:
515
647
  """
516
648
  Get weather stations from a KML file.
@@ -584,6 +716,18 @@ def get_nearest_epw_from_climate_onebuilding(longitude: float, latitude: float,
584
716
 
585
717
  # Determine which regions to scan based on user input or auto-detection
586
718
  regions_to_scan = {}
719
+ def _add_selection(selection_name: str, mapping: Dict[str, str], out: Dict[str, str]):
720
+ """Expand a region or dataset selection into concrete KML URLs."""
721
+ if selection_name in REGION_DATASET_GROUPS:
722
+ for key in REGION_DATASET_GROUPS[selection_name]:
723
+ if key in KML_SOURCES:
724
+ out[key] = KML_SOURCES[key]
725
+ elif selection_name in KML_SOURCES:
726
+ out[selection_name] = KML_SOURCES[selection_name]
727
+ else:
728
+ valid = sorted(list(REGION_DATASET_GROUPS.keys()) + list(KML_SOURCES.keys()))
729
+ raise ValueError(f"Invalid region/dataset: '{selection_name}'. Valid options include: {', '.join(valid)}")
730
+
587
731
  if region is None:
588
732
  # Auto-detect regions based on coordinates
589
733
  detected_regions = detect_regions(longitude, latitude)
@@ -591,34 +735,32 @@ def get_nearest_epw_from_climate_onebuilding(longitude: float, latitude: float,
591
735
  if detected_regions:
592
736
  print(f"Auto-detected regions: {', '.join(detected_regions)}")
593
737
  for r in detected_regions:
594
- regions_to_scan[r] = KML_SOURCES[r]
738
+ _add_selection(r, KML_SOURCES, regions_to_scan)
595
739
  else:
596
740
  # Fallback to all regions if detection fails
597
741
  print("Could not determine region from coordinates. Scanning all regions.")
598
- regions_to_scan = KML_SOURCES
742
+ regions_to_scan = dict(KML_SOURCES)
599
743
  elif isinstance(region, str):
600
744
  # Handle string input for region selection
601
745
  if region.lower() == "all":
602
- regions_to_scan = KML_SOURCES
603
- elif region in KML_SOURCES:
604
- regions_to_scan[region] = KML_SOURCES[region]
746
+ regions_to_scan = dict(KML_SOURCES)
605
747
  else:
606
- valid_regions = ", ".join(KML_SOURCES.keys())
607
- raise ValueError(f"Invalid region: '{region}'. Valid regions are: {valid_regions}")
748
+ _add_selection(region, KML_SOURCES, regions_to_scan)
608
749
  else:
609
750
  # Handle list input for multiple regions
610
751
  for r in region:
611
- if r not in KML_SOURCES:
612
- valid_regions = ", ".join(KML_SOURCES.keys())
613
- raise ValueError(f"Invalid region: '{r}'. Valid regions are: {valid_regions}")
614
- regions_to_scan[r] = KML_SOURCES[r]
752
+ _add_selection(r, KML_SOURCES, regions_to_scan)
615
753
 
616
754
  # Get stations from selected KML sources
617
755
  print("Fetching weather station data from Climate.OneBuilding.Org...")
618
756
  all_stations = []
619
757
 
620
758
  # Process each selected region
759
+ scanned_urls = set()
621
760
  for region_name, url in regions_to_scan.items():
761
+ if url in scanned_urls:
762
+ continue
763
+ scanned_urls.add(url)
622
764
  print(f"Scanning {region_name}...")
623
765
  stations = get_stations_from_kml(url)
624
766
  all_stations.extend(stations)
@@ -627,7 +769,23 @@ def get_nearest_epw_from_climate_onebuilding(longitude: float, latitude: float,
627
769
  print(f"\nTotal stations found: {len(all_stations)}")
628
770
 
629
771
  if not all_stations:
630
- raise ValueError("No weather stations found")
772
+ # Fallback: if no stations found, try scanning all available datasets
773
+ if not (isinstance(region, str) and region.lower() == "all"):
774
+ print("No stations found from detected/selected regions. Falling back to global scan...")
775
+ regions_to_scan = dict(KML_SOURCES)
776
+ all_stations = []
777
+ scanned_urls = set()
778
+ for region_name, url in regions_to_scan.items():
779
+ if url in scanned_urls:
780
+ continue
781
+ scanned_urls.add(url)
782
+ print(f"Scanning {region_name}...")
783
+ stations = get_stations_from_kml(url)
784
+ all_stations.extend(stations)
785
+ print(f"Found {len(stations)} stations in {region_name}")
786
+ print(f"\nTotal stations found after global scan: {len(all_stations)}")
787
+ if not all_stations:
788
+ raise ValueError("No weather stations found")
631
789
 
632
790
  # Calculate distances from target coordinates to all stations
633
791
  stations_with_distances = [
@@ -654,10 +812,11 @@ def get_nearest_epw_from_climate_onebuilding(longitude: float, latitude: float,
654
812
  # Find the nearest weather station
655
813
  nearest_station, distance = min(stations_with_distances, key=lambda x: x[1])
656
814
 
657
- # Download the EPW file from the nearest station
815
+ # Download the EPW archive from the nearest station with fallbacks
658
816
  print(f"\nDownloading EPW file for {nearest_station['name']}...")
659
- epw_response = requests.get(nearest_station['url'])
660
- epw_response.raise_for_status()
817
+ archive_bytes = try_download_station_zip(nearest_station['url'], timeout_s=30)
818
+ if archive_bytes is None:
819
+ raise ValueError(f"Failed to download EPW archive from station URL and fallbacks: {nearest_station['url']}")
661
820
 
662
821
  # Create a temporary directory for zip extraction
663
822
  temp_dir = Path(output_dir) / "temp"
@@ -666,7 +825,7 @@ def get_nearest_epw_from_climate_onebuilding(longitude: float, latitude: float,
666
825
  # Save the downloaded zip file temporarily
667
826
  zip_file = temp_dir / "weather_data.zip"
668
827
  with open(zip_file, 'wb') as f:
669
- f.write(epw_response.content)
828
+ f.write(archive_bytes)
670
829
 
671
830
  final_epw = None
672
831
  try:
@@ -1,8 +1,10 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: voxcity
3
- Version: 0.6.18
3
+ Version: 0.6.19
4
4
  Summary: voxcity is an easy and one-stop tool to output 3d city models for microclimate simulation by integrating multiple geospatial open-data
5
5
  License: MIT
6
+ License-File: AUTHORS.rst
7
+ License-File: LICENSE
6
8
  Author: Kunihiko Fujiwara
7
9
  Author-email: fujiwara.kunihiko@takenaka.co.jp
8
10
  Maintainer: Kunihiko Fujiwara
@@ -13,7 +13,7 @@ voxcity/exporter/cityles.py,sha256=Kfl2PAn4WquqCdjOlyPrHysxPLaudh8QfsoC6WAXlvs,1
13
13
  voxcity/exporter/envimet.py,sha256=Sh7s1JdQ6SgT_L2Xd_c4gtEGWK2hTS87bccaoIqik-s,31105
14
14
  voxcity/exporter/magicavoxel.py,sha256=SfGEgTZRlossKx3Xrv9d3iKSX-HmfQJEL9lZHgWMDX4,12782
15
15
  voxcity/exporter/netcdf.py,sha256=48rJ3wDsFhi9ANbElhMjXLxWMJoJzBt1gFbN0ekPp-A,7404
16
- voxcity/exporter/obj.py,sha256=2MA2GpexMC1_GnMv0u5GVNGO1N9DH8TAtYVcFoWvkbg,50386
16
+ voxcity/exporter/obj.py,sha256=7xmVSQ_y-X8QLjNdASDPsaltGvmyW9-yAacocByYKl4,58160
17
17
  voxcity/generator.py,sha256=4WSjO09f8z3zt0tpKY0fyAfOMym1JT4VH3Tt1lOg2Bk,66900
18
18
  voxcity/geoprocessor/__init__.py,sha256=WYxcAQrjGucIvGHF0JTC6rONZzL3kCms1S2vpzS6KaU,127
19
19
  voxcity/geoprocessor/draw.py,sha256=AZMWq23wxxDJygNloCbVzWAAr1JO7nC94umf9LSxJ5o,49248
@@ -30,9 +30,9 @@ voxcity/utils/__init__.py,sha256=Q-NYCqYnAAaF80KuNwpqIjbE7Ec3Gr4y_khMLIMhJrg,68
30
30
  voxcity/utils/lc.py,sha256=722Gz3lPbgAp0mmTZ-g-QKBbAnbxrcgaYwb1sa7q8Sk,16189
31
31
  voxcity/utils/material.py,sha256=H8K8Lq4wBL6dQtgj7esUW2U6wLCOTeOtelkTDJoRgMo,10007
32
32
  voxcity/utils/visualization.py,sha256=_c5WnhA0fawkseUviKEIpUUsF-M-OOLOT9FrpgQIh1A,118556
33
- voxcity/utils/weather.py,sha256=2Jtg-rIVJcsTtiKE-KuDnhIqS1-MSS16_zFRzj6zmu4,36435
34
- voxcity-0.6.18.dist-info/AUTHORS.rst,sha256=m82vkI5QokEGdcHof2OxK39lf81w1P58kG9ZNNAKS9U,175
35
- voxcity-0.6.18.dist-info/LICENSE,sha256=s_jE1Df1nTPL4A_5GCGic5Zwex0CVaPKcAmSilxJPPE,1089
36
- voxcity-0.6.18.dist-info/METADATA,sha256=2KzFc-aRuap89tiZhqAotBF2ACcK86VCJuwg2tUvKbk,26164
37
- voxcity-0.6.18.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
38
- voxcity-0.6.18.dist-info/RECORD,,
33
+ voxcity/utils/weather.py,sha256=WcmohW0yx2-uNMO5ffgxCtKUt32q6PQsAT43P5DwJx4,44760
34
+ voxcity-0.6.19.dist-info/licenses/AUTHORS.rst,sha256=m82vkI5QokEGdcHof2OxK39lf81w1P58kG9ZNNAKS9U,175
35
+ voxcity-0.6.19.dist-info/licenses/LICENSE,sha256=s_jE1Df1nTPL4A_5GCGic5Zwex0CVaPKcAmSilxJPPE,1089
36
+ voxcity-0.6.19.dist-info/METADATA,sha256=AUmkbdSOZM7RywhizzSM_xzphJ-QLbQEuHx9IjvGSKQ,26212
37
+ voxcity-0.6.19.dist-info/WHEEL,sha256=M5asmiAlL6HEcOq52Yi5mmk9KmTVjY2RDPtO4p9DMrc,88
38
+ voxcity-0.6.19.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.3
2
+ Generator: poetry-core 2.2.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any