Skip to content
Merged
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 .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [3.9, "3.10", "3.11", "3.12"]
python-version: [3.9, "3.10", "3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v1
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.1.1] - 2025-03-20

- Fix bug in `MARKDOWN` view for `servers` (displaying twice the `description`
instead of `description` and `url`).
- Fix bug happening when a `path item` includes properties that are not of kind
`operation item` (https://github.com/Neoteroi/mkdocs-plugins/issues/5).
- Add support for handling `parameters` defined on `path items` (common
parameters for all operation under a certain path).
Refer to the [`Path Item` specification](https://swagger.io/specification/#path-item-object).
- Fix bug happening when a parameter has a non-str `name` property.
- Add Python 3.13 to the build matrix.

## [1.1.0] - 2025-01-18

- Add additionalProperties to Schema object, by @tyzhnenko.
Expand Down
2 changes: 1 addition & 1 deletion openapidocs/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__version__ = "1.1.0"
__version__ = "1.1.1"
VERSION = __version__
42 changes: 37 additions & 5 deletions openapidocs/mk/v3/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ def get_operations(self):
paths = data["paths"]

for path, path_item in paths.items():
if not isinstance(path_item, dict):
continue
tag = self.get_tag(path_item) or ""

for operation in path_item.values():
Expand All @@ -186,11 +188,32 @@ def get_operations(self):
operation["requestBody"] = self._resolve_opt_ref(
operation["requestBody"]
)

groups[tag].append((path, path_item))
groups[tag].append((path, self._keep_operations(path_item)))

return groups

def _keep_operations(self, path_item):
# discard dictionary keys that are not of dict type

# if the path item defines common parameters, merge them into each operation:
# https://swagger.io/specification/#path-item-object
common_parameters = path_item.get("parameters", [])
# Note: we don't need to resolve $ref here, because they are resolved in
# get_parameters

return {
key: self._merge_common_parameters(value, common_parameters)
for key, value in path_item.items()
if isinstance(value, dict)
}

def _merge_common_parameters(self, operation, common_parameters):
if not common_parameters:
return operation
data = copy.deepcopy(operation)
data["parameters"] = common_parameters + data.get("parameters", [])
return data

def get_schemas(self):
schemas = read_dict(self.doc, "components", "schemas")

Expand All @@ -215,8 +238,12 @@ def get_tag(self, path_item) -> Optional[str]:
"""
single_tag: Optional[str] = None

for operation in path_item.values():
tags = operation.get("tags")
for prop in path_item.values():
if not isinstance(prop, dict):
# This property is not an operation; in this context we ignore it.
# See Path Item Object here: https://swagger.io/specification/
continue
tags = prop.get("tags")

if not tags:
continue
Expand Down Expand Up @@ -383,6 +410,11 @@ def _resolve_opt_ref(self, obj):
return self.resolve_reference(obj)
return obj

def _lower(self, obj):
if isinstance(obj, str):
return obj.lower()
return str(obj)

def get_parameters(self, operation) -> List[dict]:
"""
Returns a list of objects describing the input parameters for a given operation.
Expand All @@ -397,7 +429,7 @@ def get_parameters(self, operation) -> List[dict]:
param
for param in sorted(
parameters,
key=lambda x: x["name"].lower() if (x and "name" in x) else "",
key=lambda x: self._lower(x["name"]) if (x and "name" in x) else "",
)
if param
]
Expand Down
2 changes: 1 addition & 1 deletion openapidocs/mk/v3/views_markdown/partial/servers.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

{% with rows = [[texts.description, texts.url]] %}
{%- for server in servers -%}
{%- set _ = rows.append([server.description, server.description]) -%}
{%- set _ = rows.append([server.description, server.url]) -%}
{%- endfor -%}
{{ rows | table }}
{%- endwith -%}
5 changes: 2 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,13 @@ pathspec==0.11.2
platformdirs==4.0.0
pluggy==1.3.0
pycodestyle==2.11.1
pydantic==2.5.1
pydantic_core==2.14.3
pydantic==2.10.6
pyflakes==3.1.0
Pygments==2.17.1
pytest==7.4.3
pytest-cov==4.1.0
PyYAML==6.0.1
rich==13.7.0
sniffio==1.3.0
typing_extensions==4.8.0
typing_extensions>=4.8.0
Werkzeug==3.0.1
6 changes: 3 additions & 3 deletions tests/res/example1-output-plain.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ Optional multiline or single-line description in

## Servers

| Description | URL |
| ----------------- | ----------------- |
| Production server | Production server |
| Description | URL |
| ----------------- | ------------------------------------------- |
| Production server | https://www.neoteroi.xyz/software-center/v1 |


## Blobs
Expand Down
128 changes: 128 additions & 0 deletions tests/res/example8-openapi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
openapi: 3.0.0
info:
version: 1.0.0
title: Swagger Petstore
license:
name: MIT
servers:
- url: http://petstore.swagger.io/v1
description: Petstore server
paths:
/pets:
summary: Everything about pets
description: This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/).
parameters:
- name: X-Country
in: header
description: Country code.
required: false
schema:
type: string
default: PL
get:
summary: List all pets
operationId: listPets
tags:
- pets
parameters:
- name: limit
in: query
description: How many items to return at one time (max 100)
required: false
schema:
type: integer
format: int32
default: 100
responses:
"200":
description: A paged array of pets
headers:
x-next:
description: A link to the next page of responses
schema:
type: string
content:
application/json:
schema:
$ref: "#/components/schemas/Pets"
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
post:
summary: Create a pet
operationId: createPets
tags:
- pets
responses:
"201":
description: Null response
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/pets/{petId}:
get:
summary: Info for a specific pet
operationId: showPetById
tags:
- pets
parameters:
- name: petId
in: path
required: true
description: The id of the pet to retrieve
schema:
type: string
responses:
"200":
description: Expected response to a valid request
content:
application/json:
schema:
$ref: "#/components/schemas/Pet"
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
components:
schemas:
Pet:
type: object
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
Pets:
type: array
items:
$ref: "#/components/schemas/Pet"
PetsIds:
type: array
items:
type: integer
format: int64
Error:
type: object
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string
Loading