Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix and test unmapped SQLModels #286

Merged
merged 2 commits into from
Jun 29, 2024
Merged
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
10 changes: 7 additions & 3 deletions logfire/_internal/json_encoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,12 +282,16 @@ def logfire_json_dumps(obj: Any) -> str:


def is_sqlalchemy(obj: Any) -> bool:
if not hasattr(obj, '__mapper__'):
# A SQLModel without `table=True` will pass `isinstance(obj.__class__, DeclarativeMeta)` (I don't know how)
# but will fail when retrieving data, specifically when calling `sqlalchemy.inspect`
# or when getting the `__mapper__` attribute.
return False

try:
from sqlalchemy.orm import DeclarativeBase, DeclarativeMeta

if isinstance(obj, DeclarativeBase):
return True
return isinstance(obj.__class__, DeclarativeMeta)
return isinstance(obj, DeclarativeBase) or isinstance(obj.__class__, DeclarativeMeta)
except ImportError: # pragma: no cover
return False

Expand Down
2 changes: 1 addition & 1 deletion logfire/_internal/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ def _span(
if json_schema_properties := attributes_json_schema_properties(attributes):
otlp_attributes[ATTRIBUTES_JSON_SCHEMA_KEY] = attributes_json_schema(json_schema_properties)

tags = cast('tuple[str, ...]', (self._tags or ()) + tuple(_tags or ()))
tags = (self._tags or ()) + tuple(_tags or ())
if tags:
otlp_attributes[ATTRIBUTES_TAGS_KEY] = uniquify_sequence(tags)

Expand Down
5 changes: 2 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,7 @@ dev-dependencies = [
"asyncpg",
"cloudpickle>=3.0.0",
"anthropic>=0.27.0",
# Can remove this when https://github.com/python/typing_extensions/commit/53bcdded534494674f893112f71d3be344d65363 is released
"typing-extensions<4.12",
"sqlmodel",
]

[tool.rye.scripts]
Expand Down Expand Up @@ -191,7 +190,7 @@ quote-style = "single"
typeCheckingMode = "strict"
reportUnnecessaryTypeIgnoreComment = true
reportMissingTypeStubs = false
exclude = ["docs/**/*.py", "site/**/*.py", ".venv", "venv*"]
exclude = ["docs/**/*.py", "site/**/*.py", ".venv", "venv*", "ignoreme"]
venvPath = ".venv"

[tool.pytest.ini_options]
Expand Down
53 changes: 28 additions & 25 deletions requirements-dev.lock
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ aiosignal==1.3.1
# via aiohttp
annotated-types==0.7.0
# via pydantic
anthropic==0.28.0
anthropic==0.30.0
anyio==4.3.0
# via anthropic
# via httpx
Expand Down Expand Up @@ -55,7 +55,7 @@ cloudpickle==3.0.0
colorama==0.4.6
# via griffe
# via mkdocs-material
coverage==7.5.3
coverage==7.5.4
deprecated==1.2.14
# via opentelemetry-api
# via opentelemetry-exporter-otlp-proto-http
Expand All @@ -69,7 +69,7 @@ django==5.0.6
dnspython==2.6.1
# via email-validator
# via pymongo
email-validator==2.1.1
email-validator==2.2.0
# via fastapi
eval-type-backport==0.2.0
executing==2.0.1
Expand All @@ -78,20 +78,20 @@ executing==2.0.1
fastapi==0.111.0
fastapi-cli==0.0.4
# via fastapi
filelock==3.14.0
filelock==3.15.4
# via huggingface-hub
# via virtualenv
flask==3.0.3
frozenlist==1.4.1
# via aiohttp
# via aiosignal
fsspec==2024.6.0
fsspec==2024.6.1
# via huggingface-hub
ghp-import==2.1.0
# via mkdocs
googleapis-common-protos==1.63.1
googleapis-common-protos==1.63.2
# via opentelemetry-exporter-otlp-proto-http
griffe==0.45.2
griffe==0.47.0
# via mkdocstrings-python
h11==0.14.0
# via httpcore
Expand All @@ -104,7 +104,7 @@ httpx==0.27.0
# via anthropic
# via fastapi
# via openai
huggingface-hub==0.23.3
huggingface-hub==0.23.4
# via tokenizers
identify==2.5.36
# via pre-commit
Expand All @@ -128,7 +128,7 @@ jinja2==3.1.4
# via mkdocs
# via mkdocs-material
# via mkdocstrings
jiter==0.4.1
jiter==0.5.0
# via anthropic
loguru==0.7.2
markdown==3.6
Expand Down Expand Up @@ -159,12 +159,12 @@ mkdocs-autorefs==1.0.1
mkdocs-get-deps==0.2.0
# via mkdocs
mkdocs-glightbox==0.4.0
mkdocs-material==9.5.25
mkdocs-material==9.5.27
mkdocs-material-extensions==1.3.1
# via mkdocs-material
mkdocstrings==0.25.1
# via mkdocstrings-python
mkdocstrings-python==1.10.3
mkdocstrings-python==1.10.5
multidict==6.0.5
# via aiohttp
# via yarl
Expand All @@ -173,9 +173,9 @@ mypy-extensions==1.0.0
nodeenv==1.9.1
# via pre-commit
# via pyright
numpy==1.26.4
numpy==2.0.0
Copy link
Member

Choose a reason for hiding this comment

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

It's because of numpy!

# via pandas
openai==1.31.1
openai==1.35.7
opentelemetry-api==1.25.0
# via opentelemetry-exporter-otlp-proto-http
# via opentelemetry-instrumentation
Expand Down Expand Up @@ -276,9 +276,9 @@ opentelemetry-util-http==0.46b0
# via opentelemetry-instrumentation-requests
# via opentelemetry-instrumentation-starlette
# via opentelemetry-instrumentation-wsgi
orjson==3.10.3
orjson==3.10.5
# via fastapi
packaging==24.0
packaging==24.1
# via black
# via huggingface-hub
# via mkdocs
Expand Down Expand Up @@ -309,10 +309,11 @@ psycopg==3.1.19
psycopg-binary==3.1.19
# via psycopg
psycopg2-binary==2.9.9
pydantic==2.7.3
pydantic==2.7.4
# via anthropic
# via fastapi
# via openai
# via sqlmodel
pydantic-core==2.18.4
# via pydantic
pygments==2.18.0
Expand All @@ -321,8 +322,8 @@ pygments==2.18.0
pymdown-extensions==10.8.1
# via mkdocs-material
# via mkdocstrings
pymongo==4.7.3
pyright==1.1.365
pymongo==4.8.0
pyright==1.1.369
pytest==8.2.2
# via pytest-django
# via pytest-pretty
Expand All @@ -348,7 +349,7 @@ pyyaml==6.0.1
# via uvicorn
pyyaml-env-tag==0.1
# via mkdocs
redis==5.0.4
redis==5.0.7
regex==2024.5.15
# via mkdocs-material
requests==2.32.3
Expand All @@ -362,8 +363,8 @@ rich==13.7.1
# via logfire
# via pytest-pretty
# via typer
ruff==0.4.8
setuptools==70.0.0
ruff==0.5.0
setuptools==70.1.1
# via opentelemetry-instrumentation
shellingham==1.5.4
# via typer
Expand All @@ -375,7 +376,9 @@ sniffio==1.3.1
# via anyio
# via httpx
# via openai
sqlalchemy==2.0.30
sqlalchemy==2.0.31
# via sqlmodel
sqlmodel==0.0.19
sqlparse==0.5.0
# via django
starlette==0.37.2
Expand All @@ -392,7 +395,7 @@ typer==0.12.3
# via fastapi-cli
types-toml==0.10.8.20240310
# via inline-snapshot
typing-extensions==4.11.0
typing-extensions==4.12.2
# via anthropic
# via fastapi
# via huggingface-hub
Expand All @@ -408,13 +411,13 @@ tzdata==2024.1
# via pandas
ujson==5.10.0
# via fastapi
urllib3==2.2.1
urllib3==2.2.2
# via requests
uvicorn==0.30.1
# via fastapi
uvloop==0.19.0
# via uvicorn
virtualenv==20.26.2
virtualenv==20.26.3
# via pre-commit
watchdog==4.0.1
# via mkdocs
Expand Down
8 changes: 4 additions & 4 deletions requirements.lock
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ deprecated==1.2.14
# via opentelemetry-exporter-otlp-proto-http
executing==2.0.1
# via logfire
googleapis-common-protos==1.63.1
googleapis-common-protos==1.63.2
# via opentelemetry-exporter-otlp-proto-http
idna==3.7
# via requests
Expand Down Expand Up @@ -57,12 +57,12 @@ requests==2.32.3
# via opentelemetry-exporter-otlp-proto-http
rich==13.7.1
# via logfire
setuptools==70.0.0
setuptools==70.1.1
# via opentelemetry-instrumentation
typing-extensions==4.11.0
typing-extensions==4.12.2
# via logfire
# via opentelemetry-sdk
urllib3==2.2.1
urllib3==2.2.2
# via requests
wrapt==1.16.0
# via deprecated
Expand Down
11 changes: 11 additions & 0 deletions tests/test_json_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column, relationship
from sqlalchemy.orm.decl_api import MappedAsDataclass
from sqlalchemy.sql.schema import ForeignKey
from sqlmodel import SQLModel

import logfire
from logfire.testing import TestExporter
Expand Down Expand Up @@ -70,6 +71,10 @@ class MyPydanticComplexDataclass:
t: MyPydanticDataclass


class MySQLModel(SQLModel):
s: int


class Generator:
def __repr__(self) -> str:
return 'Generator()'
Expand Down Expand Up @@ -513,6 +518,12 @@ class StrSubclass(str):
},
id='pydantic_model_with_extra',
),
pytest.param(
MySQLModel(s=10),
's=10',
'{"s":10}',
{'type': 'object', 'title': 'MySQLModel', 'x-python-datatype': 'PydanticModel'},
),
pytest.param(
MyDataclass(10),
'MyDataclass(t=10)',
Expand Down