Skip to content
Open
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
2 changes: 1 addition & 1 deletion stubs/Flask-Cors/flask_cors/core.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ _MultiDict: TypeAlias = Any # werkzeug is not part of typeshed
@type_check_only
class _Options(TypedDict, total=False):
resources: dict[str, dict[str, Any]] | list[str] | str | None
origins: str | list[str] | None
origins: str | Pattern[str] | Iterable[str | Pattern[str]] | None
methods: str | list[str] | None
expose_headers: str | list[str] | None
allow_headers: str | list[str] | None
Comment on lines +16 to 19
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Unless I'm missing something, it appears that these function assume that the options have already been processed with serialize_options, which wraps a single string or pattern object in a list to ensure that origins is iterable. They'll raise a TypeError if you attempt to use a plain pattern object.

It also doesn't appear that None (or [None]) is a valid value (will also raise a TypeError). I'm guessing that that was added since the options are accessed with options.get(...), which suggests that None could be returned. But in actuality the options dict is pre-populated with the values from DEFAULT_OPTIONS, which sets non-None defaults, so I don't think a None value is ever valid?

A few examples of what I'm talking about:

# Non-iterable origins wrapped in list
$ uv run -w flask_cors python3 -c 'import flask_cors.core as c; print(c.serialize_options({"origins": "foo"}))'
{'origins': ['foo'], 'allow_headers': [None]}

# Raise on plain pattern object for origins
$ uv run -w flask_cors python3 -c 'import flask_cors.core as c; import re; print(c.get_cors_origins({"origins": re.compile("foo")}, "foo"))'
TypeError: argument of type 're.Pattern' is not a container or iterable

# Raise on None for origins
$ uv run -w flask_cors python3 -c 'import flask_cors.core as c; import re; print(c.get_cors_origins({"origins": None}, "foo"))'
TypeError: argument of type 'NoneType' is not a container or iterable

# Raise on [None] for origins
$ uv run -w flask_cors python3 -c 'import flask_cors.core as c; import re; print(c.get_cors_origins({"origins": [None]}, "foo"))'
TypeError: argument of type 'NoneType' is not a container or iterable

Does that match your experience?

The same appears to be true for allow_headers, so I'd suggest using the same type for it. It also appears that some of the other options can't be None in practice -- up to you if you want to try to fix those while we're here.

Suggested change
origins: str | Pattern[str] | Iterable[str | Pattern[str]] | None
methods: str | list[str] | None
expose_headers: str | list[str] | None
allow_headers: str | list[str] | None
origins: Iterable[str | Pattern[str]]
methods: str | list[str] | None
expose_headers: str | list[str] | None
allow_headers: Iterable[str | Pattern[str]]

Expand Down
5 changes: 3 additions & 2 deletions stubs/Flask-Cors/flask_cors/extension.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from collections.abc import Callable, Iterable
from datetime import timedelta
from logging import Logger
from re import Pattern
from typing import Any

import flask
Expand All @@ -13,7 +14,7 @@ class CORS:
app: flask.Flask | flask.Blueprint | None = None,
*,
resources: dict[str, dict[str, Any]] | list[str] | str | None = ...,
origins: str | list[str] | None = ...,
origins: str | Pattern[str] | Iterable[str | Pattern[str]] | None = ...,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Per above, it doesn't appear that passing None is valid.

Suggested change
origins: str | Pattern[str] | Iterable[str | Pattern[str]] | None = ...,
origins: str | Pattern[str] | Iterable[str | Pattern[str]] = ...,

methods: str | list[str] | None = ...,
expose_headers: str | list[str] | None = ...,
allow_headers: str | list[str] | None = ...,
Expand All @@ -28,7 +29,7 @@ class CORS:
app: flask.Flask,
*,
resources: dict[str, dict[str, Any]] | list[str] | str = ...,
origins: str | list[str] = ...,
origins: str | Pattern[str] | Iterable[str | Pattern[str]] = ...,
methods: str | list[str] = ...,
expose_headers: str | list[str] = ...,
allow_headers: str | list[str] = ...,
Expand Down
Loading