Skip to content

Commit

Permalink
Require >=Python3.10 (#1950)
Browse files Browse the repository at this point in the history
Co-authored-by: Håkon V. Treider <[email protected]>
  • Loading branch information
erlendvollset and haakonvt authored Oct 10, 2024
1 parent a0e5a63 commit 276e10d
Show file tree
Hide file tree
Showing 119 changed files with 598 additions and 1,230 deletions.
7 changes: 3 additions & 4 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "Dev Container for Cognite Python SDK",

// Python base image reference: https://github.com/devcontainers/images/tree/main/src/python
"image": "mcr.microsoft.com/devcontainers/python:3.8-bullseye",
"image": "mcr.microsoft.com/devcontainers/python:3.10-bullseye",

// Features to add to the dev container. More info: https://containers.dev/features
"features": {
Expand All @@ -23,9 +23,8 @@
"streetsidesoftware.code-spell-checker"
],
"settings": {
// This is the path to the Poetry enabled Python environment, seen in the "Executable" setting by running "poetry env info"
"python.defaultInterpreterPath": "~/.cache/pypoetry/virtualenvs/cognite-sdk-gQQjLrWz-py3.8/bin/python"
"python.defaultInterpreterPath": "~/.cache/pypoetry/virtualenvs/cognite-sdk-*-py3.10/bin/python"
}
}
}
}
}
9 changes: 5 additions & 4 deletions .devcontainer/postCreateCommand.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
#!/usr/bin/env bash

# Copy in default VSCode settings file as part of initial devcontainer create process.
# This instead of a checked-in .vscode/settings.json file, to not overwrite user provided settings for normal local dev setups.
# This avoids overwriting user-provided settings for normal local dev setups.
mkdir -p .vscode
cp .devcontainer/vscode.default.settings.json .vscode/settings.json

# Install all dependencies with Poetry
poetry install -E all
# Configure Poetry to create virtual environments inside the project directory
poetry config virtualenvs.in-project true

# Install pre-commit hook
poetry env use python3.10
poetry install -E all
poetry run pre-commit install
2 changes: 1 addition & 1 deletion .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ inputs:
python_version:
description: 'Python version to set up'
required: false
default: "3.8"
default: "3.10"
extras:
description: 'extra deps: poetry install -E whatever'
required: false
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
python-version: ["3.8", "3.10", "3.11", "3.12"] # TODO: 3.9, 3.10 (requires a lot of work for FakeCogResGen for tests)
python-version: ["3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup
Expand All @@ -68,6 +68,6 @@ jobs:
run: pytest --durations=10 --cov --cov-report term --cov-report xml:coverage.xml -n8 --dist loadscope --reruns 2 --maxfail 20

- uses: codecov/codecov-action@v4
if: matrix.os == 'windows-latest' && matrix.python-version == '3.8'
if: matrix.os == 'windows-latest' && matrix.python-version == '3.10'
with:
token: ${{ secrets.CODECOV_TOKEN }}
4 changes: 2 additions & 2 deletions .github/workflows/verify-jupyter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.8"
cache: "pip"
python-version: '3.10'
cache: 'pip'
- name: Build package using poetry
run: |
pip install poetry
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/verify-streamlit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.8"
cache: "pip"
python-version: '3.10'
cache: 'pip'
- name: Build package using poetry
run: |
pip install poetry
Expand Down
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ repos:
- --fix
- --exit-non-zero-on-fix
- --line-length=120
- --ignore=E731,E501,W605
- --ignore=E731,E501,W605,UP038
# See https://beta.ruff.rs/docs/rules for an overview of ruff rules
- --select=E,W,F,I,T,RUF,TID,UP
- --fixable=E,W,F,I,T,RUF,TID,UP
- --target-version=py38
- --target-version=py310
- --exclude=cognite/client/_proto
- id: ruff-format
args:
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ Changes are grouped as follows
- `Fixed` for any bug fixes.
- `Security` in case of vulnerabilities.

## [7.63.0] - 2024-10-10
### Removed
- Removed support for Python 3.8 and 3.9.

## [7.62.8] - 2024-10-07
### Added
- [Feature Preview - alpha] Support for `PostgresGateway` `Users` `client.postegres_gateway.users`.
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ git clone https://github.com/cognitedata/cognite-sdk-python.git
cd cognite-sdk-python
```

We use [poetry](https://pypi.org/project/poetry/) for dependency- and virtual environment management. Make sure you use python 3.8.
We use [poetry](https://pypi.org/project/poetry/) for dependency- and virtual environment management. Make sure you use python 3.10.

Install dependencies and initialize a shell within the virtual environment, with these commands:

Expand Down
10 changes: 3 additions & 7 deletions cognite/client/_api/annotations.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from __future__ import annotations

from collections.abc import Sequence
from copy import deepcopy
from typing import TYPE_CHECKING, Any, Literal, Sequence, cast, overload
from typing import TYPE_CHECKING, Any, Literal, cast, overload

from cognite.client._api_client import APIClient
from cognite.client._constants import DEFAULT_LIMIT_READ
Expand Down Expand Up @@ -138,12 +139,7 @@ def update(
Args:
item (Annotation | AnnotationWrite | AnnotationUpdate | Sequence[Annotation | AnnotationWrite | AnnotationUpdate]): Annotation or list of annotations to update (or patch or list of patches to apply)
mode (Literal["replace_ignore_null", "patch", "replace"]): How to update data when a non-update
object is given (Annotation or -Write). If you use 'replace_ignore_null', only the fields
you have set will be used to replace existing (default). Using 'replace' will additionally
clear all the fields that are not specified by you. Last option, 'patch', will update only
the fields you have set and for container-like fields such as metadata or labels, add the
values to the existing. For more details, see :ref:`appendix-update`.
mode (Literal['replace_ignore_null', 'patch', 'replace']): How to update data when a non-update object is given (Annotation or -Write). If you use 'replace_ignore_null', only the fields you have set will be used to replace existing (default). Using 'replace' will additionally clear all the fields that are not specified by you. Last option, 'patch', will update only the fields you have set and for container-like fields such as metadata or labels, add the values to the existing. For more details, see :ref:`appendix-update`.
Returns:
Annotation | AnnotationList: No description."""
Expand Down
39 changes: 13 additions & 26 deletions cognite/client/_api/assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,20 @@
import operator as op
import threading
import warnings
from collections.abc import Callable, Iterable, Iterator, Sequence
from functools import cached_property
from types import MappingProxyType
from typing import (
TYPE_CHECKING,
Any,
Callable,
Dict,
Iterable,
Iterator,
List,
Literal,
NamedTuple,
NoReturn,
Sequence,
Tuple,
Union,
TypeAlias,
cast,
overload,
)

from typing_extensions import TypeAlias

from cognite.client._api_client import APIClient
from cognite.client._constants import DEFAULT_LIMIT_READ
from cognite.client.data_classes import (
Expand Down Expand Up @@ -73,13 +65,13 @@

AggregateAssetProperty: TypeAlias = Literal["child_count", "path", "depth"]

SortSpec: TypeAlias = Union[
AssetSort,
str,
SortableAssetProperty,
Tuple[str, Literal["asc", "desc"]],
Tuple[str, Literal["asc", "desc"], Literal["auto", "first", "last"]],
]
SortSpec: TypeAlias = (
AssetSort
| str
| SortableAssetProperty
| tuple[str, Literal["asc", "desc"]]
| tuple[str, Literal["asc", "desc"], Literal["auto", "first", "last"]]
)

_FILTERS_SUPPORTED: frozenset[type[Filter]] = _BASIC_FILTERS | {filters.Search}

Expand Down Expand Up @@ -610,7 +602,7 @@ def create_hierarchy(
Args:
assets (Sequence[Asset | AssetWrite] | AssetHierarchy): List of assets to create or an instance of AssetHierarchy.
upsert (bool): If used, already existing assets will be updated instead of an exception being raised. You may control how updates are applied with the 'upsert_mode' argument.
upsert_mode (Literal["patch", "replace"]): Only applicable with upsert. Pass 'patch' to only update fields with non-null values (default), or 'replace' to do full updates (unset fields become null or empty).
upsert_mode (Literal['patch', 'replace']): Only applicable with upsert. Pass 'patch' to only update fields with non-null values (default), or 'replace' to do full updates (unset fields become null or empty).
Returns:
AssetList: Created (and possibly updated) asset hierarchy
Expand Down Expand Up @@ -778,12 +770,7 @@ def update(
Args:
item (Asset | AssetWrite | AssetUpdate | Sequence[Asset | AssetWrite | AssetUpdate]): Asset(s) to update
mode (Literal["replace_ignore_null", "patch", "replace"]): How to update data when a non-update
object is given (Asset or -Write). If you use 'replace_ignore_null', only the fields
you have set will be used to replace existing (default). Using 'replace' will additionally
clear all the fields that are not specified by you. Last option, 'patch', will update only
the fields you have set and for container-like fields such as metadata or labels, add the
values to the existing. For more details, see :ref:`appendix-update`.
mode (Literal['replace_ignore_null', 'patch', 'replace']): How to update data when a non-update object is given (Asset or -Write). If you use 'replace_ignore_null', only the fields you have set will be used to replace existing (default). Using 'replace' will additionally clear all the fields that are not specified by you. Last option, 'patch', will update only the fields you have set and for container-like fields such as metadata or labels, add the values to the existing. For more details, see :ref:`appendix-update`.
Returns:
Asset | AssetList: Updated asset(s)
Expand Down Expand Up @@ -856,7 +843,7 @@ def upsert(
Args:
item (Asset | AssetWrite | Sequence[Asset | AssetWrite]): Asset or list of assets to upsert.
mode (Literal["patch", "replace"]): Whether to patch or replace in the case the assets are existing. If you set 'patch', the call will only update fields with non-null values (default). Setting 'replace' will unset any fields that are not specified.
mode (Literal['patch', 'replace']): Whether to patch or replace in the case the assets are existing. If you set 'patch', the call will only update fields with non-null values (default). Setting 'replace' will unset any fields that are not specified.
Returns:
Asset | AssetList: The upserted asset(s).
Expand Down Expand Up @@ -1324,7 +1311,7 @@ def _insert(
return _TaskResult(successful, failed, unknown)

# Split assets based on their is-duplicated status:
non_dupes, dupe_assets = self._split_out_duplicated(cast(List[Dict], err.duplicated), assets)
non_dupes, dupe_assets = self._split_out_duplicated(cast(list[dict], err.duplicated), assets)
# We should try to create the non-duplicated assets before running update (as these might be dependent):
if non_dupes:
result = self._insert(non_dupes, no_recursion=True, upsert=False, upsert_mode=upsert_mode)
Expand Down
3 changes: 2 additions & 1 deletion cognite/client/_api/data_modeling/containers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

from typing import TYPE_CHECKING, Iterator, Literal, Sequence, cast, overload
from collections.abc import Iterator, Sequence
from typing import TYPE_CHECKING, Literal, cast, overload

from cognite.client._api_client import APIClient
from cognite.client._constants import DATA_MODELING_DEFAULT_LIMIT_READ
Expand Down
3 changes: 2 additions & 1 deletion cognite/client/_api/data_modeling/data_models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

from typing import TYPE_CHECKING, Iterator, Literal, Sequence, cast, overload
from collections.abc import Iterator, Sequence
from typing import TYPE_CHECKING, Literal, cast, overload

from cognite.client._api_client import APIClient
from cognite.client._constants import DATA_MODELING_DEFAULT_LIMIT_READ
Expand Down
29 changes: 11 additions & 18 deletions cognite/client/_api/data_modeling/instances.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,19 @@
import logging
import random
import time
from collections.abc import Iterable
from collections.abc import Callable, Iterable, Iterator, Sequence
from datetime import datetime, timezone
from threading import Thread
from typing import (
TYPE_CHECKING,
Any,
Callable,
Generic,
Iterator,
List,
Literal,
Sequence,
Tuple,
Union,
TypeAlias,
cast,
overload,
)

from typing_extensions import TypeAlias

from cognite.client._api_client import APIClient
from cognite.client._constants import DEFAULT_LIMIT_READ
from cognite.client.data_classes import filters
Expand Down Expand Up @@ -89,7 +82,7 @@
logger = logging.getLogger(__name__)


Source: TypeAlias = Union[SourceSelector, View, ViewId, Tuple[str, str], Tuple[str, str, str]]
Source: TypeAlias = SourceSelector | View | ViewId | tuple[str, str] | tuple[str, str, str]


class _NodeOrEdgeResourceAdapter(Generic[T_Node, T_Edge]):
Expand Down Expand Up @@ -233,7 +226,7 @@ def __call__(
Args:
chunk_size (int | None): Number of data_models to return in each chunk. Defaults to yielding one instance at a time.
instance_type (Literal["node", "edge"]): Whether to query for nodes or edges.
instance_type (Literal['node', 'edge']): Whether to query for nodes or edges.
limit (int | None): Maximum number of instances to return. Defaults to returning all items.
include_typing (bool): Whether to return property type information as part of the result.
sources (Source | Sequence[Source] | None): Views to retrieve properties from.
Expand All @@ -259,7 +252,7 @@ def __call__(
raise ValueError(f"Invalid instance type: {instance_type}")
if not include_typing:
return cast(
Union[Iterator[Edge], Iterator[EdgeList], Iterator[Node], Iterator[NodeList]],
Iterator[Edge] | Iterator[EdgeList] | Iterator[Node] | Iterator[NodeList],
self._list_generator(
list_cls=list_cls,
resource_cls=resource_cls,
Expand Down Expand Up @@ -700,7 +693,7 @@ def delete(
"""
identifiers = self._load_node_and_edge_ids(nodes, edges)
deleted_instances = cast(
List,
list,
self._delete_multiple(
identifiers,
wrap_ids=True,
Expand Down Expand Up @@ -1057,7 +1050,7 @@ def search(
Args:
view (ViewId): View to search in.
query (str | None): Query string that will be parsed and used for search.
instance_type (Literal["node", "edge"] | type[T_Node] | type[T_Edge]): Whether to search for nodes or edges. You can also pass a custom typed node (or edge class) inheriting from TypedNode (or TypedEdge). See apply, retrieve_nodes or retrieve_edges for an example.
instance_type (Literal['node', 'edge'] | type[T_Node] | type[T_Edge]): Whether to search for nodes or edges. You can also pass a custom typed node (or edge class) inheriting from TypedNode (or TypedEdge). See apply, retrieve_nodes or retrieve_edges for an example.
properties (list[str] | None): Optional array of properties you want to search through. If you do not specify one or more properties, the service will search all text fields within the view.
target_units (list[TargetUnit] | None): Properties to convert to another unit. The API can only convert to another unit if a unit has been defined as part of the type on the underlying container being queried.
space (str | SequenceNotStr[str] | None): Restrict instance search to the given space (or list of spaces).
Expand Down Expand Up @@ -1201,7 +1194,7 @@ def aggregate(
view (ViewId): View to aggregate over.
aggregates (MetricAggregation | dict | Sequence[MetricAggregation | dict]): The properties to aggregate over.
group_by (str | SequenceNotStr[str] | None): The selection of fields to group the results by when doing aggregations. You can specify up to 5 items to group by.
instance_type (Literal["node", "edge"]): The type of instance.
instance_type (Literal['node', 'edge']): The type of instance.
query (str | None): Optional query string. The API will parse the query string, and use it to match the text properties on elements to use for the aggregate(s).
properties (str | SequenceNotStr[str] | None): Optional list of properties you want to apply the query to. If you do not list any properties, you search through text fields by default.
target_units (list[TargetUnit] | None): Properties to convert to another unit. The API can only convert to another unit if a unit has been defined as part of the type on the underlying container being queried.
Expand Down Expand Up @@ -1303,7 +1296,7 @@ def histogram(
Args:
view (ViewId): View to to aggregate over.
histograms (Histogram | Sequence[Histogram]): The properties to aggregate over.
instance_type (Literal["node", "edge"]): Whether to search for nodes or edges.
instance_type (Literal['node', 'edge']): Whether to search for nodes or edges.
query (str | None): Query string that will be parsed and used for search.
properties (SequenceNotStr[str] | None): Optional array of properties you want to search through. If you do not specify one or more properties, the service will search all text fields within the view.
target_units (list[TargetUnit] | None): Properties to convert to another unit. The API can only convert to another unit if a unit has been defined as part of the type on the underlying container being queried.
Expand Down Expand Up @@ -1518,7 +1511,7 @@ def list(
"""`List instances <https://developer.cognite.com/api#tag/Instances/operation/advancedListInstance>`_
Args:
instance_type (Literal["node", "edge"] | type[T_Node] | type[T_Edge]): Whether to query for nodes or edges. You can also pass a custom typed node (or edge class) inheriting from TypedNode (or TypedEdge). See apply, retrieve_nodes or retrieve_edges for an example.
instance_type (Literal['node', 'edge'] | type[T_Node] | type[T_Edge]): Whether to query for nodes or edges. You can also pass a custom typed node (or edge class) inheriting from TypedNode (or TypedEdge). See apply, retrieve_nodes or retrieve_edges for an example.
include_typing (bool): Whether to return property type information as part of the result.
sources (Source | Sequence[Source] | None): Views to retrieve properties from.
space (str | SequenceNotStr[str] | None): Only return instances in the given space (or list of spaces).
Expand Down Expand Up @@ -1585,7 +1578,7 @@ def list(
raise ValueError(f"Invalid instance type: {instance_type}")

return cast(
Union[NodeList[T_Node], EdgeList[T_Edge]],
NodeList[T_Node] | EdgeList[T_Edge],
self._list(
list_cls=list_cls,
resource_cls=resource_cls,
Expand Down
3 changes: 2 additions & 1 deletion cognite/client/_api/data_modeling/spaces.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

from typing import TYPE_CHECKING, Iterator, Sequence, cast, overload
from collections.abc import Iterator, Sequence
from typing import TYPE_CHECKING, cast, overload

from cognite.client._api_client import APIClient
from cognite.client._constants import DEFAULT_LIMIT_READ
Expand Down
3 changes: 2 additions & 1 deletion cognite/client/_api/data_modeling/views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from __future__ import annotations

from collections import defaultdict
from typing import TYPE_CHECKING, Iterator, Sequence, cast, overload
from collections.abc import Iterator, Sequence
from typing import TYPE_CHECKING, cast, overload

from cognite.client._api_client import APIClient
from cognite.client._constants import DATA_MODELING_DEFAULT_LIMIT_READ
Expand Down
Loading

0 comments on commit 276e10d

Please sign in to comment.