Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
## Description

<!-- Describe the goal of the PR in a few lines. -->

## TODO

- [ ] Update version.
- [ ] Update [changelog](../CHANGELOG.md).
- [ ] Quality passed.
- [ ] Tests passed.
- [ ] Readme is up-to-date.
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- Typing has been improved.

## [0.1.0]

### Added

- Various observations contexts to track code.

[Unreleased]: https://github.com/bendabir/trackotron/tree/develop
[Unreleased]: https://github.com/bendabir/trackotron/compare/0.1.0...main
[0.1.0]: https://github.com/bendabir/trackotron/tree/0.1.0
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,4 @@ Here are some ideas to improve the current decorator :
- [ ] Add more tests to ensure behaviors and consistency
- [ ] Support context reuse if that makes sense
- [ ] Handle data obfuscation when needed so we don't expose secrets.
- [ ] Make parenthesis usage optional (see [#918](https://github.com/langfuse/langfuse-python/pull/918))
13 changes: 4 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# --- poetry ---
[tool.poetry]
name = "trackotron"
version = "0.1.0"
version = "0.2.0"
description = "Improved decorator for Langfuse."
license = "GPL-3.0-or-later"
authors = ["Bendabir"]
Expand Down Expand Up @@ -37,13 +37,13 @@ build-backend = "poetry.core.masonry.api"
# --- black ---
[tool.black]
line-length = 88
target-version = ["py38"]
target-version = ["py39"]
preview = false

# --- mypy ---
[tool.mypy]
local_partial_types = true
python_version = "3.8"
python_version = "3.9"
mypy_path = "src/,tests/"
files = "**/src/**/*.py,**/tests/**/*.py"
scripts_are_modules = true
Expand Down Expand Up @@ -79,15 +79,10 @@ enable_error_code = [
"unused-awaitable",
]

[tool.pydantic-mypy]
init_typed = false
init_forbid_extra = true
warn_required_dynamic_aliases = true

# --- ruff ---
[tool.ruff]
line-length = 88
target-version = "py38"
target-version = "py39"
indent-width = 4
preview = true
namespace-packages = ["src/trackotron"]
Expand Down
49 changes: 21 additions & 28 deletions src/trackotron/contexts/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
TYPE_CHECKING,
Any,
Callable,
Coroutine,
Generic,
TypeVar,
final,
Expand All @@ -28,9 +27,18 @@
from contextvars import ContextVar
from types import TracebackType

from trackotron.types_ import Arguments, P, R_co
from trackotron.types_ import (
Arguments,
AsyncFunction,
AsyncInjectedFunction,
Function,
InjectedFunction,
ObservationParameters,
P,
R_co,
TraceParameters,
)
from trackotron.types_.compatibility import Langfuse, StatefulClient
from trackotron.types_.misc import ObservationParameters, TraceParameters

U_co = TypeVar("U_co", bound=ObservationUpdate, covariant=True)

Expand Down Expand Up @@ -238,12 +246,9 @@ def _is_method(f: Callable[P, R_co], /) -> bool:
@final
def _wrap_sync(
self,
f: Callable[
Concatenate[ObservationProxy[O_co, U_co], P],
R_co,
],
f: InjectedFunction[ObservationProxy[O_co, U_co], P, R_co],
/,
) -> Callable[P, R_co]:
) -> Function[P, R_co]:
@ft.wraps(f)
def wrap(*args: Any, **kwargs: Any) -> R_co:
with self._context() as proxy:
Expand Down Expand Up @@ -288,43 +293,31 @@ def wrap(*args: Any, **kwargs: Any) -> R_co:
@final
def _wrap_async(
self,
f: Callable[
Concatenate[ObservationProxy[O_co, U_co], P],
Coroutine[Any, Any, R_co],
],
f: AsyncInjectedFunction[ObservationProxy[O_co, U_co], P, R_co],
/,
) -> Callable[P, Coroutine[Any, Any, R_co]]:
) -> AsyncFunction[P, R_co]:
raise NotImplementedError

@overload
def __call__(
self,
f: Callable[
Concatenate[ObservationProxy[O_co, U_co], P],
R_co,
],
f: InjectedFunction[ObservationProxy[O_co, U_co], P, R_co],
/,
) -> Callable[P, R_co]: ...
) -> Function[P, R_co]: ...

@overload
def __call__(
self,
f: Callable[
Concatenate[ObservationProxy[O_co, U_co], P],
Coroutine[Any, Any, R_co],
],
f: AsyncInjectedFunction[ObservationProxy[O_co, U_co], P, R_co],
/,
) -> Callable[P, Coroutine[Any, Any, R_co]]: ...
) -> AsyncFunction[P, R_co]: ...

@final
def __call__(
self,
f: Callable[
Concatenate[ObservationProxy[O_co, U_co], P],
R_co,
],
f: InjectedFunction[ObservationProxy[O_co, U_co], P, R_co],
/,
) -> Callable[P, R_co] | Callable[P, Coroutine[Any, Any, R_co]]:
) -> Function[P, R_co] | AsyncFunction[P, R_co]:
"""Decorate a function to observe it in Langfuse.

If the name was not provided, it will infer it from the function/method.
Expand Down
31 changes: 29 additions & 2 deletions src/trackotron/types_/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@

from __future__ import annotations

from .aliases import (
AsyncClassMethod,
AsyncFunction,
AsyncInjectedClassMethod,
AsyncInjectedFunction,
AsyncInjectedMethod,
AsyncMethod,
ClassMethod,
Function,
InjectedClassMethod,
InjectedFunction,
InjectedMethod,
Method,
)
from .compatibility import (
Langfuse,
ModelUsage,
Expand All @@ -13,12 +27,26 @@
StatefulSpanClient,
StatefulTraceClient,
)
from .generics import P, R_co, T_contra
from .generics import C, I, P, R_co
from .misc import Arguments, ObservationParameters, ObservationType, TraceParameters

__all__ = [
"Arguments",
"AsyncClassMethod",
"AsyncFunction",
"AsyncInjectedClassMethod",
"AsyncInjectedFunction",
"AsyncInjectedMethod",
"AsyncMethod",
"C",
"ClassMethod",
"Function",
"I",
"InjectedClassMethod",
"InjectedFunction",
"InjectedMethod",
"Langfuse",
"Method",
"ModelUsage",
"ObservationParameters",
"ObservationType",
Expand All @@ -31,6 +59,5 @@
"StatefulGenerationClient",
"StatefulSpanClient",
"StatefulTraceClient",
"T_contra",
"TraceParameters",
]
26 changes: 26 additions & 0 deletions src/trackotron/types_/aliases.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""Copyright (c) 2024 Bendabir."""

from __future__ import annotations

from typing import Any, Callable, Coroutine

from typing_extensions import Concatenate

from trackotron.types_.generics import C, I, P, R_co

Function = Callable[P, R_co]
InjectedFunction = Callable[Concatenate[I, P], R_co]
Method = Callable[Concatenate[C, P], R_co]
InjectedMethod = Callable[Concatenate[C, I, P], R_co]
ClassMethod = Callable[Concatenate[type[C], P], R_co]
InjectedClassMethod = Callable[Concatenate[type[C], I, P], R_co]

AsyncFunction = Callable[P, Coroutine[Any, Any, R_co]]
AsyncInjectedFunction = Callable[Concatenate[I, P], Coroutine[Any, Any, R_co]]
AsyncMethod = Callable[Concatenate[C, P], Coroutine[Any, Any, R_co]]
AsyncInjectedMethod = Callable[Concatenate[C, I, P], Coroutine[Any, Any, R_co]]
AsyncClassMethod = Callable[Concatenate[type[C], P], Coroutine[Any, Any, R_co]]
AsyncInjectedClassMethod = Callable[
Concatenate[type[C], I, P],
Coroutine[Any, Any, R_co],
]
3 changes: 2 additions & 1 deletion src/trackotron/types_/generics.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@

P = ParamSpec("P")
R_co = TypeVar("R_co", covariant=True)
T_contra = TypeVar("T_contra", contravariant=True)
C = TypeVar("C")
I = TypeVar("I")