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

chore: unreleased changes #118

Merged
merged 4 commits into from
Aug 16, 2023
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
12 changes: 12 additions & 0 deletions noxfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import nox
import nox_poetry


@nox_poetry.session(reuse_venv=True, name="test-pydantic-v1")
def test_pydantic_v1(session: nox.Session) -> None:
session.run_always("poetry", "install", external=True)

# https://github.com/cjolowicz/nox-poetry/issues/1116
session._session.run("python", "-m", "pip", "install", "pydantic<2", external=True) # type: ignore

session.run("pytest", "--showlocals", "--ignore=tests/functional")
324 changes: 279 additions & 45 deletions poetry.lock

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ packages = [
[tool.poetry.dependencies]
python = "^3.7"
httpx = ">= 0.23.0, < 1"
pydantic = "^1.9.0"
pydantic = ">= 1.9.0, < 3"
typing-extensions = ">= 4.5, < 5"
anyio = ">= 3.5.0, < 4"
distro = ">= 1.7.0, < 2"
tokenizers = ">= 0.13.0"


[tool.poetry.group.dev.dependencies]
pyright = "1.1.318"
mypy = "1.4.1"
Expand All @@ -29,6 +30,8 @@ pytest-asyncio = "0.21.1"
ruff = "0.0.282"
isort = "5.10.1"
time-machine = "^2.9.0"
nox = "^2023.4.22"
nox-poetry = "^1.0.3"


[build-system]
Expand Down Expand Up @@ -59,7 +62,8 @@ pythonVersion = "3.7"

exclude = [
"_dev",
".venv"
".venv",
".nox",
]
reportImportCycles = false
reportPrivateUsage = false
Expand Down
3 changes: 3 additions & 0 deletions release-please-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@
"hidden": true
}
],
"reviewers": [
"RobertCraigie"
],
"release-type": "python",
"extra-files": [
"src/anthropic/_version.py"
Expand Down
6 changes: 4 additions & 2 deletions src/anthropic/_base_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
ModelBuilderProtocol,
)
from ._utils import is_dict, is_mapping
from ._compat import model_copy
from ._models import (
BaseModel,
GenericModel,
Expand Down Expand Up @@ -82,7 +83,8 @@
_AsyncStreamT = TypeVar("_AsyncStreamT", bound=AsyncStream[Any])


DEFAULT_TIMEOUT = Timeout(timeout=60.0, connect=5.0)
# default timeout is 10 minutes
DEFAULT_TIMEOUT = Timeout(timeout=600.0, connect=5.0)
DEFAULT_MAX_RETRIES = 2
DEFAULT_LIMITS = Limits(max_connections=100, max_keepalive_connections=20)

Expand Down Expand Up @@ -150,7 +152,7 @@ def _params_from_url(self, url: URL) -> httpx.QueryParams:
return httpx.QueryParams(cast(Any, self._options.params)).merge(url.params)

def _info_to_options(self, info: PageInfo) -> FinalRequestOptions:
options = self._options.copy()
options = model_copy(self._options)

if not isinstance(info.params, NotGiven):
options.params = {**options.params, **info.params}
Expand Down
152 changes: 152 additions & 0 deletions src/anthropic/_compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
from __future__ import annotations

from typing import TYPE_CHECKING, Any, Union, TypeVar, cast
from datetime import date, datetime

import pydantic
from pydantic.fields import FieldInfo

from ._types import StrBytesIntFloat

_ModelT = TypeVar("_ModelT", bound=pydantic.BaseModel)

# --------------- Pydantic v2 compatibility ---------------

# Pyright incorrectly reports some of our functions as overriding a method when they don't
# pyright: reportIncompatibleMethodOverride=false

PYDANTIC_V2 = pydantic.VERSION.startswith("2.")

# v1 re-exports
if TYPE_CHECKING:

def parse_date(value: date | StrBytesIntFloat) -> date:
...

def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime:
...

def get_args(t: type[Any]) -> tuple[Any, ...]:
...

def is_union(tp: type[Any] | None) -> bool:
...

def get_origin(t: type[Any]) -> type[Any] | None:
...

def is_literal_type(type_: type[Any]) -> bool:
...

def is_typeddict(type_: type[Any]) -> bool:
...

else:
if PYDANTIC_V2:
from pydantic.v1.typing import get_args as get_args
from pydantic.v1.typing import is_union as is_union
from pydantic.v1.typing import get_origin as get_origin
from pydantic.v1.typing import is_typeddict as is_typeddict
from pydantic.v1.typing import is_literal_type as is_literal_type
from pydantic.v1.datetime_parse import parse_date as parse_date
from pydantic.v1.datetime_parse import parse_datetime as parse_datetime
else:
from pydantic.typing import get_args as get_args
from pydantic.typing import is_union as is_union
from pydantic.typing import get_origin as get_origin
from pydantic.typing import is_typeddict as is_typeddict
from pydantic.typing import is_literal_type as is_literal_type
from pydantic.datetime_parse import parse_date as parse_date
from pydantic.datetime_parse import parse_datetime as parse_datetime


# refactored config
if TYPE_CHECKING:
from pydantic import ConfigDict as ConfigDict
else:
if PYDANTIC_V2:
from pydantic import ConfigDict
else:
# TODO: provide an error message here?
ConfigDict = None


# renamed methods / properties
def parse_obj(model: type[_ModelT], value: object) -> _ModelT:
if PYDANTIC_V2:
return model.model_validate(value)
else:
return cast(_ModelT, model.parse_obj(value)) # pyright: ignore[reportDeprecated, reportUnnecessaryCast]


def field_is_required(field: FieldInfo) -> bool:
if PYDANTIC_V2:
return field.is_required()
return field.required # type: ignore


def field_get_default(field: FieldInfo) -> Any:
value = field.get_default()
if PYDANTIC_V2:
from pydantic_core import PydanticUndefined

if value == PydanticUndefined:
return None
return value
return value


def field_outer_type(field: FieldInfo) -> Any:
if PYDANTIC_V2:
return field.annotation
return field.outer_type_ # type: ignore


def get_model_config(model: type[pydantic.BaseModel]) -> Any:
if PYDANTIC_V2:
return model.model_config
return model.__config__ # type: ignore


def get_model_fields(model: type[pydantic.BaseModel]) -> dict[str, FieldInfo]:
if PYDANTIC_V2:
return model.model_fields
return model.__fields__ # type: ignore


def model_copy(model: _ModelT) -> _ModelT:
if PYDANTIC_V2:
return model.model_copy()
return model.copy() # type: ignore


def model_json(model: pydantic.BaseModel) -> str:
if PYDANTIC_V2:
return model.model_dump_json()
return model.json() # type: ignore


def model_dump(model: pydantic.BaseModel) -> dict[str, Any]:
if PYDANTIC_V2:
return model.model_dump()
return cast("dict[str, Any]", model.dict()) # pyright: ignore[reportDeprecated, reportUnnecessaryCast]


# generic models
if TYPE_CHECKING:

class GenericModel(pydantic.BaseModel):
...

else:
if PYDANTIC_V2:
# there no longer needs to be a distinction in v2 but
# we still have to create our own subclass to avoid
# inconsistent MRO ordering errors
class GenericModel(pydantic.BaseModel):
...

else:

class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel):
...
Loading