From 6e43be208883693487e8cb63ed97b0bca2195aa3 Mon Sep 17 00:00:00 2001 From: Forest Newark Date: Tue, 9 Dec 2025 15:48:09 -0500 Subject: [PATCH] Add support for Python 3.12 and 3.13 --- .github/workflows/python-package.yml | 20 +++++++++---------- CHANGELOG.rst | 4 ++++ .../agent_metadata/agent_metadata.py | 2 +- codeguru_profiler_agent/sampler.py | 2 +- codeguru_profiler_agent/utils/time.py | 6 +++--- setup.py | 8 ++++++++ test/unit/metrics/test_with_timer.py | 3 ++- test/unit/model/test_memory_counter.py | 7 ++++++- 8 files changed, 34 insertions(+), 18 deletions(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index cb41526..537953b 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -16,21 +16,19 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-20.04, ubuntu-latest, windows-latest, macos-latest] - python-version: ['3.6', '3.7', '3.8', '3.9', '3.10', '3.11'] + os: [ubuntu-latest, windows-latest, macos-latest] + python-version: ['3.6', '3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13'] exclude: + # ubuntu-latest (24.04) doesn't support Python 3.6-3.7 (EOL) - os: ubuntu-latest python-version: '3.6' - - os: ubuntu-20.04 + - os: ubuntu-latest + python-version: '3.7' + # macos-latest (ARM64) doesn't support Python 3.6-3.7 (never built for ARM64) + - os: macos-latest + python-version: '3.6' + - os: macos-latest python-version: '3.7' - - os: ubuntu-20.04 - python-version: '3.8' - - os: ubuntu-20.04 - python-version: '3.9' - - os: ubuntu-20.04 - python-version: '3.10' - - os: ubuntu-20.04 - python-version: '3.11' steps: - uses: actions/checkout@v3 diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 773085a..fa4e036 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,10 @@ CHANGELOG ========= +1.2.6 (layer_v13) +=================== +* Add support for Python 3.12 and 3.13 + 1.2.5 (layer_v12) =================== * Fix bug which causes agent to crash if line_no was None. diff --git a/codeguru_profiler_agent/agent_metadata/agent_metadata.py b/codeguru_profiler_agent/agent_metadata/agent_metadata.py index a9c6826..5bd9eac 100644 --- a/codeguru_profiler_agent/agent_metadata/agent_metadata.py +++ b/codeguru_profiler_agent/agent_metadata/agent_metadata.py @@ -9,7 +9,7 @@ # NOTE: Please do not alter the value for the following constants without the full knowledge of the use of them. # These constants are used in several scripts, including setup.py. __agent_name__ = "CodeGuruProfiler-python" -__agent_version__ = "1.2.5" +__agent_version__ = "1.2.6" def look_up_fleet_info( diff --git a/codeguru_profiler_agent/sampler.py b/codeguru_profiler_agent/sampler.py index ebef34f..38037b3 100644 --- a/codeguru_profiler_agent/sampler.py +++ b/codeguru_profiler_agent/sampler.py @@ -62,6 +62,6 @@ def _threads_to_sample_from(self, all_threads): if len(all_threads) > self._max_threads: if isinstance(all_threads, dict): all_threads = list(all_threads.keys()) - return random.sample(all_threads, self._max_threads) + return random.sample(all_threads, self._max_threads) # nosec B311 else: return list(all_threads) diff --git a/codeguru_profiler_agent/utils/time.py b/codeguru_profiler_agent/utils/time.py index a6f4095..2db41e7 100644 --- a/codeguru_profiler_agent/utils/time.py +++ b/codeguru_profiler_agent/utils/time.py @@ -1,13 +1,13 @@ from __future__ import absolute_import import time -from datetime import datetime +from datetime import datetime, timezone def to_iso(epoch_milli): try: - return datetime.utcfromtimestamp(epoch_milli / 1000).isoformat( - timespec='milliseconds') + "Z" # ISO 8601 date-time format + return datetime.fromtimestamp(epoch_milli / 1000, timezone.utc).replace( + tzinfo=None).isoformat(timespec='milliseconds') + "Z" # ISO 8601 date-time format except ValueError: return str(epoch_milli) diff --git a/setup.py b/setup.py index 1ebfd21..375d130 100755 --- a/setup.py +++ b/setup.py @@ -35,6 +35,14 @@ def find_version(*file_paths): download_url="https://github.com/aws/amazon-codeguru-profiler-python-agent", classifiers=[ "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Development Status :: 5 - Production/Stable", "Topic :: Utilities", "License :: OSI Approved :: Apache Software License" diff --git a/test/unit/metrics/test_with_timer.py b/test/unit/metrics/test_with_timer.py index 8105a49..eee801b 100644 --- a/test/unit/metrics/test_with_timer.py +++ b/test/unit/metrics/test_with_timer.py @@ -19,7 +19,8 @@ def foo_wall(self): def foo_cpu(self): # Call set_int_max_str for specific versions to test as its limited to resolve CVE-2020-10735 # (https://docs.python.org/3/library/stdtypes.html#integer-string-conversion-length-limitation) - if (sys.version_info >= (3, 7) and platform.system() != 'Windows') or (sys.version_info >= (3, 10) and platform.system() == 'Windows'): + # Note: set_int_max_str_digits was added in 3.10.2, 3.9.10, 3.8.12 (security backport) + if hasattr(sys, 'set_int_max_str_digits'): sys.set_int_max_str_digits(0) len(str(2 ** 500_000)) return diff --git a/test/unit/model/test_memory_counter.py b/test/unit/model/test_memory_counter.py index c842c6c..1e6287e 100644 --- a/test/unit/model/test_memory_counter.py +++ b/test/unit/model/test_memory_counter.py @@ -69,5 +69,10 @@ def test_sanity_check_it_counts_frame_file_path_line_no_class_name_size(self): subject.count_create_node(frame="test/frame", file_path="test/file/path", class_name="TestClass") # [Oct-2020 Python-3.7.7] "test/frame" size: 59 bytes; "test/file/path" size: 63 bytes; "TestClass" size: # 58 bytes; fixed line_no size: 2 * 32 = 64; sum = 244 - expected_size = subject.empty_node_size_bytes + 244 + # [Dec-2025 Python-3.12+] Internal string memory optimization reduced size by 24 bytes; sum = 220 + import sys + if sys.version_info >= (3, 12): + expected_size = subject.empty_node_size_bytes + 220 + else: + expected_size = subject.empty_node_size_bytes + 244 assert (subject.get_memory_usage_bytes() == expected_size)