Skip to content

Commit 471147b

Browse files
Codacy linting issues
1 parent 3f124e4 commit 471147b

5 files changed

Lines changed: 62 additions & 19 deletions

File tree

.pylintrc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[MAIN]
2+
py-version = 3.12
3+
4+
[BASIC]
5+
# h and s are intentional short names that map directly to API query parameters.
6+
good-names = h,s,e,i,j,k,_
7+
8+
[DESIGN]
9+
# _build_options and route handlers mirror the full set of API query parameters.
10+
max-args = 15
11+
max-positional-arguments = 15
12+
13+
[MESSAGES CONTROL]
14+
# 'format' and 'help' shadow builtins intentionally — they are public API
15+
# query-parameter names whose spelling cannot be changed without breaking clients.
16+
disable = redefined-builtin,
17+
line-too-long,
18+
missing-module-docstring

.remarkrc.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
plugins:
22
- remark-lint
33
- - remark-lint-ordered-list-marker-value
4-
- off
4+
- false

pyproject.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,21 @@ source = ["service"]
3737

3838
[tool.bandit]
3939
skips = ["B101"]
40+
41+
[tool.pylint.main]
42+
# Inform Pylint of the actual Python version so built-in generics (list[...],
43+
# dict[...]) and typing additions (Literal, Annotated) are recognised correctly.
44+
py-version = "3.12"
45+
46+
[tool.pylint.basic]
47+
# h and s are intentional short names that map directly to API query parameters.
48+
good-names = ["h", "s", "e", "i", "j", "k", "_"]
49+
50+
[tool.pylint.design]
51+
# _build_options mirrors the full set of API query parameters (12 args).
52+
max-args = 15
53+
54+
[tool.pylint.messages_control]
55+
# 'format' and 'help' shadow builtins intentionally — they are public API
56+
# query-parameter names whose spelling cannot be changed without breaking clients.
57+
disable = ["redefined-builtin"]

service/routes/dc.py

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44

55
import json
66
import re
7-
from typing import Annotated, Optional
7+
from typing import Annotated, Literal, Optional
88

99
from fastapi import APIRouter, Query
10-
from fastapi.responses import JSONResponse, PlainTextResponse
10+
from fastapi.responses import JSONResponse, PlainTextResponse, Response
1111

1212
from ..models import CharacterSearchBody
1313
from ..utils import ApiUtils, InvalidUsage, ReadFile
@@ -35,7 +35,7 @@
3535
3636
e.g. `?pretty` and `?pretty=true` are functionally equivalent
3737
38-
**character: character filters can used like:**
38+
**characters: character filters can used like:**
3939
4040
`{keyword1},{keyword2}` e.g. superman,batman will search for each character individually
4141
@@ -119,6 +119,7 @@ def _build_options(
119119
}.items():
120120
if val is not None:
121121
options[key] = val
122+
# Presence-style flags: key present (even empty string) means True
122123
for key, val in {
123124
"help": help,
124125
"pretty": pretty,
@@ -137,19 +138,23 @@ def _respond(api: ApiUtils, config: dict):
137138

138139
try:
139140
data = ReadFile(config).get_data()
140-
except InvalidUsage:
141-
# Preserve existing InvalidUsage exceptions without re-wrapping
142-
raise
143-
except TypeError as error:
144-
# Wrap unexpected TypeError in InvalidUsage
145-
raise InvalidUsage(error)
141+
except (TypeError, InvalidUsage) as error:
142+
if isinstance(error, InvalidUsage):
143+
# Preserve original InvalidUsage, including its status_code and payload
144+
raise
145+
raise InvalidUsage(error) from error
146146

147147
if config.get("pretty"):
148-
body = json.dumps(data, indent=4, separators=(",", ": "), sort_keys=False, ensure_ascii=False)
149-
else:
150-
body = json.dumps(data, sort_keys=False, ensure_ascii=False)
148+
body = json.dumps(
149+
data,
150+
indent=4,
151+
separators=(",", ": "),
152+
sort_keys=False,
153+
ensure_ascii=False,
154+
)
155+
return Response(content=body, media_type="application/json")
151156

152-
return JSONResponse(content=json.loads(body))
157+
return JSONResponse(content=data)
153158

154159

155160
@bp_dc.get(
@@ -159,19 +164,20 @@ def _respond(api: ApiUtils, config: dict):
159164
description=_BASE_DESCRIPTION,
160165
)
161166
def dc_get_base(
162-
characters: Annotated[Optional[str], Query(description="Character(s) to search for. Either a string or Array of strings.")] = None,
167+
characters: Annotated[Optional[str], Query(description="Character(s) to search for as a string value (e.g. a single name or a comma-separated list).")] = None,
163168
format: Annotated[Optional[str], Query(description="Output format (currently only JSON)")] = None,
164-
h: Annotated[Optional[str], Query(description="Headers to display. Either a string or Array of strings")] = None,
169+
h: Annotated[Optional[str], Query(description="Headers to display as a string value (e.g. a single header or a comma-separated list).")] = None,
165170
help: Annotated[Optional[str], Query(description=f"List available options. {_TF_TEXT}")] = None,
166171
limit: Annotated[Optional[str], Query(description="Limit result set. '0' for no limit")] = None,
167-
nulls: Annotated[Optional[str], Query(description="Sort null values first or last in order. Accepted values: 'first' or 'last'.")] = None,
172+
nulls: Annotated[Optional[Literal["first", "last"]], Query(description="Sort null values either 'first' or 'last' in the sort order.")] = None,
168173
pretty: Annotated[Optional[str], Query(description=f"Pretty print the result set. {_TF_TEXT}")] = None,
169174
prune: Annotated[Optional[str], Query(description=f"Remove keys with null values. {_TF_TEXT}")] = None,
170175
random: Annotated[Optional[str], Query(description=f"Returns array of random superheroes based on limit. {_TF_TEXT}")] = None,
171176
s: Annotated[Optional[str], Query(description="Columns to sort on.")] = None,
172177
seed: Annotated[Optional[str], Query(description=f"Keep the same random characters on multiple requests. {_TF_TEXT}")] = None,
173178
universe: Annotated[Optional[str], Query(include_in_schema=False)] = None,
174179
):
180+
"""Filterable GET handler for the DC universe base endpoint."""
175181
api = ApiUtils()
176182
options = _build_options(
177183
characters=characters,

service/routes/marvel.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
3636
e.g. `?pretty` and `?pretty=true` are functionally equivalent
3737
38-
**character: character filters can used like:**
38+
**characters: character filters can used like:**
3939
4040
`{keyword1},{keyword2}` e.g. iron man,spider-man will search for each character individually
4141
@@ -142,7 +142,7 @@ def _respond(api: ApiUtils, config: dict):
142142
if isinstance(error, InvalidUsage):
143143
# Preserve original InvalidUsage, including its status_code and payload
144144
raise
145-
raise InvalidUsage(error)
145+
raise InvalidUsage(error) from error
146146

147147
if config.get("pretty"):
148148
body = json.dumps(
@@ -177,6 +177,7 @@ def marvel_get_base(
177177
seed: Annotated[Optional[str], Query(description=f"Keep the same random characters on multiple requests. {_TF_TEXT}")] = None,
178178
universe: Annotated[Optional[str], Query(include_in_schema=False)] = None,
179179
):
180+
"""Filterable GET handler for the Marvel universe base endpoint."""
180181
api = ApiUtils()
181182
options = _build_options(
182183
characters=characters,

0 commit comments

Comments
 (0)