增加环绕侦察场景适配

This commit is contained in:
2026-01-08 15:44:38 +08:00
parent 3eba1f962b
commit 10c5bb5a8a
5441 changed files with 40219 additions and 379695 deletions

View File

@@ -14,19 +14,22 @@ from ipaddress import (
from pathlib import Path, PurePath
from re import Pattern
from types import GeneratorType
from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union
from typing import Annotated, Any, Callable, Optional, Union
from uuid import UUID
from annotated_doc import Doc
from fastapi._compat import may_v1
from fastapi.exceptions import PydanticV1NotSupportedError
from fastapi.types import IncEx
from pydantic import BaseModel
from pydantic.color import Color
from pydantic.networks import AnyUrl, NameEmail
from pydantic.types import SecretBytes, SecretStr
from typing_extensions import Annotated
from pydantic_core import PydanticUndefinedType
from ._compat import Url, _is_undefined, _model_dump
from ._compat import (
Url,
is_pydantic_v1_model_instance,
)
# Taken from Pydantic v1 as is
@@ -34,14 +37,14 @@ def isoformat(o: Union[datetime.date, datetime.time]) -> str:
return o.isoformat()
# Taken from Pydantic v1 as is
# Adapted from Pydantic v1
# TODO: pv2 should this return strings instead?
def decimal_encoder(dec_value: Decimal) -> Union[int, float]:
"""
Encodes a Decimal as int of there's no exponent, otherwise float
Encodes a Decimal as int if there's no exponent, otherwise float
This is useful when we use ConstrainedDecimal to represent Numeric(x,0)
where a integer (but not int typed) is used. Encoding this as a float
where an integer (but not int typed) is used. Encoding this as a float
results in failed round-tripping between encode and parse.
Our Id type is a prime example of this.
@@ -50,17 +53,20 @@ def decimal_encoder(dec_value: Decimal) -> Union[int, float]:
>>> decimal_encoder(Decimal("1"))
1
>>> decimal_encoder(Decimal("NaN"))
nan
"""
if dec_value.as_tuple().exponent >= 0: # type: ignore[operator]
exponent = dec_value.as_tuple().exponent
if isinstance(exponent, int) and exponent >= 0:
return int(dec_value)
else:
return float(dec_value)
ENCODERS_BY_TYPE: Dict[Type[Any], Callable[[Any], Any]] = {
ENCODERS_BY_TYPE: dict[type[Any], Callable[[Any], Any]] = {
bytes: lambda o: o.decode(),
Color: str,
may_v1.Color: str,
datetime.date: isoformat,
datetime.datetime: isoformat,
datetime.time: isoformat,
@@ -77,26 +83,21 @@ ENCODERS_BY_TYPE: Dict[Type[Any], Callable[[Any], Any]] = {
IPv6Interface: str,
IPv6Network: str,
NameEmail: str,
may_v1.NameEmail: str,
Path: str,
Pattern: lambda o: o.pattern,
SecretBytes: str,
may_v1.SecretBytes: str,
SecretStr: str,
may_v1.SecretStr: str,
set: list,
UUID: str,
Url: str,
may_v1.Url: str,
AnyUrl: str,
may_v1.AnyUrl: str,
}
def generate_encoders_by_class_tuples(
type_encoder_map: Dict[Any, Callable[[Any], Any]],
) -> Dict[Callable[[Any], Any], Tuple[Any, ...]]:
encoders_by_class_tuples: Dict[Callable[[Any], Any], Tuple[Any, ...]] = defaultdict(
type_encoder_map: dict[Any, Callable[[Any], Any]],
) -> dict[Callable[[Any], Any], tuple[Any, ...]]:
encoders_by_class_tuples: dict[Callable[[Any], Any], tuple[Any, ...]] = defaultdict(
tuple
)
for type_, encoder in type_encoder_map.items():
@@ -176,7 +177,7 @@ def jsonable_encoder(
),
] = False,
custom_encoder: Annotated[
Optional[Dict[Any, Callable[[Any], Any]]],
Optional[dict[Any, Callable[[Any], Any]]],
Doc(
"""
Pydantic's `custom_encoder` parameter, passed to Pydantic models to define
@@ -221,15 +222,8 @@ def jsonable_encoder(
include = set(include)
if exclude is not None and not isinstance(exclude, (set, dict)):
exclude = set(exclude)
if isinstance(obj, (BaseModel, may_v1.BaseModel)):
# TODO: remove when deprecating Pydantic v1
encoders: Dict[Any, Any] = {}
if isinstance(obj, may_v1.BaseModel):
encoders = getattr(obj.__config__, "json_encoders", {}) # type: ignore[attr-defined]
if custom_encoder:
encoders = {**encoders, **custom_encoder}
obj_dict = _model_dump(
obj,
if isinstance(obj, BaseModel):
obj_dict = obj.model_dump(
mode="json",
include=include,
exclude=exclude,
@@ -238,14 +232,10 @@ def jsonable_encoder(
exclude_none=exclude_none,
exclude_defaults=exclude_defaults,
)
if "__root__" in obj_dict:
obj_dict = obj_dict["__root__"]
return jsonable_encoder(
obj_dict,
exclude_none=exclude_none,
exclude_defaults=exclude_defaults,
# TODO: remove when deprecating Pydantic v1
custom_encoder=encoders,
sqlalchemy_safe=sqlalchemy_safe,
)
if dataclasses.is_dataclass(obj):
@@ -268,7 +258,7 @@ def jsonable_encoder(
return str(obj)
if isinstance(obj, (str, int, float, type(None))):
return obj
if _is_undefined(obj):
if isinstance(obj, PydanticUndefinedType):
return None
if isinstance(obj, dict):
encoded_dict = {}
@@ -328,11 +318,15 @@ def jsonable_encoder(
for encoder, classes_tuple in encoders_by_class_tuples.items():
if isinstance(obj, classes_tuple):
return encoder(obj)
if is_pydantic_v1_model_instance(obj):
raise PydanticV1NotSupportedError(
"pydantic.v1 models are no longer supported by FastAPI."
f" Please update the model {obj!r}."
)
try:
data = dict(obj)
except Exception as e:
errors: List[Exception] = []
errors: list[Exception] = []
errors.append(e)
try:
data = vars(obj)