Skip to content

Commit 055954b

Browse files
authored
Merge pull request #783 from powerapi-ng/build/python-312
build: Bump Python minimal version to `3.12`
2 parents 82259df + 123aa03 commit 055954b

9 files changed

Lines changed: 30 additions & 31 deletions

File tree

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
runs-on: ubuntu-latest
1616
strategy:
1717
matrix:
18-
python-version: ["3.10", "3.x"]
18+
python-version: ["3.12", "3.x"]
1919

2020
steps:
2121
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

.ruff.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
target-version = "py310" # should match minimal python version of PowerAPI
1+
target-version = "py312" # should match minimal python version of PowerAPI
22

33
[lint]
44
select = [

pyproject.toml

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,20 @@ description = "PowerAPI is a middleware toolkit for building software-defined po
88
readme = "README.md"
99
keywords = ["powerapi", "energy", "power-meter", "green-computing"]
1010
license = {text = "BSD-3-Clause"}
11-
requires-python = ">=3.10"
11+
requires-python = ">=3.12"
1212
version = "2.10.0"
1313

1414
classifiers = [
15-
"Programming Language :: Python :: 3.10",
16-
"Programming Language :: Python :: 3.11",
15+
"Development Status :: 5 - Production/Stable",
16+
"Intended Audience :: Science/Research",
17+
"Intended Audience :: Developers",
18+
"License :: OSI Approved :: BSD License",
19+
"Programming Language :: Python",
20+
"Programming Language :: Python :: 3",
1721
"Programming Language :: Python :: 3.12",
1822
"Programming Language :: Python :: 3.13",
1923
"Programming Language :: Python :: 3.14",
20-
"License :: OSI Approved :: BSD License",
21-
"Intended Audience :: Science/Research",
22-
"Intended Audience :: Developers",
23-
"Development Status :: 5 - Production/Stable",
24+
"Programming Language :: Python :: Implementation :: CPython",
2425
"Topic :: Software Development :: Libraries :: Python Modules"
2526
]
2627

@@ -73,5 +74,5 @@ dev = [
7374

7475
[project.urls]
7576
homepage = "https://powerapi.org"
76-
documentation = "https://powerapi.readthedocs.org"
77-
repository = "https://github.com/powerapi-ng/powerapi"
77+
source = "https://github.com/powerapi-ng/powerapi"
78+
tracker = "https://github.com/powerapi-ng/powerapi/issues"

src/powerapi/database/codec.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2828
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2929

30-
from typing import TypeVar, Generic, Protocol
30+
from typing import TypeVar, Protocol
3131

3232
from powerapi.report import Report
3333

@@ -62,20 +62,18 @@ class ReportDecoder(Protocol[_EncodedDataType, _ReportType]):
6262
def decode(data: _EncodedDataType, opts: CodecOptions | None = None) -> _ReportType: ...
6363

6464

65-
_CodecType = TypeVar('_CodecType', ReportEncoder, ReportDecoder)
66-
67-
class _Registry(Generic[_CodecType]):
65+
class _Registry[CodecType: (ReportEncoder, ReportDecoder)]:
6866
"""
6967
Generic codecs registry class.
7068
"""
71-
_registry: dict[type[Report], _CodecType]
69+
_registry: dict[type[Report], CodecType]
7270

7371
def __init_subclass__(cls):
7472
super().__init_subclass__()
7573
cls._registry = {} # Ensure each subclass has its own independent registry.
7674

7775
@classmethod
78-
def register(cls, report_type: type[Report], codec: _CodecType) -> None:
76+
def register(cls, report_type: type[Report], codec: CodecType) -> None:
7977
"""
8078
Register a report type with its corresponding codec.
8179
:param report_type: Report type to register
@@ -84,7 +82,7 @@ def register(cls, report_type: type[Report], codec: _CodecType) -> None:
8482
cls._registry[report_type] = codec
8583

8684
@classmethod
87-
def get(cls, report_type: type[Report]) -> _CodecType:
85+
def get(cls, report_type: type[Report]) -> CodecType:
8886
"""
8987
Get the codec corresponding to the given report type.
9088
:param report_type: Report type

src/powerapi/database/csv/codecs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2828
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2929

30-
from datetime import datetime, timezone
30+
from datetime import datetime, UTC
3131

3232
from powerapi.database.codec import CodecOptions, ReportEncoder, ReportEncoderRegistry, ReportDecoder, ReportDecoderRegistry
3333
from powerapi.report import PowerReport, FormulaReport, HWPCReport
@@ -81,7 +81,7 @@ def decode(data: _SourcedCsvRowsType, opts: CodecOptions | None = None) -> HWPCR
8181
groups = {}
8282
for group_name, rows in data.items():
8383
first_row = next(iter(rows))
84-
timestamp = datetime.fromtimestamp(int(first_row['timestamp']) / 1000, tz=timezone.utc)
84+
timestamp = datetime.fromtimestamp(int(first_row['timestamp']) / 1000, tz=UTC)
8585
sensor = first_row['sensor']
8686
target = first_row['target']
8787
group = groups.setdefault(group_name, {})

src/powerapi/database/opentsdb/codecs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2828
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2929

30-
from datetime import timezone
30+
from datetime import UTC
3131

3232
from powerapi.database.codec import CodecOptions, ReportEncoder, ReportEncoderRegistry
3333
from powerapi.report import PowerReport
@@ -40,7 +40,7 @@ class PowerReportEncoder(ReportEncoder[PowerReport, tuple[float, dict]]):
4040

4141
@staticmethod
4242
def encode(report: PowerReport, opts: CodecOptions | None = None) -> tuple[float, dict]:
43-
timestamp = int(report.timestamp.replace(tzinfo=timezone.utc).timestamp())
43+
timestamp = int(report.timestamp.replace(tzinfo=UTC).timestamp())
4444
tags = {'timestamp': timestamp, 'host': report.sensor, 'target': report.target}
4545
return report.power, tags
4646

src/powerapi/database/socket/codecs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2828
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2929

30-
from datetime import datetime, timezone
30+
from datetime import datetime, UTC
3131

3232
from powerapi.database.codec import CodecOptions, ReportDecoder, ReportDecoderRegistry
3333
from powerapi.report import HWPCReport
@@ -40,7 +40,7 @@ class HWPCReportDecoder(ReportDecoder[dict, HWPCReport]):
4040

4141
@staticmethod
4242
def decode(data: dict, opts: CodecOptions | None = None) -> HWPCReport:
43-
timestamp = datetime.fromtimestamp(data['timestamp'] / 1000, tz=timezone.utc) # Unix timestamp in milliseconds
43+
timestamp = datetime.fromtimestamp(data['timestamp'] / 1000, tz=UTC) # Unix timestamp in milliseconds
4444
return HWPCReport(timestamp, data['sensor'], data['target'], data['groups'], data.get('metadata', {}))
4545

4646

tests/unit/database/test_csv.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2828
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2929

30-
from datetime import datetime, timezone
30+
from datetime import datetime, UTC
3131

3232
from powerapi.database.csv.codecs import HWPCReportDecoder
3333
from powerapi.report import HWPCReport
@@ -42,7 +42,7 @@ def test_decode_valid_csv_lines_with_one_events_group(self):
4242
"""
4343
Test to decode valid CSV lines with one events group.
4444
"""
45-
ts = int(datetime.now(timezone.utc).timestamp() * 1000) # milliseconds
45+
ts = int(datetime.now(tz=UTC).timestamp() * 1000) # milliseconds
4646
lines = {'testg': [
4747
{'timestamp': ts, 'sensor': 'pytest', 'target': 'example', 'socket': '0', 'cpu': '0', 'event1': 1, 'event2': 1},
4848
{'timestamp': ts, 'sensor': 'pytest', 'target': 'example', 'socket': '0', 'cpu': '1', 'event1': 2, 'event2': 2},
@@ -53,7 +53,7 @@ def test_decode_valid_csv_lines_with_one_events_group(self):
5353
report = HWPCReportDecoder().decode(lines)
5454

5555
assert isinstance(report, HWPCReport)
56-
assert report.timestamp == datetime.fromtimestamp(ts / 1000, timezone.utc)
56+
assert report.timestamp == datetime.fromtimestamp(ts / 1000, tz=UTC)
5757
assert report.sensor == 'pytest'
5858
assert report.target == 'example'
5959
assert report.metadata == {}
@@ -70,7 +70,7 @@ def test_decode_valid_csv_lines_with_multiple_events_groups(self):
7070
"""
7171
Test to decode valid CSV lines with multiple events groups.
7272
"""
73-
ts = int(datetime.now(timezone.utc).timestamp() * 1000) # milliseconds
73+
ts = int(datetime.now(tz=UTC).timestamp() * 1000) # milliseconds
7474
lines = {
7575
'testg1': [
7676
{'timestamp': ts, 'sensor': 'pytest', 'target': 'example', 'socket': '0', 'cpu': '0', 'event1': 1, 'event2': 1},
@@ -85,7 +85,7 @@ def test_decode_valid_csv_lines_with_multiple_events_groups(self):
8585
report = HWPCReportDecoder().decode(lines)
8686

8787
assert isinstance(report, HWPCReport)
88-
assert report.timestamp == datetime.fromtimestamp(ts / 1000, timezone.utc)
88+
assert report.timestamp == datetime.fromtimestamp(ts / 1000, tz=UTC)
8989
assert report.sensor == 'pytest'
9090
assert report.target == 'example'
9191
assert report.metadata == {}

tests/utils/db/db.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
from collections.abc import Iterable
3131
from contextlib import contextmanager
32-
from datetime import datetime, timezone
32+
from datetime import datetime, UTC
3333
from multiprocessing import Manager
3434
from uuid import uuid4
3535

@@ -44,7 +44,7 @@ def make_report(sensor: str = 'pytest', target: str | None = None) -> Report:
4444
:param target: Target name, random UUID4 if None
4545
:return: Initialized report
4646
"""
47-
timestamp = datetime.now(timezone.utc)
47+
timestamp = datetime.now(tz=UTC)
4848
target_name = target if target is not None else str(uuid4())
4949
return Report(timestamp, sensor, target_name)
5050

0 commit comments

Comments
 (0)