Add max deps and bump old ones
All checks were successful
Publish documentation / publish (push) Successful in 51s
Check / Test on Python 3.10 (push) Successful in 1m1s
Check / Lint, format & type checks (push) Successful in 1m9s
Check / Test on Python 3.11 (push) Successful in 51s
Check / Test on Python 3.12 (push) Successful in 58s
Check / Test on Python 3.13 (push) Successful in 55s

This commit is contained in:
Andras Schmelczer 2026-06-06 22:29:16 +01:00
parent 2403a20ed0
commit c55eba2077
18 changed files with 98 additions and 75 deletions

View file

@ -6,6 +6,7 @@ from typing import (
Callable, Callable,
Generic, Generic,
List, List,
Literal,
Optional, Optional,
Sequence, Sequence,
Tuple, Tuple,
@ -17,7 +18,6 @@ from typing import (
from fastapi import FastAPI from fastapi import FastAPI
from tqdm import tqdm from tqdm import tqdm
from typing_extensions import Literal # <= Python 3.7
from ..constants import DASHBOARD_PATH from ..constants import DASHBOARD_PATH
from ..context import get_context from ..context import get_context

View file

@ -1,7 +1,7 @@
from pathlib import Path from pathlib import Path
from a2wsgi import WSGIMiddleware
from fastapi import FastAPI from fastapi import FastAPI
from fastapi.middleware.wsgi import WSGIMiddleware
from fastapi.responses import FileResponse, RedirectResponse from fastapi.responses import FileResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
@ -19,7 +19,10 @@ def bootstrap_dashboard(app: FastAPI, function_name: str, documentation: str) ->
def get_favicon() -> FileResponse: def get_favicon() -> FileResponse:
return FileResponse(PATH / "dashboard/assets/favicon.ico") return FileResponse(PATH / "dashboard/assets/favicon.ico")
app.mount(DASHBOARD_PATH, WSGIMiddleware(dash_app)) # a2wsgi types its WSGI input (Flask) and ASGI output more strictly than
# Starlette's loose WSGIApp/ASGIApp aliases, so mypy flags the mount despite
# this being the canonical, runtime-correct way to bridge the Dash app.
app.mount(DASHBOARD_PATH, WSGIMiddleware(dash_app)) # type: ignore[arg-type]
@app.get("/", include_in_schema=False) @app.get("/", include_in_schema=False)
def redirect_to_entrypoint() -> RedirectResponse: def redirect_to_entrypoint() -> RedirectResponse:

View file

@ -16,7 +16,8 @@ def get_description(
style={"color": accent_color}, style={"color": accent_color},
), ),
dcc.Markdown( dcc.Markdown(
strip_lines(f""" strip_lines(
f"""
> View the live data of your deployment here. > View the live data of your deployment here.
## Using the API ## Using the API
@ -26,7 +27,8 @@ def get_description(
## Details ## Details
{function_docs} {function_docs}
"""), """
),
className="description", className="description",
), ),
] ]

View file

@ -7,9 +7,7 @@ from abc import ABC, abstractmethod
from functools import lru_cache from functools import lru_cache
from pathlib import Path from pathlib import Path
from types import TracebackType from types import TracebackType
from typing import IO, Any, List, Optional, Type, Union, cast from typing import IO, Any, List, Literal, Optional, Type, Union, cast
from typing_extensions import Literal # <= Python 3.7
from great_ai.utilities import ConfigFile, get_logger from great_ai.utilities import ConfigFile, get_logger

View file

@ -1,8 +1,19 @@
from functools import wraps from functools import wraps
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, TypeVar, Union, cast from typing import (
Any,
Callable,
Dict,
List,
Literal,
Optional,
Set,
Tuple,
TypeVar,
Union,
cast,
)
from dill import load from dill import load
from typing_extensions import Literal # <= Python 3.7
from ..context import get_context from ..context import get_context
from ..helper import get_function_metadata_store from ..helper import get_function_metadata_store

View file

@ -1,4 +1,4 @@
from datetime import datetime from datetime import datetime, timezone
from math import ceil from math import ceil
from random import shuffle from random import shuffle
from typing import Any, Iterable, List, TypeVar, Union, cast from typing import Any, Iterable, List, TypeVar, Union, cast
@ -94,7 +94,7 @@ def add_ground_truth(
) )
shuffle(split_tags) shuffle(split_tags)
created = datetime.utcnow().isoformat() created = datetime.now(timezone.utc).replace(tzinfo=None).isoformat()
traces = [ traces = [
cast( cast(
Trace[T], Trace[T],

View file

@ -1,12 +1,10 @@
from contextvars import ContextVar from contextvars import ContextVar
from datetime import datetime from datetime import datetime, timezone
from time import perf_counter from time import perf_counter
from types import TracebackType from types import TracebackType
from typing import Any, Dict, Generic, List, Optional, Type, TypeVar, cast from typing import Any, Dict, Generic, List, Literal, Optional, Type, TypeVar, cast
from uuid import uuid4 from uuid import uuid4
from typing_extensions import Literal # <= Python 3.7
from ..constants import DEVELOPMENT_TAG_NAME, ONLINE_TAG_NAME, PRODUCTION_TAG_NAME from ..constants import DEVELOPMENT_TAG_NAME, ONLINE_TAG_NAME, PRODUCTION_TAG_NAME
from ..context import get_context from ..context import get_context
from ..views import Model, Trace from ..views import Model, Trace
@ -25,7 +23,7 @@ class TracingContext(Generic[T]):
self._models: List[Model] = [] self._models: List[Model] = []
self._values: Dict[str, Any] = {} self._values: Dict[str, Any] = {}
self._trace: Optional[Trace[T]] = None self._trace: Optional[Trace[T]] = None
self._start_datetime = datetime.utcnow() self._start_datetime = datetime.now(timezone.utc).replace(tzinfo=None)
self._start_time = perf_counter() self._start_time = perf_counter()
self._name = function_name self._name = function_name

View file

@ -94,9 +94,11 @@ class ConfigFile(Mapping[str, str]):
try: try:
value = next(v for v in values if v) value = next(v for v in values if v)
except StopIteration: except StopIteration:
raise ParseError(f"""Cannot parse config file ({ raise ParseError(
f"""Cannot parse config file ({
self._path.absolute() self._path.absolute()
}), error at key `{key}`""") }), error at key `{key}`"""
)
already_exists = key in self._key_values already_exists = key in self._key_values
if already_exists and not value.startswith( if already_exists and not value.startswith(

View file

@ -39,9 +39,11 @@ def manage_communication(
is_iteration_over = True is_iteration_over = True
except Exception as e: except Exception as e:
if ignore_exceptions: if ignore_exceptions:
logger.error(f"""Exception {e} encountered in input, traceback:\n{ logger.error(
f"""Exception {e} encountered in input, traceback:\n{
traceback.format_exc() traceback.format_exc()
}""") }"""
)
else: else:
raise raise

View file

@ -3,6 +3,7 @@ from typing import (
Awaitable, Awaitable,
Callable, Callable,
Iterable, Iterable,
Literal,
Optional, Optional,
Sequence, Sequence,
TypeVar, TypeVar,
@ -11,7 +12,6 @@ from typing import (
) )
import dill import dill
from typing_extensions import Literal # <= Python 3.7
from .get_config import get_config from .get_config import get_config
from .manage_communication import manage_communication from .manage_communication import manage_communication

View file

@ -4,6 +4,7 @@ from typing import (
Awaitable, Awaitable,
Callable, Callable,
Iterable, Iterable,
Literal,
Optional, Optional,
Sequence, Sequence,
TypeVar, TypeVar,
@ -11,8 +12,6 @@ from typing import (
overload, overload,
) )
from typing_extensions import Literal # <= Python 3.7
from .get_config import get_config from .get_config import get_config
from .manage_communication import manage_communication from .manage_communication import manage_communication
from .mapper_function import mapper_function from .mapper_function import mapper_function

View file

@ -1,6 +1,4 @@
from typing import List from typing import List, Literal
from typing_extensions import Literal # <= Python 3.7
Operator = Literal[">=", "<=", "<", ">", "!=", "=", "contains"] Operator = Literal[">=", "<=", "<", ">", "!=", "=", "contains"]

View file

@ -1,6 +1,4 @@
from typing import Any, List, Optional from typing import Any, List, Literal, Optional
from typing_extensions import Literal # <= Python 3.7
from ..hashable_base_model import HashableBaseModel from ..hashable_base_model import HashableBaseModel

View file

@ -1,5 +1,6 @@
from typing import Literal
from pydantic import BaseModel from pydantic import BaseModel
from typing_extensions import Literal # <= Python 3.7
class SortBy(BaseModel): class SortBy(BaseModel):

View file

@ -9,7 +9,7 @@ from .model import Model
T = TypeVar("T") T = TypeVar("T")
class Trace(Generic[T], HashableBaseModel): class Trace(HashableBaseModel, Generic[T]):
"""Universal structure for storing prediction traces and training data. """Universal structure for storing prediction traces and training data.
Attributes: Attributes:

View file

@ -21,49 +21,51 @@ classifiers = [
"Natural Language :: English", "Natural Language :: English",
] ]
keywords = ["SE4ML", "MLOps", "AI engineering", "general", "robust", "end-to-end", "automated", "trustworthy", "ai", "deployment"] keywords = ["SE4ML", "MLOps", "AI engineering", "general", "robust", "end-to-end", "automated", "trustworthy", "ai", "deployment"]
requires-python = ">= 3.7" requires-python = ">= 3.10"
dependencies = [ dependencies = [
"scikit-learn", "scikit-learn >= 1.3, < 2",
"matplotlib", "matplotlib >= 3.7, < 4",
"numpy", "numpy >= 1.24, < 3",
"nbconvert", "nbconvert >= 7.0, < 8",
"ipython", "ipython >= 8.0, < 10",
"unidecode >= 1.3.0", "unidecode >= 1.3.0, < 2",
"syntok >= 1.4.0", "syntok >= 1.4.0, < 2",
"langcodes[data] >= 3.3.0", "langcodes[data] >= 3.3.0, < 4",
"langdetect >= 1.0.9", "langdetect >= 1.0.9, < 2",
"tinydb >= 4.7.0", "tinydb >= 4.7.0, < 5",
"boto3 >= 1.23.0", "boto3 >= 1.34, < 2",
"plotly >= 5.8.0", "plotly >= 5.20, < 7",
"pandas", "pandas >= 2.0, < 4",
"dash >= 2.4.0", "dash >= 2.16, < 5",
"fastapi >= 0.70.0", "fastapi >= 0.110, < 1",
"uvicorn[standard] >= 0.18.0", "uvicorn[standard] >= 0.27, < 1",
"watchdog >= 2.1.0", "a2wsgi >= 1.9, < 2",
"typeguard >= 2.10.0", "watchdog >= 3.0, < 7",
"pymongo >= 4.0.0", "typeguard >= 4.0, < 5",
"dill >= 0.3.5.0", "pydantic >= 2.5, < 3",
"tqdm", "pymongo >= 4.6, < 5",
"httpx >= 0.20.0", "dill >= 0.3.6, < 1",
"tqdm >= 4.64, < 5",
"httpx >= 0.24, < 1",
] ]
[project.optional-dependencies] [project.optional-dependencies]
dev = [ dev = [
"flit", "flit >= 3.9, < 4",
"mkdocs", "mkdocs >= 1.5, < 2",
"mkdocstrings[python]", "mkdocstrings[python] >= 0.24, < 1",
"mkdocs-material", "mkdocs-material >= 9.5, < 10",
"mkdocs-jupyter", "mkdocs-jupyter >= 0.24, < 1",
"mkdocs-git-revision-date-localized-plugin", "mkdocs-git-revision-date-localized-plugin >= 1.2, < 2",
"autoflake", "autoflake >= 2.0, < 3",
"isort", "isort >= 5.12, < 7",
"black[jupyter]", "black[jupyter] >= 25.1, < 26",
"mypy", "mypy >= 1.8, < 2",
"flake8", "flake8 >= 7.0, < 8",
"tox", "tox >= 4.0, < 5",
"pytest", "pytest >= 7.4, < 9",
"pytest-cov", "pytest-cov >= 4.1, < 8",
"pytest-asyncio", "pytest-asyncio >= 0.23, < 2",
] ]
[tool.pytest.ini_options] [tool.pytest.ini_options]

View file

@ -3,7 +3,7 @@
set -e set -e
echo "Installing dependencies if necessary" echo "Installing dependencies if necessary"
python3 -m pip install --upgrade autoflake isort black[jupyter] mypy flake8 python3 -m pip install autoflake isort black[jupyter] mypy flake8
for dir in "$@"; do for dir in "$@"; do
echo "Checking $dir" echo "Checking $dir"
@ -19,7 +19,7 @@ for dir in "$@"; do
python3 -m mypy --namespace-packages --ignore-missing-imports --install-types --non-interactive --disallow-untyped-defs --disallow-incomplete-defs --follow-imports=silent --exclude=external/ --exclude=/build/ --exclude='(^|/)__main__\.py$' --pretty . python3 -m mypy --namespace-packages --ignore-missing-imports --install-types --non-interactive --disallow-untyped-defs --disallow-incomplete-defs --follow-imports=silent --exclude=external/ --exclude=/build/ --exclude='(^|/)__main__\.py$' --pretty .
fi fi
python3 -m flake8 . --count --show-source --statistics --exclude=__init__.py,.env,external --ignore=E501,E402,F821,W503,E722,E203,E704 python3 -m flake8 . --count --show-source --statistics --exclude=__init__.py,.env,external --extend-ignore=E501,E402,F821,W503,E722,E203,E704
cd - cd -
done done

View file

@ -14,11 +14,14 @@ def test_simple() -> None:
assert c.first_key == "András" assert c.first_key == "András"
assert c.second_key == "test 2" assert c.second_key == "test 2"
assert c.third_key == "test= 2==" assert c.third_key == "test= 2=="
assert c.fourth_key == """ assert (
c.fourth_key
== """
this# this#
is is
multiline multiline
""" """
)
assert c.whitespace == "hardly matters" assert c.whitespace == "hardly matters"
with pytest.raises(KeyError): with pytest.raises(KeyError):
c.this c.this
@ -31,11 +34,14 @@ def test_simple_dict() -> None:
assert c["my_hashtag"] == "#great_ai" assert c["my_hashtag"] == "#great_ai"
assert c["second_key"] == "test 2" assert c["second_key"] == "test 2"
assert c["third_key"] == "test= 2==" assert c["third_key"] == "test= 2=="
assert c["fourth_key"] == """ assert (
c["fourth_key"]
== """
this# this#
is is
multiline multiline
""" """
)
assert c["whitespace"] == "hardly matters" assert c["whitespace"] == "hardly matters"
with pytest.raises(KeyError): with pytest.raises(KeyError):
c["#this"] c["#this"]
@ -49,11 +55,14 @@ def test_string_path() -> None:
assert c.second_key == "test 2" assert c.second_key == "test 2"
assert c.third_key == "test= 2==" assert c.third_key == "test= 2=="
assert c.fourth_key == """ assert (
c.fourth_key
== """
this# this#
is is
multiline multiline
""" """
)
assert c.whitespace == "hardly matters" assert c.whitespace == "hardly matters"