FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
splunk-ao-python/scripts/patch_http_validation_error.py at main · splunk/splunk-ao-python · GitHub
splunk
splunk-ao-python
Repository navigation
Code
Issues
1
(1)
Pull requests
86
(86)
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
splunk-ao-python
/
scripts
/
patch_http_validation_error.py
Copy path
More file actions
More file actions
Latest commit
History
History
History
145 lines (118 loc) · 5.17 KB
Breadcrumbs
splunk-ao-python
/
scripts
/
patch_http_validation_error.py
Copy path
File metadata and controls
145 lines (118 loc) · 5.17 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/usr/bin/env python3
"""
Patch the generated HTTPValidationError model so it correctly handles both
list-of-ValidationError and plain-string ``detail`` payloads from the API.
Some API error paths (e.g. invalid model alias) return a 422 whose ``detail``
is a plain string instead of the standard list-of-ValidationError objects.
The auto-generated ``from_dict`` iterates ``detail`` unconditionally, which
causes it to crash when ``detail`` is a string (each character is passed to
``ValidationError.from_dict``). This script fixes that by replacing the
generated for-loop with an isinstance-guarded block, and changes the field
initialisation from an empty list to UNSET so missing/absent detail is
distinguishable from an empty error list.
Workflow
--------
Run this script as a post-generation hook after
``scripts/auto-generate-api-client.sh``::
python scripts/patch_http_validation_error.py
\\
src/splunk_ao/resources/models/http_validation_error.py
Exit codes
----------
0 patch applied successfully
1 I/O or syntax error
2 expected pattern not found in target (template drift — update this script)
"""
from
__future__
import
annotations
import
re
import
sys
from
pathlib
import
Path
# ---------------------------------------------------------------------------
# Patterns to find in the auto-generated file
# ---------------------------------------------------------------------------
# Inside from_dict — pattern produced by the generator (openapi-python-client 0.29+):
#
# _detail = d.pop("detail", UNSET)
# detail: list[ValidationError] | Unset = UNSET
# if _detail is not UNSET:
# detail = []
# for detail_item_data in _detail:
# detail_item = ValidationError.from_dict(detail_item_data)
# <- blank line
# detail.append(detail_item)
#
# The class-level field annotation already comes out as
# `list[ValidationError] | Unset = UNSET` from the generator, so it
# does NOT need to be patched — only the from_dict body is rewritten here.
_LOOP_RE
=
re
.
compile
(
r"(?P<indent>[ \t]+)_detail = d\.pop\(\"detail\", UNSET\)\n"
r"(?P=indent)detail: list\[ValidationError\] \| Unset = UNSET\n"
r"(?P=indent)if _detail is not UNSET:\n"
r"(?P=indent) detail = \[\]\n"
r"(?P=indent) for detail_item_data in _detail:\n"
r"(?P=indent) detail_item = ValidationError\.from_dict\(detail_item_data\)\n"
r"[ \t]*\n"
r"(?P=indent) detail\.append\(detail_item\)"
,
re
.
MULTILINE
,
)
def
_loop_replacement
(
indent
:
str
)
->
str
:
i
=
indent
i4
=
indent
+
" "
return
"
\n
"
.
join
(
[
f'
{
i
}
_detail = d.pop("detail", UNSET)'
,
f"
{
i
}
detail: list[ValidationError] | Unset = UNSET"
,
f"
{
i
}
if isinstance(_detail, list):"
,
f"
{
i4
}
detail = [ValidationError.from_dict(item) for item in _detail]"
,
f"
{
i
}
elif isinstance(_detail, str) and _detail:"
,
f"
{
i4
}
# Some backend 422s return a bare string instead of the standard"
,
f"
{
i4
}
# list-of-ValidationError shape (e.g. invalid model alias lookups"
,
f'
{
i4
}
# returning {{"detail": "Model alias
\'
...
\'
not found"}}).'
,
f"
{
i4
}
# Wrap it so callers always receive a consistent ValidationError list."
,
f'
{
i4
}
detail = [ValidationError(loc=[], msg=_detail, type_="server_error")]'
,
]
)
# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
_PATCHED_SENTINEL
=
"isinstance(_detail, list)"
def
patch
(
text
:
str
)
->
tuple
[
str
,
bool
]:
"""Rewrite the from_dict loop; return (patched_text, success)."""
patched
,
count
=
_LOOP_RE
.
subn
(
lambda
m
:
_loop_replacement
(
m
.
group
(
"indent"
)),
text
)
# Treat the file as already-patched if no replacements were made but the
# patched sentinel is present — ensures idempotent re-runs exit 0 instead
# of falsely reporting template drift (exit 2).
already_patched
=
count
==
0
and
_PATCHED_SENTINEL
in
text
return
patched
,
bool
(
count
)
or
already_patched
def
main
()
->
int
:
if
len
(
sys
.
argv
)
!=
2
:
print
(
f"Usage:
{
Path
(
sys
.
argv
[
0
]).
name
}
<file_path>"
,
file
=
sys
.
stderr
)
return
1
target
=
Path
(
sys
.
argv
[
1
])
try
:
original
=
target
.
read_text
(
encoding
=
"utf-8"
)
except
FileNotFoundError
:
print
(
f"
{
target
}
not found"
,
file
=
sys
.
stderr
)
return
1
except
OSError
as
e
:
print
(
f"Error reading
{
target
}
:
{
e
}
"
,
file
=
sys
.
stderr
)
return
1
patched
,
success
=
patch
(
original
)
if
not
success
:
print
(
f"Expected patterns not found in
{
target
}
— template may have changed. "
"Update this script to match the new generated code."
,
file
=
sys
.
stderr
,
)
return
2
if
patched
==
original
:
print
(
f"
{
target
}
already patched — nothing to do."
)
return
0
try
:
target
.
write_text
(
patched
,
encoding
=
"utf-8"
)
except
OSError
as
e
:
print
(
f"Error writing
{
target
}
:
{
e
}
"
,
file
=
sys
.
stderr
)
return
1
print
(
f"Patched
{
target
}
"
)
return
0
if
__name__
==
"__main__"
:
sys
.
exit
(
main
())
Back
|
FazBrowse Home
|
New Git URL