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

AnyHttpUrl behaves differently when inherited from BaseSettings than from BaseModel #104

Closed
1 task done
Zer0x00 opened this issue Jul 5, 2023 · 4 comments
Closed
1 task done
Assignees

Comments

@Zer0x00
Copy link

Zer0x00 commented Jul 5, 2023

Initial Checks

  • I confirm that I'm using Pydantic V2 installed directly from the main branch, or equivalent

Description

AnyHttpUrl adds a trailing slash at the end of the URL.
Since this worked in Pydantic v1 and is different from Pydantic v2's BaseModel behaviour I guess this is unwanted.

Example Code

############################################################
# Using BaseSettings the assertion fails:

from pydantic import AnyHttpUrl
from pydantic_settings import BaseSettings


class SettingsV2(BaseSettings):
    URL: AnyHttpUrl = "https://github.com"


settings_v2 = SettingsV2()

assert str(settings_v2.URL) == "https://github.com"

############################################################
# Using BaseModel works as expected:

from pydantic import AnyHttpUrl, BaseModel


class SettingsV2_BaseModel(BaseModel):
    URL: AnyHttpUrl = "https://github.com"


settings_base_model = SettingsV2_BaseModel()

assert str(settings_base_model.URL) == "https://github.com"

############################################################
# Pydantic v1 BaseSettings worked also as expected:
from pydantic import v1 as pydantic_v1


class SettingsV1(pydantic_v1.BaseSettings):
    URL: pydantic_v1.AnyHttpUrl = "https://github.com"


settings_v1 = SettingsV1()

assert str(settings_v1.URL) == "https://github.com"

Python, Pydantic & OS Version

             pydantic version: 2.0.1
        pydantic-core version: 2.0.2 release build profile
                 install path: /usr/local/lib/python3.11/dist-packages/pydantic
               python version: 3.11.4 (main, Jun  7 2023, 12:45:48) [GCC 11.3.0]
                     platform: Linux-5.15.90.1-microsoft-standard-WSL2-x86_64-with-glibc2.35
     optional deps. installed: ['typing-extensions']

Selected Assignee: @hramezani

@hramezani
Copy link
Member

Thanks @Zer0x00 for reporting this 🙏

In pydantic-settings, validate_default config is enabled by default. So, that's why you get a trailing slash at the end of the URL.

You can disable this:

from pydantic import AnyHttpUrl
from pydantic_settings import BaseSettings, SettingsConfigDict


class SettingsV2(BaseSettings):
    model_config = SettingsConfigDict(validate_default=False)  # disablin the behavior

    URL: AnyHttpUrl = "https://github.com"


settings_v2 = SettingsV2()

assert str(settings_v2.URL) == "https://github.com"

@Zer0x00
Copy link
Author

Zer0x00 commented Jul 5, 2023

Thanks for the hint but I wonder if the default of validate_default shouldn't match the default of Pydantic BaseModel?

@samuelcolvin
Copy link
Member

No, it's extremely helpful to have the default values validated with BaseSettings - it's useful to be able to access settings_base_model.URL.host whether or not that field was set during validation.

Whereas with BaseModel it's generally preferable to reduce the overhead by not running validation on defaults, this is also how V1 behaved. The URL validation has changed/improved significantly in V2, hence the trailing slash.

@shawnwall
Copy link

noting this may be the cause of a CORS origin error I've run into when migrating to pydantic-settings, as, to my knowledge, these origins should not contain a trailing slash, and now it is being added.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants