Skip to content

[v4.0] Update use of type annotations#1017

Open
anoto-moniz wants to merge 5 commits intorelease/v4.0from
use-new-python-features
Open

[v4.0] Update use of type annotations#1017
anoto-moniz wants to merge 5 commits intorelease/v4.0from
use-new-python-features

Conversation

@anoto-moniz
Copy link
Collaborator

A handful of updates and improvements came into type annotations in Python 3.9 and 3.10. The ones most relevant to us are the introduction of | for union types, the ability to use builtin classes as annotations (i.e. list), and the deprecation of a handful of types in typing in favor of referencing them in collections.abc.

We could also replace our usages of Optional[T] with T | None, but the latter syntax doesn't seem as clear to me.

We're also clear to start using match statements and the dictionary update operator, it's just harder to identify opportunities for them without knowing where to look.

Note: a couple classes (namely DataConceptsCollection and PredictorEvaluationCollection) still have methods that return List. It seems the list method defined in Collection is conflicting with the built-in in those cases. I'm not sure why, but will be investigating in a follow-up.

PR Type:

  • Breaking change (fix or feature that would cause existing functionality to change)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Maintenance (non-breaking change to assist developers)

Adherence to team decisions

  • I have added tests for 100% coverage
  • I have written Numpy-style docstrings for every method and class.
  • I have communicated the downstream consequences of the PR to others.
  • I have bumped the version in __version__.py

As of python 3.9, the builtin classes can be used as type annotations,
so there's no need to use the separate "typing" versions (which are also
deprecated).

Note that data_objects and predictor_evaluation retain List for now, as
it conflicts with their definition of a method called "list".
As of python 3.10, unions can be expressed with the pipe (|) operator.
Clean up all the unused imports created by the previous two changes. It
was easier to handle them all at once rather than as I went.
Many types introduced as type annotations in typing are now available
for use from collections.abc. The typing versions are deprecated, so we
switch to these newer versions. For us, this impacts Sequence, Iterator,
Iterable, Callable, and (in one place) Collection.
@anoto-moniz anoto-moniz marked this pull request as ready for review February 17, 2026 20:35
@anoto-moniz anoto-moniz requested a review from a team as a code owner February 17, 2026 20:35
Copy link
Collaborator

@kroenlein kroenlein left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I transformed a lot of Optional[x] to x | None, and there are a lot more left. Seems like it's the better pattern.


def __init__(self,
klass: typing.Type[typing.Any],
klass: type[typing.Any],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this just be a naked type?

"""Batching by clusters where nothing references anything outside the cluster."""

def batch(self, objects: Iterable[DataConcepts], batch_size) -> List[List[DataConcepts]]:
def batch(self, objects: Iterable[DataConcepts], batch_size) -> list[list[DataConcepts]]:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def batch(self, objects: Iterable[DataConcepts], batch_size) -> list[list[DataConcepts]]:
def batch(self, objects: Iterable[DataConcepts], batch_size: int) -> list[list[DataConcepts]]:

"""Batching by object type."""

def batch(self, objects: Iterable[DataConcepts], batch_size) -> List[List[DataConcepts]]:
def batch(self, objects: Iterable[DataConcepts], batch_size) -> list[list[DataConcepts]]:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def batch(self, objects: Iterable[DataConcepts], batch_size) -> list[list[DataConcepts]]:
def batch(self, objects: Iterable[DataConcepts], batch_size: int) -> list[list[DataConcepts]]:

The list of features to exclude, either by name or by group alias. Default is none.
The final set of features generated by the predictor is set(features) - set(excludes).
powers: Optional[List[float]]
powers: Optional[list[int]]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think maybe an accidental regression?

Suggested change
powers: Optional[list[int]]
powers: Optional[list[float]]

Comment on lines +110 to +111
branch_version_id: Optional[UUID | str] = None,
version: Optional[int | str] = None) -> Iterator[ExperimentDataSource]:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
branch_version_id: Optional[UUID | str] = None,
version: Optional[int | str] = None) -> Iterator[ExperimentDataSource]:
branch_version_id: UUID | str | None = None,
version: int | str | None = None) -> Iterator[ExperimentDataSource]:

predictors: List[PredictorNode],
training_data: Optional[List[DataSource]] = None):
predictors: list[PredictorNode],
training_data: Optional[list[DataSource]] = None):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
training_data: Optional[list[DataSource]] = None):
training_data: list[DataSource] | None = None):

-------
Union[PredictorEvaluationExecution, DesignExecution, GenerativeDesignExecution,
SampleDesignSpaceExecution]
ExectutionType
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ExectutionType
ExecutionType

@@ -1,8 +1,9 @@
import csv
import json
from typing import Iterator
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
from typing import Iterator
from collections.abc import Iterator

label: Optional[tuple[str, float]]
multiplier for a label in the numerator of the ratio
basis_ingredients: Optional[Union[list[str], dict[str, float]]]
basis_ingredients: Optional[list[str] | dict[str | float]]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
basis_ingredients: Optional[list[str] | dict[str | float]]
basis_ingredients: Optional[list[str] | dict[str, float]]

basis_ingredients: Optional[list[str] | dict[str | float]]
the ingredients which should appear in the denominator of the ratio
basis_labels: Optional[Union[list[str], dict[str, float]]]
basis_labels: Optional[list[str] | dict[str | float]]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
basis_labels: Optional[list[str] | dict[str | float]]
basis_labels: Optional[list[str] | dict[str, float]]

Copy link
Collaborator

@kroenlein kroenlein left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I transformed a lot of Optional[x] to x | None, and there are a lot more left. Seems like it's the better pattern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants