buildstock-fetch 1.3.1__py3-none-any.whl → 1.4.0__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 buildstock-fetch might be problematic. Click here for more details.

@@ -6,6 +6,7 @@ from pathlib import Path
6
6
  from typing import Union, cast
7
7
 
8
8
  import questionary
9
+ import tomli
9
10
  import typer
10
11
  from rich.console import Console
11
12
  from rich.panel import Panel
@@ -29,7 +30,7 @@ app = typer.Typer(
29
30
  BUILDSTOCK_RELEASES_FILE = str(files("buildstock_fetch").joinpath("data").joinpath("buildstock_releases.json"))
30
31
 
31
32
  # File types that haven't been implemented yet
32
- UNAVAILABLE_FILE_TYPES = ["load_curve_daily"]
33
+ UNAVAILABLE_FILE_TYPES: list[str] = []
33
34
 
34
35
 
35
36
  class InvalidProductError(Exception):
@@ -75,7 +76,7 @@ def _get_release_years_options(available_releases: list[str], product_type: str)
75
76
  parsed_releases = _parse_buildstock_releases(available_releases)
76
77
  available_releases = _filter_available_releases(list(parsed_releases.keys()), product_type=product_type)
77
78
  available_release_years = list({parsed_releases[release]["release_year"] for release in available_releases})
78
- available_release_years.sort()
79
+ available_release_years.sort(reverse=True) # Sort in descending order (latest first)
79
80
 
80
81
  return available_releases, available_release_years
81
82
 
@@ -218,10 +219,26 @@ def _get_file_type_options(release_name: str) -> list[str]:
218
219
  return cast(list[str], available_releases[release_name]["available_data"])
219
220
 
220
221
 
221
- def _get_file_type_options_grouped(release_name: str) -> list[dict]:
222
+ def _get_file_type_options_grouped(release_name: str, selected_states: list[str]) -> list[dict]:
222
223
  """Get file type options grouped by category for questionary checkbox."""
223
224
  file_types = _get_file_type_options(release_name)
224
225
 
226
+ # TODO: If a trip_schedule table was built for any of the states in this release, "trip_schedules" will be included
227
+ # in the file_types list above. However, the state that the user wants to download files for may not have the trip_schedule tables built for it yet.
228
+ # So, we need to check if the release_name + state combo is in the available trip_schedules_states list.
229
+ # If not, we need to remove "trip_schedules" from the file_types list, so it doesn't show up in the questionary checkbox.
230
+ # Remember that users can select multiple states, so as long as one release_name + state combo is in the available trip_schedules_states list,
231
+ # we should include "trip_schedules" in the file_types list. and then later on, we need to handle different states differently.
232
+
233
+ trip_schedule_availabile = False
234
+ available_releases = _get_all_available_releases()
235
+ for state in selected_states:
236
+ if (
237
+ "trip_schedules" in available_releases[release_name]["available_data"]
238
+ and state in available_releases[release_name]["trip_schedule_states"]
239
+ ):
240
+ trip_schedule_availabile = True
241
+
225
242
  # Define categories
226
243
  categories = {
227
244
  "Simulation Files": ["hpxml", "schedule"],
@@ -233,21 +250,39 @@ def _get_file_type_options_grouped(release_name: str) -> list[dict]:
233
250
  "load_curve_annual",
234
251
  ],
235
252
  "Metadata": ["metadata"],
253
+ "EV": ["trip_schedules"],
236
254
  "Weather": ["weather"],
237
255
  }
238
256
 
239
- choices = []
257
+ choices: list[dict] = []
240
258
  for category, types in categories.items():
241
- # Filter available types but maintain the defined order
242
- available_in_category = [ft for ft in types if ft in file_types]
243
- if available_in_category:
244
- choices.append({"name": f"--- {category} ---", "value": None, "disabled": True})
245
- for file_type in available_in_category:
246
- choices.append({"name": f" {file_type}", "value": file_type, "style": "bold"})
259
+ if category == "EV":
260
+ _add_ev_category_choices(choices, category, types, trip_schedule_availabile)
261
+ else:
262
+ _add_standard_category_choices(choices, category, types, file_types)
247
263
 
248
264
  return choices
249
265
 
250
266
 
267
+ def _add_ev_category_choices(
268
+ choices: list[dict], category: str, types: list[str], trip_schedule_available: bool
269
+ ) -> None:
270
+ """Add EV category choices to the choices list."""
271
+ for file_type in types:
272
+ if file_type == "trip_schedules" and trip_schedule_available:
273
+ choices.append({"name": f"--- {category} ---", "value": None, "disabled": True})
274
+ choices.append({"name": f" {file_type}", "value": file_type, "style": "bold"})
275
+
276
+
277
+ def _add_standard_category_choices(choices: list[dict], category: str, types: list[str], file_types: list[str]) -> None:
278
+ """Add standard category choices to the choices list."""
279
+ available_in_category = [ft for ft in types if ft in file_types]
280
+ if available_in_category:
281
+ choices.append({"name": f"--- {category} ---", "value": None, "disabled": True})
282
+ for file_type in available_in_category:
283
+ choices.append({"name": f" {file_type}", "value": file_type, "style": "bold"})
284
+
285
+
251
286
  def _get_available_releases_names() -> list[str]:
252
287
  # Read the buildstock releases JSON file
253
288
  buildstock_releases = json.loads(Path(BUILDSTOCK_RELEASES_FILE).read_text(encoding="utf-8"))
@@ -363,20 +398,23 @@ def _run_interactive_mode() -> dict[str, Union[str, list[str]]]:
363
398
  )
364
399
 
365
400
  # Retrieve state
366
- selected_states = _handle_cancellation(
367
- questionary.checkbox(
368
- "Select states:",
369
- choices=_get_state_options(),
370
- instruction="Use spacebar to select/deselect options, enter to confirm",
371
- validate=lambda answer: "You must select at least one state" if len(answer) == 0 else True,
372
- ).ask()
401
+ selected_states: list[str] = cast(
402
+ list[str],
403
+ _handle_cancellation(
404
+ questionary.checkbox(
405
+ "Select states:",
406
+ choices=_get_state_options(),
407
+ instruction="Use spacebar to select/deselect options, enter to confirm",
408
+ validate=lambda answer: "You must select at least one state" if len(answer) == 0 else True,
409
+ ).ask()
410
+ ),
373
411
  )
374
412
 
375
413
  # Retrieve requested file type
376
414
  requested_file_types = _handle_cancellation(
377
415
  questionary.checkbox(
378
416
  "Select file type:",
379
- choices=_get_file_type_options_grouped(selected_release_name),
417
+ choices=_get_file_type_options_grouped(selected_release_name, selected_states),
380
418
  instruction="Use spacebar to select/deselect options, enter to confirm",
381
419
  validate=lambda answer: "You must select at least one file type" if len(answer) == 0 else True,
382
420
  ).ask()
@@ -512,6 +550,18 @@ def _check_unavailable_file_types(inputs: Mapping[str, Union[str, list[str]]]) -
512
550
  if "weather" in selected_file_types:
513
551
  _check_weather_file_availability(inputs, available_file_types, selected_unavailable_file_types)
514
552
 
553
+ if "trip_schedules" in selected_file_types:
554
+ product_short_name = "res" if inputs["product"] == "resstock" else "com"
555
+ input_release_name = (
556
+ f"{product_short_name}_{inputs['release_year']}_{inputs['weather_file']}_{inputs['release_version']}"
557
+ )
558
+ available_releases = _get_all_available_releases()
559
+ availble_trip_schedule_states = available_releases[input_release_name]["trip_schedule_states"]
560
+ for state in inputs["states"]:
561
+ if state not in availble_trip_schedule_states:
562
+ console.print(f"[yellow]The following state is not available for trip schedules: {state}[/yellow]")
563
+ selected_unavailable_file_types.append(f"trip_schedules_{state}")
564
+
515
565
  _print_unavailable_file_types_warning(selected_unavailable_file_types)
516
566
 
517
567
  return available_file_types, selected_unavailable_file_types
@@ -645,6 +695,7 @@ def _validate_file_types(inputs: dict[str, Union[str, list[str]]], release_name:
645
695
  """Validate file types."""
646
696
  available_releases = _get_all_available_releases()
647
697
  for file_type in inputs["file_type"]:
698
+ # TODO: Validate EV related files
648
699
  if file_type not in available_releases[release_name]["available_data"]:
649
700
  return f"Invalid file type: {file_type}"
650
701
  return True
@@ -715,6 +766,29 @@ UPGRADE_ID_OPTION = typer.Option(
715
766
  None, "--upgrade_id", "-u", help="Upgrade IDs (multiple can be provided, inside quotes and separated by spaces)"
716
767
  )
717
768
  OUTPUT_DIRECTORY_OPTION = typer.Option(None, "--output_directory", "-o", help='e.g., "data" or "../output"')
769
+ VERSION_OPTION = typer.Option(False, "--version", "-v", help="Show version information and exit")
770
+
771
+
772
+ def _get_version() -> str:
773
+ """Get the version from pyproject.toml."""
774
+ try:
775
+ # Get the path to pyproject.toml (assuming it's in the project root)
776
+ project_root = Path(__file__).parent.parent
777
+ pyproject_path = project_root / "pyproject.toml"
778
+
779
+ with open(pyproject_path, "rb") as f:
780
+ data = tomli.load(f)
781
+ version = data["project"]["version"]
782
+ return str(version)
783
+ except (FileNotFoundError, KeyError, Exception):
784
+ return "unknown"
785
+
786
+
787
+ def _show_version() -> None:
788
+ """Display version information and exit."""
789
+ version = _get_version()
790
+ console.print(f"buildstock-fetch version {version}")
791
+ raise typer.Exit(0) from None
718
792
 
719
793
 
720
794
  def _run_interactive_mode_wrapper() -> dict[str, Union[str, list[str]]]:
@@ -792,7 +866,6 @@ def _process_data_download(inputs: dict[str, Union[str, list[str]]]) -> None:
792
866
  output_dir = inputs["output_directory"]
793
867
  if isinstance(output_dir, list):
794
868
  output_dir = output_dir[0] if output_dir else "."
795
-
796
869
  fetch_bldg_data(
797
870
  selected_bldg_ids, file_type_tuple, Path(output_dir), weather_states=available_weather_states
798
871
  )
@@ -811,11 +884,16 @@ def main_callback(
811
884
  file_type: str = FILE_TYPE_OPTION,
812
885
  upgrade_id: str = UPGRADE_ID_OPTION,
813
886
  output_directory: str = OUTPUT_DIRECTORY_OPTION,
887
+ version: bool = VERSION_OPTION,
814
888
  ) -> None:
815
889
  """
816
890
  Buildstock Fetch CLI tool. Run without arguments for interactive mode.
817
891
  """
818
892
 
893
+ # Handle version option first
894
+ if version:
895
+ _show_version()
896
+
819
897
  # If no arguments provided, run interactive mode
820
898
  if not any([product, release_year, weather_file, release_version, states, file_type]):
821
899
  inputs = _run_interactive_mode_wrapper()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: buildstock-fetch
3
- Version: 1.3.1
3
+ Version: 1.4.0
4
4
  Summary: This library simplifies downloading building characteristics and load curve data from NREL's ResStock and ComStock projects.
5
5
  Author-email: Switchbox <hello@switch.box>
6
6
  Project-URL: Homepage, https://switchbox-data.github.io/buildstock-fetch/
@@ -24,6 +24,7 @@ Requires-Dist: typer>=0.9.0
24
24
  Requires-Dist: rich>=13.9.5
25
25
  Requires-Dist: questionary>=1.11.0
26
26
  Requires-Dist: polars>=0.20.0
27
+ Requires-Dist: tomli>=2.0.0
27
28
  Provides-Extra: test
28
29
  Requires-Dist: pytest>=7.2.0; extra == "test"
29
30
  Provides-Extra: docs
@@ -44,6 +45,7 @@ Requires-Dist: botocore>=1.33.0; extra == "dev-utils"
44
45
  Requires-Dist: pyarrow>=14.0.1; extra == "dev-utils"
45
46
  Requires-Dist: numpy>=1.26.4; extra == "dev-utils"
46
47
  Requires-Dist: scikit-learn>=1.6.1; extra == "dev-utils"
48
+ Requires-Dist: awscli>=1.32.0; extra == "dev-utils"
47
49
  Requires-Dist: xmltodict>=0.14.2; extra == "dev-utils"
48
50
  Provides-Extra: dev
49
51
  Requires-Dist: buildstock-fetch[dev-utils,docs,lint,test]; extra == "dev"
@@ -57,15 +59,36 @@ Dynamic: license-file
57
59
  [![Commit activity](https://img.shields.io/github/commit-activity/m/switchbox-data/buildstock-fetch)](https://img.shields.io/github/commit-activity/m/switchbox-data/buildstock-fetch)
58
60
  [![License](https://img.shields.io/github/license/switchbox-data/buildstock-fetch)](https://img.shields.io/github/license/switchbox-data/buildstock-fetch)
59
61
 
60
- This library simplifies downloading building characteristics and load curve data from NREL's ResStock and ComStock projects.
62
+ A CLI tool, and python library, to simplify downloading building characteristics and load curve data from NREL's ResStock and ComStock projects.
61
63
 
62
64
  - **Github repository**: <https://github.com/switchbox-data/buildstock-fetch/>
63
65
  - **Documentation**: <https://switchbox-data.github.io/buildstock-fetch/>
64
- - **PyPI page***: <https://pypi.org/project/buildstock-fetch/>
66
+ - **PyPI page**: <https://pypi.org/project/buildstock-fetch/>
67
+
68
+ ## Installing the CLI tool
69
+
70
+ We recommend using [uv](https://docs.astral.sh/uv/getting-started/installation/) or [pipx](https://pipx.pypa.io/stable/installation/) to install the buildstock-fetch CLI:
71
+
72
+ ```bash
73
+ uv install buildstock-fetch
74
+ ```
75
+ or
76
+
77
+ ```bash
78
+ pipx install buildstock-fetch
79
+ ```
80
+
81
+ You'll then be able to access the `bsf` command system-wide:
82
+
83
+ ```bash
84
+ bsf --help
85
+ ```
65
86
 
66
87
  ## Installing the library
67
88
 
68
- `buildstock-fetch` is available on [PyPI](https://pypi.org/project/buildstock-fetch/) and can be installed via:
89
+ buildstock-fetch is implemented in Python, and we expose our internal functions via a library.
90
+
91
+ If you're using Python, and you want to install the CLI only for a particular project (rather than system-wide), or you want to user the underlying library, install our [PyPI](https://pypi.org/project/buildstock-fetch/) package via:
69
92
 
70
93
  ```bash
71
94
  pip install buildstock-fetch
@@ -77,26 +100,20 @@ or
77
100
  uv add buildstock-fetch
78
101
  ```
79
102
 
80
- ## Using the library
103
+ ## Using the CLI
81
104
 
82
- To use the CLI tool in `buildstock-fetch` run:
105
+ To make it easy to download what you want from NREL's S3 bucket, `bsf` has an interactive mode. Activate it with:
83
106
 
84
107
  ```bash
85
108
  bsf
86
109
  ```
87
110
 
88
- to activate the interactive mode. Alternatively, provide the inputs directly. For example,
111
+ Alternatively, you can tell `bsf` exactly what to download via CLI args:
89
112
 
90
113
  ```bash
91
114
  bsf --product resstock --release_year 2022 --weather_file tmy3 --release_version 1 --states CA --file_type "hpxml metadata" --upgrade_id "0 1 2" --output_directory ./CA_data
92
115
  ```
93
116
 
94
- If the above options don't work, try:
95
-
96
- ```bash
97
- python -m buildstock_fetch
98
- ```
99
-
100
117
  For more details about the usage, see [Usage](https://switchbox-data.github.io/buildstock-fetch/usage/)
101
118
 
102
119
  ## Developing the library
@@ -1,8 +1,8 @@
1
1
  buildstock_fetch/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  buildstock_fetch/__main__.py,sha256=wEPNJ-s7F6KcRQ_4B5Xh08uqvYZHno5F2R8DU0BMBtk,80
3
- buildstock_fetch/main.py,sha256=6NAYxs_5yW0PpNgPdCgmaJJUqgSF-InrMO8xZJe4npQ,73839
4
- buildstock_fetch/main_cli.py,sha256=3zKJ5sXG2QGmAs--kZPQy1qhLEnaw5gvi4RoH_q65dI,31891
5
- buildstock_fetch/data/buildstock_releases.json,sha256=rHbNkWtTi6VXFim7xtvhwFWQUvtqvcbCfjtvRjkWV-4,10853
3
+ buildstock_fetch/main.py,sha256=yZ8xoYWnoyeTIDMXzVnbQt57a2NAZS7bEPRDtj_SuiU,90887
4
+ buildstock_fetch/main_cli.py,sha256=lf-UGI9rcJgBOrJtRdHZ1mcr-jvRxOQ5H0G3re2v9Is,35754
5
+ buildstock_fetch/data/buildstock_releases.json,sha256=XL-D1Xdix59sFGbS6vKFiGhQakhhPrwn14N-Tgt9iuk,11620
6
6
  buildstock_fetch/data/building_data/combined_metadata.parquet/product=comstock/release_year=2021/weather_file=amy2018/release_version=1/state=AK/d1454abff0d94c8090af7b3e923c473b-0.parquet,sha256=nG6H3oGyDzPk1B15YmFd_U81PsA14uABqqwK7P30nKE,7059
7
7
  buildstock_fetch/data/building_data/combined_metadata.parquet/product=comstock/release_year=2021/weather_file=amy2018/release_version=1/state=AK/dcd864cc169b4695be2b9775b1a054ae-0.parquet,sha256=fsREWV9g4fsA3cIWqyPnXVwd7FsJxED2btYpmyOvnbQ,7163
8
8
  buildstock_fetch/data/building_data/combined_metadata.parquet/product=comstock/release_year=2021/weather_file=amy2018/release_version=1/state=AL/d1454abff0d94c8090af7b3e923c473b-0.parquet,sha256=jiTG48ly-LZwfwAL3THdfRzHDG1qEogoxO7P78U4WOU,41201
@@ -1602,9 +1602,9 @@ buildstock_fetch/data/building_data/combined_metadata.parquet/product=resstock/r
1602
1602
  buildstock_fetch/data/load_curve_column_map/2022_resstock_load_curve_columns.csv,sha256=9UoTPlvxR3RqsxH8i4tI75lLtdSAT-HbAFxwlzvAYNY,7339
1603
1603
  buildstock_fetch/data/load_curve_column_map/2024_resstock_load_curve_columns.csv,sha256=TIxqsE-iVHE5tYq9oPSgBxIVbd5qfyDcJG_eTqds9aY,7471
1604
1604
  buildstock_fetch/data/weather_station_map/weather_station_map.parquet,sha256=igNrx-UGH20CqPcjANTDrrMyj6Z4_JcXIg2aaCNhFRg,346990
1605
- buildstock_fetch-1.3.1.dist-info/licenses/LICENSE,sha256=TJeh2yvO8__8Rbamd8r48-zvlFCINAsu9nOo5QdMRX8,1066
1606
- buildstock_fetch-1.3.1.dist-info/METADATA,sha256=hdj6JpUKIqsyAS_2CIQL-CHruvKiau28by_d6MIrebY,7607
1607
- buildstock_fetch-1.3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1608
- buildstock_fetch-1.3.1.dist-info/entry_points.txt,sha256=C7zPk3BSLcI47ymvYKI05nvfRJMEXz4BPIIDKsjePn8,54
1609
- buildstock_fetch-1.3.1.dist-info/top_level.txt,sha256=-PGb2C-Tb3O-wPqUHSOBrvJqRzNHgY_KTbTsXaHIo5M,17
1610
- buildstock_fetch-1.3.1.dist-info/RECORD,,
1605
+ buildstock_fetch-1.4.0.dist-info/licenses/LICENSE,sha256=TJeh2yvO8__8Rbamd8r48-zvlFCINAsu9nOo5QdMRX8,1066
1606
+ buildstock_fetch-1.4.0.dist-info/METADATA,sha256=d7DyxjVTO_F-XbtLvJbJDEQyImhBkZQLGr9H5PAZ13M,8262
1607
+ buildstock_fetch-1.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1608
+ buildstock_fetch-1.4.0.dist-info/entry_points.txt,sha256=C7zPk3BSLcI47ymvYKI05nvfRJMEXz4BPIIDKsjePn8,54
1609
+ buildstock_fetch-1.4.0.dist-info/top_level.txt,sha256=-PGb2C-Tb3O-wPqUHSOBrvJqRzNHgY_KTbTsXaHIo5M,17
1610
+ buildstock_fetch-1.4.0.dist-info/RECORD,,