This is an automated email from the ASF dual-hosted git repository.

ebenizzy pushed a commit to branch remove-3.9-support
in repository https://gitbox.apache.org/repos/asf/hamilton.git

commit 9d7292bf7b90d471502246c8e54df529640e54d8
Author: Elijah ben Izzy <[email protected]>
AuthorDate: Sun Oct 19 10:22:47 2025 -0700

    Drops support for 3.9, adds support for 3.13
    
    3.9 is EOL in october. This also fixes some iffy numpy tests that relied on
    unspecified numpy behavior with type-annotations for shapes
---
 .github/workflows/hamilton-lsp.yml     |   2 +-
 .github/workflows/hamilton-main.yml    |   3 +--
 .github/workflows/hamilton-sdk.yml     |   2 +-
 examples/hello_world/my_dag.png        | Bin 68544 -> 63755 bytes
 examples/styling_visualization/dag.png | Bin 297452 -> 341276 bytes
 hamilton/node.py                       |  12 +++++++-----
 pyproject.toml                         |   5 ++---
 tests/test_node.py                     |   7 +++----
 8 files changed, 15 insertions(+), 16 deletions(-)

diff --git a/.github/workflows/hamilton-lsp.yml 
b/.github/workflows/hamilton-lsp.yml
index 83e17dc6..b1d23c22 100644
--- a/.github/workflows/hamilton-lsp.yml
+++ b/.github/workflows/hamilton-lsp.yml
@@ -17,7 +17,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        python-version: ['3.9', '3.10', '3.11']
+        python-version: ['3.10', '3.11', '3.12', '3.13']
     defaults:
       run:
         working-directory: dev_tools/language_server
diff --git a/.github/workflows/hamilton-main.yml 
b/.github/workflows/hamilton-main.yml
index 15495039..b1039c81 100644
--- a/.github/workflows/hamilton-main.yml
+++ b/.github/workflows/hamilton-main.yml
@@ -23,11 +23,10 @@ jobs:
         os:
           - ubuntu-latest
         python-version:
-          - '3.8'
-          - '3.9'
           - '3.10'
           - '3.11'
           - '3.12'
+          - '3.13'
     env:
       UV_PRERELEASE: "allow"
       HAMILTON_TELEMETRY_ENABLED: false
diff --git a/.github/workflows/hamilton-sdk.yml 
b/.github/workflows/hamilton-sdk.yml
index 5ec89e5a..d5f539f4 100644
--- a/.github/workflows/hamilton-sdk.yml
+++ b/.github/workflows/hamilton-sdk.yml
@@ -17,7 +17,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        python-version: ['3.9', '3.10', '3.11']
+        python-version: ['3.10', '3.11', '3.12', '3.13']
     defaults:
       run:
         working-directory: ui/sdk
diff --git a/examples/hello_world/my_dag.png b/examples/hello_world/my_dag.png
index 77e64e42..b77a634a 100644
Binary files a/examples/hello_world/my_dag.png and 
b/examples/hello_world/my_dag.png differ
diff --git a/examples/styling_visualization/dag.png 
b/examples/styling_visualization/dag.png
index ceda0c39..80da1082 100644
Binary files a/examples/styling_visualization/dag.png and 
b/examples/styling_visualization/dag.png differ
diff --git a/hamilton/node.py b/hamilton/node.py
index 5a0ba3f5..3122cafe 100644
--- a/hamilton/node.py
+++ b/hamilton/node.py
@@ -68,7 +68,7 @@ class Node(object):
         doc_string: str = "",
         callabl: Callable = None,
         node_source: NodeType = NodeType.STANDARD,
-        input_types: Dict[str, Union[Type, Tuple[Type, DependencyType]]] = 
None,
+        input_types: Optional[Dict[str, Union[Type, Tuple[Type, 
DependencyType]]]] = None,
         tags: Dict[str, Any] = None,
         namespace: Tuple[str, ...] = (),
         originating_functions: Optional[Tuple[Callable, ...]] = None,
@@ -118,8 +118,9 @@ class Node(object):
                 # assume optional values passed
                 self._default_parameter_values = optional_values if 
optional_values else {}
             else:
-                # TODO -- remove this when we no longer support 3.8 -- 
10/14/2024
-                type_hint_kwargs = {} if sys.version_info < (3, 9) else 
{"include_extras": True}
+                type_hint_kwargs: dict[str, Any] = {"include_extras": True}
+                if sys.version_info >= (3, 13):
+                    type_hint_kwargs["globalns"] = callabl.__globals__
                 input_types = typing.get_type_hints(callabl, 
**type_hint_kwargs)
                 signature = inspect.signature(callabl)
                 for key, value in signature.parameters.items():
@@ -291,8 +292,9 @@ class Node(object):
         """
         if name is None:
             name = fn.__name__
-        # TODO -- remove this when we no longer support 3.8 -- 10/14/2024
-        type_hint_kwargs = {} if sys.version_info < (3, 9) else 
{"include_extras": True}
+        type_hint_kwargs = {"include_extras": True}
+        if sys.version_info >= (3, 13):
+            type_hint_kwargs["globalns"] = fn.__globals__
         return_type = typing.get_type_hints(fn, 
**type_hint_kwargs).get("return")
         if return_type is None:
             raise ValueError(f"Missing type hint for return value in function 
{fn.__qualname__}.")
diff --git a/pyproject.toml b/pyproject.toml
index 2e58e897..bfa3f85e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -26,7 +26,7 @@ version = "1.89.0"  # NOTE: keep this in sync with 
hamilton/version.py
 # dynamic = ["version"]
 description = "Hamilton, the micro-framework for creating dataframes."
 readme = "README.md"
-requires-python = ">=3.8.1, <4"
+requires-python = ">=3.10.1, <4"
 license = {text = "Apache-2.0"}
 keywords = ["hamilton"]
 authors = [
@@ -39,11 +39,10 @@ classifiers = [
     "Natural Language :: English",
     "License :: OSI Approved :: Apache Software License",
     "Programming Language :: Python :: 3",
-    "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"
 ]
 dependencies = [
     "numpy",
diff --git a/tests/test_node.py b/tests/test_node.py
index 0411f055..111870f0 100644
--- a/tests/test_node.py
+++ b/tests/test_node.py
@@ -65,7 +65,6 @@ np_version = np.__version__
 major, minor, _ = map(int, np_version.split("."))
 
 
[email protected](sys.version_info < (3, 9), reason="requires python 3.9 or 
higher")
 def test_node_handles_annotated():
     from typing import Annotated
 
@@ -77,7 +76,7 @@ def test_node_handles_annotated():
 
     node = Node.from_fn(annotated_func)
     assert node.name == "annotated_func"
-    if major == 2 and minor > 1 and sys.version_info > (3, 9):  # greater that 
2.1
+    if major == 2 and minor > 1 and sys.version_info < (3, 13):  # greater 
that 2.1
         expected = {
             "first": (
                 Annotated[np.ndarray[tuple[int, ...], np.dtype[np.float64]], 
Literal["N"]],
@@ -89,12 +88,12 @@ def test_node_handles_annotated():
     else:
         expected = {
             "first": (
-                Annotated[np.ndarray[Any, np.dtype[np.float64]], Literal["N"]],
+                Annotated[np.ndarray[tuple[Any, ...], np.dtype[np.float64]], 
Literal["N"]],
                 DependencyType.REQUIRED,
             ),
             "other": (float, DependencyType.OPTIONAL),
         }
-        expected_type = Annotated[np.ndarray[Any, np.dtype[np.float64]], 
Literal["N"]]
+        expected_type = Annotated[np.ndarray[tuple[Any, ...], 
np.dtype[np.float64]], Literal["N"]]
     assert node.input_types == expected
     assert node.type == expected_type
 

Reply via email to