<!-- Thank you for your contribution! -->
<!-- Unless your change is trivial, please create an issue to discuss the change before creating a PR -->

## Change Summary

<!-- Please give a short summary of the changes. -->

This fixes an issue where the JSON schema can end up using the drive letter (like `C`, `D` etc) instead of the model name on Windows if the module with the model is imported from an absolute path on the filesystem (for example using importlib).  This was caused by splitting at the first colon `:` character to remove it and the ID following it, thus on an absolute path on Windows of the form `C:\...` ended up becoming just the drive letter. This fix changes it to remove the LAST colon character and anything following it.

Modified description post-further investigation of the issue / source of the problem:

This makes the model name used in the JSON Schema be correct also if the model is loaded from a module that has a colon in the name. This should not really happen in any correct use case (python modules should not typically have colons in them), but it's possible to achieve by accident if you use the absolute file path as the module name on Windows when working with importlib. In that case you would have ended up getting just the drive letter as a model name in the JSON Schema, this fix ensures it will still work correctly in that case.



## Related issue number

<!-- WARNING: please use "fix #123" style references so the issue is closed when this PR is merged. -->

fix #7860

## Checklist

* [x] The pull request title is a good summary of the changes - it will be used in the changelog
* [ ] Unit tests for the changes exist
* [x] Tests pass on CI
* [ ] Documentation reflects the changes where applicable
* [ ] My PR is ready to review, **please add a comment including the phrase "please review" to assign reviewers**

Make the model name generation more robust in JSON schema. <!-- Thank you for your contribution! -->
<!-- Unless your change is trivial, please create an issue to discuss the change before creating a PR -->

## Change Summary

<!-- Please give a short summary of the changes. -->

This fixes an issue where the JSON schema can end up using the drive letter (like `C`, `D` etc) instead of the model name on Windows if the module with the model is imported from an absolute path on the filesystem (for example using importlib).  This was caused by splitting at the first colon `:` character to remove it and the ID following it, thus on an absolute path on Windows of the form `C:\...` ended up becoming just the drive letter. This fix changes it to remove the LAST colon character and anything following it.

Modified description post-further investigation of the issue / source of the problem:

This makes the model name used in the JSON Schema be correct also if the model is loaded from a module that has a colon in the name. This should not really happen in any correct use case (python modules should not typically have colons in them), but it's possible to achieve by accident if you use the absolute file path as the module name on Windows when working with importlib. In that case you would have ended up getting just the drive letter as a model name in the JSON Schema, this fix ensures it will still work correctly in that case.



## Related issue number

<!-- WARNING: please use "fix #123" style references so the issue is closed when this PR is merged. -->

fix #7860

## Checklist

* [x] The pull request title is a good summary of the changes - it will be used in the changelog
* [ ] Unit tests for the changes exist
* [x] Tests pass on CI
* [ ] Documentation reflects the changes where applicable
* [ ] My PR is ready to review, **please add a comment including the phrase "please review" to assign reviewers**

from typing import Any, ClassVar, Generic, List, Optional, TypeVar, Union

from typing_extensions import Self

from pydantic import BaseModel, ConfigDict, Field, create_model, field_validator, model_validator, validator
from pydantic.dataclasses import dataclass


class Model(BaseModel):
    x: float
    y: str

    model_config = ConfigDict(from_attributes=True)


class SelfReferencingModel(BaseModel):
    submodel: Optional['SelfReferencingModel']

    @property
    def prop(self) -> None:
        ...


SelfReferencingModel.model_rebuild()

model = Model(x=1, y='y')
Model(x=1, y='y', z='z')
# MYPY: error: Unexpected keyword argument "z" for "Model"  [call-arg]
model.x = 2
model.model_validate(model)

self_referencing_model = SelfReferencingModel(submodel=SelfReferencingModel(submodel=None))


class KwargsModel(BaseModel, from_attributes=True):
    x: float
    y: str


kwargs_model = KwargsModel(x=1, y='y')
KwargsModel(x=1, y='y', z='z')
# MYPY: error: Unexpected keyword argument "z" for "KwargsModel"  [call-arg]
kwargs_model.x = 2
kwargs_model.model_validate(kwargs_model.__dict__)


class InheritingModel(Model):
    z: int = 1


InheritingModel.model_validate(model.__dict__)


class ForwardReferencingModel(Model):
    future: 'FutureModel'


class FutureModel(Model):
    pass


ForwardReferencingModel.model_rebuild()
future_model = FutureModel(x=1, y='a')
forward_model = ForwardReferencingModel(x=1, y='a', future=future_model)


class NoMutationModel(BaseModel):
    x: int

    model_config = ConfigDict(frozen=True)


class MutationModel(NoMutationModel):
    a: int = 1

    model_config = ConfigDict(frozen=False, from_attributes=True)


MutationModel(x=1).x = 2
MutationModel.model_validate(model.__dict__)


class KwargsNoMutationModel(BaseModel, frozen=True):
    x: int


class KwargsMutationModel(KwargsNoMutationModel, frozen=False, from_attributes=True):
# MYPY: error: Cannot inherit non-frozen dataclass from a frozen one  [misc]
    a: int = 1


KwargsMutationModel(x=1).x = 2
# MYPY: error: Property "x" defined in "KwargsNoMutationModel" is read-only  [misc]
KwargsMutationModel.model_validate(model.__dict__)


class OverrideModel(Model):
    x: int


OverrideModel(x=1, y='b')


class Mixin:
    def f(self) -> None:
        pass


class MultiInheritanceModel(BaseModel, Mixin):
    pass


MultiInheritanceModel().f()


class AliasModel(BaseModel):
    x: str = Field(..., alias='y')


alias_model = AliasModel(y='hello')
assert alias_model.x == 'hello'


class ClassVarModel(BaseModel):
    x: int
    y: ClassVar[int] = 1


ClassVarModel(x=1)


@dataclass(config={'validate_assignment': True})
class AddProject:
    name: str
    slug: Optional[str]
    description: Optional[str]


p = AddProject(name='x', slug='y', description='z')


class TypeAliasAsAttribute(BaseModel):
    __type_alias_attribute__ = Union[str, bytes]


class NestedModel(BaseModel):
    class Model(BaseModel):
        id: str

    model: Model


_ = NestedModel.Model


DynamicModel = create_model('DynamicModel', __base__=Model)

dynamic_model = DynamicModel(x=1, y='y')
dynamic_model.x = 2


class FrozenModel(BaseModel):
    x: int

    model_config = ConfigDict(frozen=True)


class NotFrozenModel(FrozenModel):
    a: int = 1

    model_config = ConfigDict(frozen=False, from_attributes=True)


NotFrozenModel(x=1).x = 2
NotFrozenModel.model_validate(model.__dict__)


class KwargsFrozenModel(BaseModel, frozen=True):
    x: int


class KwargsNotFrozenModel(FrozenModel, frozen=False, from_attributes=True):
    a: int = 1


KwargsNotFrozenModel(x=1).x = 2
KwargsNotFrozenModel.model_validate(model.__dict__)


class ModelWithSelfField(BaseModel):
    self: str


def f(name: str) -> str:
    return name


class ModelWithAllowReuseValidator(BaseModel):
    name: str
    normalize_name = field_validator('name')(f)


model_with_allow_reuse_validator = ModelWithAllowReuseValidator(name='xyz')


T = TypeVar('T')


class Response(BaseModel, Generic[T]):
    data: T
    error: Optional[str]


response = Response[Model](data=model, error=None)


class ModelWithAnnotatedValidator(BaseModel):
    name: str

    @field_validator('name')
    def noop_validator_with_annotations(cls, name: str) -> str:
        return name


def _default_factory_str() -> str:
    return 'x'


def _default_factory_list() -> List[int]:
    return [1, 2, 3]


class FieldDefaultTestingModel(BaseModel):
    # Required
    a: int
    b: int = Field()
    c: int = Field(...)

    # Default
    d: int = Field(1)

    # Default factory
    g: List[int] = Field(default_factory=_default_factory_list)
    h: str = Field(default_factory=_default_factory_str)
    i: str = Field(default_factory=lambda: 'test')


_TModel = TypeVar('_TModel')
_TType = TypeVar('_TType')


class OrmMixin(Generic[_TModel, _TType]):
    @classmethod
    def from_orm(cls, model: _TModel) -> _TType:
        raise NotImplementedError

    @classmethod
    def from_orm_optional(cls, model: Optional[_TModel]) -> Optional[_TType]:
        if model is None:
            return None
        return cls.from_orm(model)


import sys  # noqa E402

if sys.version_info >= (3, 8):
    from dataclasses import InitVar  # E402

    InitVarStr = InitVar[str]
else:
    # InitVar is not supported in 3.7 due to loss of type information
    InitVarStr = str


@dataclass
class MyDataClass:
    foo: InitVarStr
    bar: str


MyDataClass(foo='foo', bar='bar')


def get_my_custom_validator(field_name: str) -> Any:
    @validator(field_name, allow_reuse=True)
    def my_custom_validator(cls: Any, v: int) -> int:
        return v

    return my_custom_validator


def foo() -> None:
    class MyModel(BaseModel):
        number: int
        custom_validator = get_my_custom_validator('number')  # type: ignore[pydantic-field]
# MYPY: error: Unused "type: ignore" comment  [unused-ignore]

        @model_validator(mode='before')
        @classmethod
        def validate_before(cls, values: Any) -> Any:
            return values

        @model_validator(mode='after')
        def validate_after(self) -> Self:
            return self

    MyModel(number=2)

from typing import Any, ClassVar, Generic, List, Optional, TypeVar, Union

from typing_extensions import Self

from pydantic import BaseModel, ConfigDict, Field, create_model, field_validator, model_validator, validator
from pydantic.dataclasses import dataclass


class Model(BaseModel):
    x: float
    y: str

    model_config = ConfigDict(from_attributes=True)


class SelfReferencingModel(BaseModel):
    submodel: Optional['SelfReferencingModel']

    @property
    def prop(self) -> None:
        ...


SelfReferencingModel.model_rebuild()

model = Model(x=1, y='y')
Model(x=1, y='y', z='z')
# MYPY: error: Unexpected keyword argument "z" for "Model"  [call-arg]
model.x = 2
model.model_validate(model)

self_referencing_model = SelfReferencingModel(submodel=SelfReferencingModel(submodel=None))


class KwargsModel(BaseModel, from_attributes=True):
    x: float
    y: str


kwargs_model = KwargsModel(x=1, y='y')
KwargsModel(x=1, y='y', z='z')
# MYPY: error: Unexpected keyword argument "z" for "KwargsModel"  [call-arg]
kwargs_model.x = 2
kwargs_model.model_validate(kwargs_model.__dict__)


class InheritingModel(Model):
    z: int = 1


InheritingModel.model_validate(model.__dict__)


class ForwardReferencingModel(Model):
    future: 'FutureModel'


class FutureModel(Model):
    pass


ForwardReferencingModel.model_rebuild()
future_model = FutureModel(x=1, y='a')
forward_model = ForwardReferencingModel(x=1, y='a', future=future_model)


class NoMutationModel(BaseModel):
    x: int

    model_config = ConfigDict(frozen=True)


class MutationModel(NoMutationModel):
    a: int = 1

    model_config = ConfigDict(frozen=False, from_attributes=True)


MutationModel(x=1).x = 2
MutationModel.model_validate(model.__dict__)


class KwargsNoMutationModel(BaseModel, frozen=True):
    x: int


class KwargsMutationModel(KwargsNoMutationModel, frozen=False, from_attributes=True):
# MYPY: error: Cannot inherit non-frozen dataclass from a frozen one  [misc]
    a: int = 1


KwargsMutationModel(x=1).x = 2
# MYPY: error: Property "x" defined in "KwargsNoMutationModel" is read-only  [misc]
KwargsMutationModel.model_validate(model.__dict__)


class OverrideModel(Model):
    x: int


OverrideModel(x=1, y='b')


class Mixin:
    def f(self) -> None:
        pass


class MultiInheritanceModel(BaseModel, Mixin):
    pass


MultiInheritanceModel().f()


class AliasModel(BaseModel):
    x: str = Field(..., alias='y')


alias_model = AliasModel(y='hello')
assert alias_model.x == 'hello'


class ClassVarModel(BaseModel):
    x: int
    y: ClassVar[int] = 1


ClassVarModel(x=1)


@dataclass(config={'validate_assignment': True})
class AddProject:
    name: str
    slug: Optional[str]
    description: Optional[str]


p = AddProject(name='x', slug='y', description='z')


class TypeAliasAsAttribute(BaseModel):
    __type_alias_attribute__ = Union[str, bytes]


class NestedModel(BaseModel):
    class Model(BaseModel):
        id: str

    model: Model


_ = NestedModel.Model


DynamicModel = create_model('DynamicModel', __base__=Model)

dynamic_model = DynamicModel(x=1, y='y')
dynamic_model.x = 2


class FrozenModel(BaseModel):
    x: int

    model_config = ConfigDict(frozen=True)


class NotFrozenModel(FrozenModel):
    a: int = 1

    model_config = ConfigDict(frozen=False, from_attributes=True)


NotFrozenModel(x=1).x = 2
NotFrozenModel.model_validate(model.__dict__)


class KwargsFrozenModel(BaseModel, frozen=True):
    x: int


class KwargsNotFrozenModel(FrozenModel, frozen=False, from_attributes=True):
    a: int = 1


KwargsNotFrozenModel(x=1).x = 2
KwargsNotFrozenModel.model_validate(model.__dict__)


class ModelWithSelfField(BaseModel):
    self: str


def f(name: str) -> str:
    return name


class ModelWithAllowReuseValidator(BaseModel):
    name: str
    normalize_name = field_validator('name')(f)


model_with_allow_reuse_validator = ModelWithAllowReuseValidator(name='xyz')


T = TypeVar('T')


class Response(BaseModel, Generic[T]):
    data: T
    error: Optional[str]


response = Response[Model](data=model, error=None)


class ModelWithAnnotatedValidator(BaseModel):
    name: str

    @field_validator('name')
    def noop_validator_with_annotations(cls, name: str) -> str:
        return name


def _default_factory_str() -> str:
    return 'x'


def _default_factory_list() -> List[int]:
    return [1, 2, 3]


class FieldDefaultTestingModel(BaseModel):
    # Required
    a: int
    b: int = Field()
    c: int = Field(...)

    # Default
    d: int = Field(1)

    # Default factory
    g: List[int] = Field(default_factory=_default_factory_list)
    h: str = Field(default_factory=_default_factory_str)
    i: str = Field(default_factory=lambda: 'test')


_TModel = TypeVar('_TModel')
_TType = TypeVar('_TType')


class OrmMixin(Generic[_TModel, _TType]):
    @classmethod
    def from_orm(cls, model: _TModel) -> _TType:
        raise NotImplementedError

    @classmethod
    def from_orm_optional(cls, model: Optional[_TModel]) -> Optional[_TType]:
        if model is None:
            return None
        return cls.from_orm(model)


import sys  # noqa E402

if sys.version_info >= (3, 8):
    from dataclasses import InitVar  # E402

    InitVarStr = InitVar[str]
else:
    # InitVar is not supported in 3.7 due to loss of type information
    InitVarStr = str


@dataclass
class MyDataClass:
    foo: InitVarStr
    bar: str


MyDataClass(foo='foo', bar='bar')


def get_my_custom_validator(field_name: str) -> Any:
    @validator(field_name, allow_reuse=True)
    def my_custom_validator(cls: Any, v: int) -> int:
        return v

    return my_custom_validator


def foo() -> None:
    class MyModel(BaseModel):
        number: int
        custom_validator = get_my_custom_validator('number')  # type: ignore[pydantic-field]
# MYPY: error: Unused "type: ignore" comment  [unused-ignore]

        @model_validator(mode='before')
        @classmethod
        def validate_before(cls, values: Any) -> Any:
            return values

        @model_validator(mode='after')
        def validate_after(self) -> Self:
            return self

    MyModel(number=2)
