Skip to content

Commit 4bf1080

Browse files
committed
uv migration and python upgrade
1 parent d382b73 commit 4bf1080

20 files changed

Lines changed: 1163 additions & 1188 deletions

.github/workflows/ci.yml

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,34 +9,19 @@ jobs:
99
strategy:
1010
fail-fast: false
1111
matrix:
12-
os: [ubuntu-latest]
13-
python-version: ["3.9", "3.13"]
12+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
13+
os: [ubuntu-latest, macos-latest, windows-latest]
1414
runs-on: ${{ matrix.os }}
1515
steps:
16-
- uses: actions/checkout@v4
17-
- name: Set up Python ${{ matrix.python-version }}
18-
uses: actions/setup-python@v5
16+
- uses: actions/checkout@v6
17+
- name: Install uv and set the Python version
18+
uses: astral-sh/setup-uv@v7
1919
with:
2020
python-version: ${{ matrix.python-version }}
21-
- name: Install poetry
22-
uses: abatilo/actions-poetry@v3
23-
with:
24-
poetry-version: 1.8.4
25-
- name: Install dependencies with Poetry
26-
run: |
27-
pip install --upgrade pip
28-
poetry install
21+
version: "0.9.27"
22+
- name: Install the project
23+
run: uv sync --locked
2924
- name: Run pytest
30-
run: |
31-
poetry run pytest
32-
pre-commit:
33-
runs-on: ubuntu-latest
34-
steps:
35-
- uses: actions/checkout@v4
36-
- uses: actions/setup-python@v5
37-
with:
38-
python-version: "3.13"
25+
run: uv run pytest -v -n auto
3926
- name: Run pre-commit
40-
uses: pre-commit/action@v3.0.1
41-
with:
42-
extra_args: --all-files
27+
run: uv run pre-commit run -a

.pre-commit-config.yaml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
repos:
22
- repo: https://github.com/pre-commit/pre-commit-hooks
3-
rev: v4.6.0
3+
rev: v6.0.0
44
hooks:
55
- id: trailing-whitespace
66
- id: check-added-large-files
@@ -15,20 +15,26 @@ repos:
1515
- id: mixed-line-ending
1616
- id: pretty-format-json
1717
args: ["--autofix", "--no-sort-keys"]
18+
- repo: https://github.com/asottile/pyupgrade
19+
rev: v3.21.2
20+
hooks:
21+
- id: pyupgrade
1822
- repo: https://github.com/pre-commit/mirrors-prettier
1923
rev: v4.0.0-alpha.8
2024
hooks:
2125
- id: prettier
2226
types_or: [markdown, yaml]
2327
- repo: https://github.com/pre-commit/mirrors-mypy
24-
rev: v1.12.1
28+
rev: v1.19.1
2529
hooks:
2630
- id: mypy
31+
additional_dependencies:
32+
- pandas-stubs
2733
- repo: https://github.com/astral-sh/ruff-pre-commit
28-
rev: v0.7.0
34+
rev: v0.14.14
2935
hooks:
3036
# Run the linter
31-
- id: ruff
37+
- id: ruff-check
3238
args: [--fix, --exit-non-zero-on-fix, --output-format=full]
3339
# Run the formatter
3440
- id: ruff-format

LICENSE

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
BuildingSync®, Copyright (c) 2015, 2024 Alliance for Sustainable Energy, LLC, and other contributors.
1+
BuildingSync®, Copyright (c) 2015, 2024 Alliance for Energy Innovation, LLC, and other contributors.
22

33
All rights reserved.
44

@@ -17,7 +17,7 @@ respective party.
1717

1818
(4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other
1919
derivative works may not use the "BuildingSync" trademark or any other confusingly similar designation
20-
without specific prior written permission from Alliance for Sustainable Energy, LLC.
20+
without specific prior written permission from Alliance for Energy Innovation, LLC.
2121

2222
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
2323
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND

buildingsync_asset_extractor/bae_types.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from dataclasses import dataclass
2-
from typing import Any, Optional
2+
from typing import Any
33

44

55
@dataclass
66
class Section:
7-
type: Optional[str]
7+
type: str | None
88
areas: dict
99

1010

@@ -27,13 +27,13 @@ class AssetDef:
2727
parent_path: str
2828
key: str
2929
export_units: bool
30-
units: Optional[str] = None
30+
units: str | None = None
3131

3232

3333
@dataclass
3434
class SystemData:
3535
value: Any
36-
sqft: Optional[float] = None
37-
cap: Optional[str] = None
38-
cap_units: Optional[str] = None
39-
units: Optional[str] = None
36+
sqft: float | None = None
37+
cap: str | None = None
38+
cap_units: str | None = None
39+
units: str | None = None

buildingsync_asset_extractor/converter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Literal, Optional, get_args
1+
from typing import Literal, get_args
22

33
from buildingsync_asset_extractor.bae_types import SystemData
44
from buildingsync_asset_extractor.errors import BSyncProcessorError
@@ -22,7 +22,7 @@
2222

2323
def unify_units(
2424
system_datas: list[SystemData],
25-
to_units: Optional[str] = None,
25+
to_units: str | None = None,
2626
) -> list[SystemData]:
2727
if to_units is None:
2828
to_units = system_datas[0].cap_units

buildingsync_asset_extractor/cts/classes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import functools
22
import logging
3+
from collections.abc import Iterable
34
from dataclasses import dataclass, field
45
from pathlib import Path
5-
from typing import Iterable, Optional
66

77
from lxml import etree as ETree # noqa: N812
88

@@ -36,7 +36,7 @@ class FacilityAppearance:
3636
path: Path
3737

3838
@functools.cached_property
39-
def cheapest_package_of_measures_scenario(self) -> Optional[PackageOfMeasuresScenario]:
39+
def cheapest_package_of_measures_scenario(self) -> PackageOfMeasuresScenario | None:
4040
# get the measures for reference
4141
measures_by_id = {m.get("ID"): Measure(m) for m in self.etree.findall("./Measures/Measure", self.etree.nsmap)}
4242

buildingsync_asset_extractor/cts/cts.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def aggregate_facilities(files: list[Path]) -> dict[str, Facility]:
4242

4343
# for each file, get the facilities in the file
4444
for f in files:
45-
file_etree = etree.parse(f) # noqa: S320
45+
file_etree = etree.parse(f)
4646
facility_etrees = file_etree.findall("/Facilities/Facility", namespaces=file_etree.getroot().nsmap)
4747

4848
# for each facility in the file, add it to facility_by_id

buildingsync_asset_extractor/cts/parsers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ def get_aggregated_findings_of_comprehensive_evaluations_estimated_life_cycle_da
8888

8989

9090
def get_potential_conservation_measures_per_technology_category(facility: Facility) -> pd.Series:
91-
results = {k: 0 for k in ENERGY_AND_WATER_CONSERVATION_MEASURES}
92-
results.update({k: 0 for k in technology_category_to_cts_field.values()})
91+
results = dict.fromkeys(ENERGY_AND_WATER_CONSERVATION_MEASURES, 0)
92+
results.update(dict.fromkeys(technology_category_to_cts_field.values(), 0))
9393

9494
# for each measure
9595
measures = [

buildingsync_asset_extractor/cts_main.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""
22
*********************************************************************************************************
3-
:copyright (c) BuildingSync®, Copyright (c) 2015-2022, Alliance for Sustainable Energy, LLC,
3+
:copyright (c) BuildingSync®, Copyright (c) 2015-2026, Alliance for Energy Innovation, LLC,
44
and other contributors.
55
66
All rights reserved.
@@ -20,7 +20,7 @@
2020
2121
(4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other
2222
derivative works may not use the "BuildingSync" trademark or any other confusingly similar designation
23-
without specific prior written permission from Alliance for Sustainable Energy, LLC.
23+
without specific prior written permission from Alliance for Energy Innovation, LLC.
2424
2525
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
2626
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND

buildingsync_asset_extractor/formatters.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import logging
2-
from typing import Any, Callable, Optional, Tuple, Union
2+
from collections.abc import Callable
3+
from typing import Any
34

45
from buildingsync_asset_extractor.bae_types import SystemData
56
from buildingsync_asset_extractor.converter import unify_units
@@ -25,7 +26,7 @@ def __init__(self, export_asset: Callable[[str, Any], None], export_asset_units:
2526
self.export_asset = export_asset
2627
self.export_asset_units = export_asset_units
2728

28-
def format_age_results(self, name: str, results: list[SystemData], process_type: str, units: Optional[str]) -> None:
29+
def format_age_results(self, name: str, results: list[SystemData], process_type: str, units: str | None) -> None:
2930
# process results
3031
value = None
3132
if process_type.endswith("oldest"):
@@ -48,7 +49,7 @@ def format_age_results(self, name: str, results: list[SystemData], process_type:
4849
elif process_type.endswith("average"):
4950
self.format_custom_avg_results(name, results, units)
5051

51-
def format_80_percent_results(self, name: str, results: list[SystemData], units: Optional[str]) -> None:
52+
def format_80_percent_results(self, name: str, results: list[SystemData], units: str | None) -> None:
5253
"""format 80% rule results
5354
the "primary" type returned must at least serve 80% of the area by
5455
1. Capacity
@@ -68,7 +69,7 @@ def format_80_percent_results(self, name: str, results: list[SystemData], units:
6869

6970
results = unify_units(results)
7071

71-
values, capacities, cap_units, sqfts = self.remap_results(results)
72+
_values, capacities, cap_units, sqfts = self.remap_results(results)
7273
if None not in capacities and len(set(cap_units)) <= 1:
7374
# capacity method
7475
# add all capacities
@@ -82,8 +83,8 @@ def format_80_percent_results(self, name: str, results: list[SystemData], units:
8283
primaries[res.value] = 0.0
8384
primaries[res.value] += float(res.cap) # type: ignore[arg-type]
8485

85-
for p in primaries:
86-
if float(primaries[p]) / total >= 0.8:
86+
for p, value in primaries.items():
87+
if float(value) / total >= 0.8:
8788
# this fuel meets the 80% threshold by capacity
8889
found = 1
8990
self.export_asset(name, p)
@@ -126,7 +127,7 @@ def format_80_percent_results(self, name: str, results: list[SystemData], units:
126127
self.export_asset(name, "unknown")
127128
self.export_asset_units(name, units)
128129

129-
def format_lighting_results(self, name: str, results: list[LightingData], units: Optional[str]) -> None:
130+
def format_lighting_results(self, name: str, results: list[LightingData], units: str | None) -> None:
130131
"""custom processing for lighting efficiency
131132
1. if 'lpd' is present, average the values
132133
2. else if percentpremisesserved
@@ -191,7 +192,7 @@ def format_lighting_results(self, name: str, results: list[LightingData], units:
191192
self.export_asset_units(name, units)
192193
return
193194

194-
def format_custom_avg_results(self, name: str, results: list[SystemData], units: Optional[str]) -> None:
195+
def format_custom_avg_results(self, name: str, results: list[SystemData], units: str | None) -> None:
195196
"""format weighted average
196197
1. Ensure all units are the same
197198
2. Attempt to calculate with installed power (NOT IMPLEMENTED)
@@ -229,7 +230,7 @@ def format_custom_avg_results(self, name: str, results: list[SystemData], units:
229230
for res in results:
230231
cap_total = cap_total + float(res.cap) # type: ignore[arg-type]
231232
eff_total = eff_total + (float(res.value) * float(res.cap)) # type: ignore[arg-type]
232-
total: Union[float, str] = eff_total / cap_total
233+
total: float | str = eff_total / cap_total
233234

234235
# special case for average age: take the floor since partial year doesn't make sense
235236
if name.lower().endswith("age"):
@@ -254,7 +255,7 @@ def format_custom_avg_results(self, name: str, results: list[SystemData], units:
254255
self.export_asset_units(name, units)
255256
return
256257

257-
def format_sqft_results(self, name: str, results: dict[str, float], units: Optional[str]) -> None:
258+
def format_sqft_results(self, name: str, results: dict[str, float], units: str | None) -> None:
258259
"""return primary and secondary for top 2 results by sqft"""
259260
# NOTE: this is the only method that modifies the export name '
260261
# by appending 'primary' and 'secondary'
@@ -279,13 +280,13 @@ def format_sqft_results(self, name: str, results: dict[str, float], units: Optio
279280
self.export_asset("Secondary " + name, value2)
280281
self.export_asset_units("Secondary " + name, units)
281282

282-
def format_avg_sqft_results(self, name: str, results: dict[Any, float], units: Optional[str]) -> None:
283+
def format_avg_sqft_results(self, name: str, results: dict[Any, float], units: str | None) -> None:
283284
"""weighted average of results"""
284285

285286
# in this case the result keys will convert to numbers
286287
# to calculate the weighted average
287288

288-
total: Union[str, float, None] = None
289+
total: str | float | None = None
289290

290291
if results:
291292
total_sqft = sum(results.values())
@@ -304,7 +305,7 @@ def format_avg_sqft_results(self, name: str, results: dict[Any, float], units: O
304305
self.export_asset(name, total)
305306
self.export_asset_units(name, units)
306307

307-
def format_electrification_potential(self, name: str, results: list[SystemData], units: Optional[str]) -> None:
308+
def format_electrification_potential(self, name: str, results: list[SystemData], units: str | None) -> None:
308309
"""Sum non electric capacities"""
309310
# If no SystemDatas, then None
310311
if len(results) == 0:
@@ -340,7 +341,7 @@ def format_electrification_potential(self, name: str, results: list[SystemData],
340341
def remap_results(
341342
self,
342343
results: list[SystemData],
343-
) -> Tuple[list[Optional[float]], list[Optional[float]], list[Optional[str]], list[Optional[float]]]:
344+
) -> tuple[list[float | None], list[float | None], list[str | None], list[float | None]]:
344345
"""Remap results from a list of dictionaries to 4 lists"""
345346
try:
346347
values = [sub.value if sub.value is None else float(sub.value) for sub in results]

0 commit comments

Comments
 (0)