Skip to content

Commit f9bf0bb

Browse files
authored
Merge branch 'main' into main
2 parents 908dc4f + df9960b commit f9bf0bb

File tree

18 files changed

+229
-36
lines changed

18 files changed

+229
-36
lines changed

.github/workflows/pipeline.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
runs-on: ubuntu-latest
1010
strategy:
1111
matrix:
12-
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
12+
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14']
1313
steps:
1414
- uses: actions/checkout@v2
1515
- name: Set up Python ${{ matrix.python-version }}

.github/workflows/release.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ jobs:
1313
steps:
1414
- uses: actions/checkout@master
1515

16-
- name: Set up Python 3.9
16+
- name: Set up Python 3.12
1717
uses: actions/setup-python@v1
1818
with:
19-
python-version: 3.9
19+
python-version: 3.12
2020

2121
- name: Update version
2222
run: sed -i "s/^version = .*/version = '${{github.ref_name}}'/" pyproject.toml
@@ -28,15 +28,15 @@ jobs:
2828
2929
- name: Publish distribution 📦 to Test PyPI
3030
if: github.event_name == 'push'
31-
uses: pypa/gh-action-pypi-publish@v1.5.0
31+
uses: pypa/gh-action-pypi-publish@v1.13.0
3232
with:
3333
user: __token__
3434
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
3535
repository_url: https://test.pypi.org/legacy/
3636

3737
- name: Publish distribution 📦 to PyPI if triggered by release
3838
if: github.event_name == 'release'
39-
uses: pypa/gh-action-pypi-publish@v1.5.0
39+
uses: pypa/gh-action-pypi-publish@v1.13.0
4040
with:
4141
user: __token__
4242
password: ${{ secrets.PYPI_API_TOKEN }}

.readthedocs.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ sphinx:
66
build:
77
os: "ubuntu-22.04"
88
tools:
9-
python: "3.8"
9+
python: "3.12"
1010
jobs:
1111
post_create_environment:
1212
# Install poetry

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ Connexion also **helps you write your OpenAPI specification** and develop agains
5454
## 🫶 Sponsors
5555

5656
<a href="https://www.ml6.eu"><img src="https://raw.githubusercontent.com/spec-first/connexion/main/docs/images/sponsors/ML6.png" title=ML6 height="100"></a>
57-
<a href="https://www.devmark.ai/fern/?utm_source=connexion&utm_loc=readme&utm_type=logo"><img src="https://raw.githubusercontent.com/spec-first/connexion/main/docs/images/sponsors/Fern.png" title=Fern height="100"></a>
5857

5958
Sponsors help us dedicate time to maintain Connexion. Want to help?
6059

connexion/middleware/swagger_ui.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def _spec_for_prefix(self, request) -> dict:
7070
This is needed when behind a path-altering reverse proxy.
7171
"""
7272
base_path = self._base_path_for_prefix(request)
73-
return self.specification.with_base_path(base_path).raw
73+
return self.specification.with_base_path(base_path).spec
7474

7575
def add_openapi_json(self):
7676
"""

connexion/security.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -493,11 +493,26 @@ def parse_security_scheme(
493493
security_handler = self.security_handlers["apiKey"]
494494
return security_handler().get_fn(security_scheme, required_scopes)
495495

496-
# Custom security handler
497-
elif (scheme := security_scheme["scheme"].lower()) in self.security_handlers:
496+
elif security_type == "openIdConnect":
497+
if security_type in self.security_handlers:
498+
security_handler = self.security_handlers[security_type]
499+
return security_handler().get_fn(security_scheme, required_scopes)
500+
logger.warning("... No default implementation for openIdConnect")
501+
return None
502+
503+
# Custom security scheme handler
504+
elif (
505+
"scheme" in security_scheme
506+
and (scheme := security_scheme["scheme"].lower()) in self.security_handlers
507+
):
498508
security_handler = self.security_handlers[scheme]
499509
return security_handler().get_fn(security_scheme, required_scopes)
500510

511+
# Custom security type handler
512+
elif security_type in self.security_handlers:
513+
security_handler = self.security_handlers[security_type]
514+
return security_handler().get_fn(security_scheme, required_scopes)
515+
501516
else:
502517
logger.warning(
503518
"... Unsupported security scheme type %s",

connexion/spec.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ def __init__(self, raw_spec, *, base_uri=""):
8181
self._set_defaults(raw_spec)
8282
self._validate_spec(raw_spec)
8383
self._spec = resolve_refs(raw_spec, base_uri=base_uri)
84+
self._base_uri = base_uri
8485

8586
@classmethod
8687
@abc.abstractmethod
@@ -107,6 +108,10 @@ def get_operation(self, path, method):
107108
def raw(self):
108109
return self._raw_spec
109110

111+
@property
112+
def spec(self):
113+
return self._spec
114+
110115
@property
111116
def version(self):
112117
return self._get_spec_version(self._spec)
@@ -204,7 +209,7 @@ def enforce_string_keys(obj):
204209
return OpenAPISpecification(spec, base_uri=base_uri)
205210

206211
def clone(self):
207-
return type(self)(copy.deepcopy(self._spec))
212+
return type(self)(copy.deepcopy(self._raw_spec), base_uri=self._base_uri)
208213

209214
@classmethod
210215
def load(cls, spec, *, arguments=None):

connexion/utils.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
import importlib
88
import inspect
99
import os
10-
import pkgutil
1110
import sys
11+
import typing
1212
import typing as t
1313

1414
import yaml
@@ -391,13 +391,16 @@ def cast_leaves(d, schema):
391391
return value
392392

393393

394+
@typing.no_type_check
394395
def get_root_path(import_name: str) -> str:
395396
"""Copied from Flask:
396397
https://github.com/pallets/flask/blob/836866dc19218832cf02f8b04911060ac92bfc0b/src/flask/helpers.py#L595
397398
398399
Find the root path of a package, or the path that contains a
399400
module. If it cannot be found, returns the current working
400401
directory.
402+
403+
:meta private:
401404
"""
402405
# Module already imported and has a file attribute. Use that first.
403406
mod = sys.modules.get(import_name)
@@ -406,16 +409,24 @@ def get_root_path(import_name: str) -> str:
406409
return os.path.dirname(os.path.abspath(mod.__file__))
407410

408411
# Next attempt: check the loader.
409-
loader = pkgutil.get_loader(import_name)
412+
try:
413+
spec = importlib.util.find_spec(import_name)
414+
415+
if spec is None:
416+
raise ValueError
417+
except (ImportError, ValueError):
418+
loader = None
419+
else:
420+
loader = spec.loader
410421

411422
# Loader does not exist or we're referring to an unloaded main
412423
# module or a main module without path (interactive sessions), go
413424
# with the current working directory.
414-
if loader is None or import_name == "__main__":
425+
if loader is None:
415426
return os.getcwd()
416427

417428
if hasattr(loader, "get_filename"):
418-
filepath = loader.get_filename(import_name) # type: ignore
429+
filepath = loader.get_filename(import_name) # pyright: ignore
419430
else:
420431
# Fall back to imports.
421432
__import__(import_name)
@@ -436,7 +447,7 @@ def get_root_path(import_name: str) -> str:
436447
)
437448

438449
# filepath is import_name.py for a module, or __init__.py for a package.
439-
return os.path.dirname(os.path.abspath(filepath))
450+
return os.path.dirname(os.path.abspath(filepath)) # type: ignore[no-any-return]
440451

441452

442453
def inspect_function_arguments(function: t.Callable) -> t.Tuple[t.List[str], bool]:
@@ -499,7 +510,7 @@ def __init__(self, path: str) -> None:
499510
self.path_regex, _, _ = compile_path(self.path)
500511

501512
def __lt__(self, other: "SortableRoute") -> bool:
502-
return bool(other.path_regex.match(self.path))
513+
return bool(other.path_regex.match(self.path)) or self.path < other.path
503514

504515
return sorted(routes, key=lambda r: SortableRoute(key(r) if key else r))
505516

@@ -542,5 +553,9 @@ def build_example_from_schema(schema):
542553
except ImportError:
543554
return None
544555

545-
faker = JSF(schema)
546-
return faker.generate()
556+
try:
557+
faker = JSF(schema)
558+
return faker.generate()
559+
except TypeError:
560+
561+
return None

examples/frameworks/spec/swagger.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ paths:
1313
description: Generates a greeting message.
1414
operationId: post_greeting
1515
produces:
16-
- text/plain;
16+
- text/plain
1717
responses:
1818
'200':
1919
description: greeting response

examples/helloworld/spec/swagger.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ paths:
1313
description: Generates a greeting message.
1414
operationId: hello.post_greeting
1515
produces:
16-
- text/plain;
16+
- text/plain
1717
responses:
1818
'200':
1919
description: greeting response

0 commit comments

Comments
 (0)