Skip to content

Commit dbc5113

Browse files
committed
Improved multiple items.
1 parent 95fc3fd commit dbc5113

5 files changed

Lines changed: 317 additions & 182 deletions

File tree

python_postman/models/auth.py

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,28 @@ def __init__(self, type: str, parameters: Optional[List[AuthParameter]] = None):
7575
parameters: List of authentication parameters
7676
"""
7777
self.type = type
78-
self.parameters = parameters or []
79-
self._parameter_dict: Optional[Dict[str, Any]] = None
78+
self._parameters = []
79+
self._parameter_lookup: Dict[str, AuthParameter] = {}
80+
81+
# Set parameters using property to maintain lookup dict
82+
if parameters:
83+
self.parameters = parameters
84+
85+
@property
86+
def parameters(self) -> List[AuthParameter]:
87+
"""Get the list of authentication parameters."""
88+
return self._parameters
89+
90+
@parameters.setter
91+
def parameters(self, value: List[AuthParameter]) -> None:
92+
"""Set the list of authentication parameters and update lookup dict."""
93+
self._parameters = value or []
94+
# Handle case where non-list values are passed (for validation testing)
95+
try:
96+
self._parameter_lookup = {param.key: param for param in self._parameters}
97+
except (AttributeError, TypeError):
98+
# If parameters are not AuthParameter objects, create empty lookup
99+
self._parameter_lookup = {}
80100

81101
def get_auth_type(self) -> AuthType:
82102
"""
@@ -100,10 +120,8 @@ def get_parameter(self, key: str) -> Optional[Any]:
100120
Returns:
101121
Parameter value or None if not found
102122
"""
103-
for param in self.parameters:
104-
if param.key == key:
105-
return param.value
106-
return None
123+
param = self._parameter_lookup.get(key)
124+
return param.value if param else None
107125

108126
def get_parameter_dict(self) -> Dict[str, Any]:
109127
"""
@@ -112,9 +130,7 @@ def get_parameter_dict(self) -> Dict[str, Any]:
112130
Returns:
113131
Dictionary of parameter key-value pairs
114132
"""
115-
if self._parameter_dict is None:
116-
self._parameter_dict = {param.key: param.value for param in self.parameters}
117-
return self._parameter_dict.copy()
133+
return {key: param.value for key, param in self._parameter_lookup.items()}
118134

119135
def add_parameter(self, key: str, value: Any, type: str = "string") -> None:
120136
"""
@@ -125,12 +141,21 @@ def add_parameter(self, key: str, value: Any, type: str = "string") -> None:
125141
value: Parameter value
126142
type: Parameter type
127143
"""
128-
# Remove existing parameter with same key
129-
self.parameters = [p for p in self.parameters if p.key != key]
130-
# Add new parameter
131-
self.parameters.append(AuthParameter(key, value, type))
132-
# Clear cached parameter dict
133-
self._parameter_dict = None
144+
new_param = AuthParameter(key, value, type)
145+
146+
# If parameter exists, replace it
147+
if key in self._parameter_lookup:
148+
# Find and replace in list
149+
for i, param in enumerate(self._parameters):
150+
if param.key == key:
151+
self._parameters[i] = new_param
152+
break
153+
else:
154+
# Add new parameter
155+
self._parameters.append(new_param)
156+
157+
# Update lookup dict
158+
self._parameter_lookup[key] = new_param
134159

135160
def remove_parameter(self, key: str) -> bool:
136161
"""
@@ -142,12 +167,16 @@ def remove_parameter(self, key: str) -> bool:
142167
Returns:
143168
True if parameter was removed, False if not found
144169
"""
145-
original_length = len(self.parameters)
146-
self.parameters = [p for p in self.parameters if p.key != key]
147-
removed = len(self.parameters) < original_length
148-
if removed:
149-
self._parameter_dict = None
150-
return removed
170+
if key not in self._parameter_lookup:
171+
return False
172+
173+
# Remove from lookup dict
174+
del self._parameter_lookup[key]
175+
176+
# Remove from list
177+
self._parameters = [p for p in self._parameters if p.key != key]
178+
179+
return True
151180

152181
def is_basic_auth(self) -> bool:
153182
"""Check if this is basic authentication."""

python_postman/models/body.py

Lines changed: 92 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -302,9 +302,87 @@ def _parse_json_safely(self, content: str) -> Union[Dict[str, Any], str]:
302302
except json.JSONDecodeError:
303303
return content
304304

305+
def _resolve_variables_in_text(
306+
self, text: str, variable_context: Optional[Dict[str, Any]] = None
307+
) -> str:
308+
"""
309+
Utility method to resolve variables in text content.
310+
311+
Args:
312+
text: Text containing variable placeholders
313+
variable_context: Dictionary of variables for resolution
314+
315+
Returns:
316+
Text with resolved variables
317+
"""
318+
if not text or not variable_context:
319+
return text
320+
321+
import re
322+
323+
def replace_placeholder(match):
324+
var_name = match.group(1).strip()
325+
if var_name in variable_context:
326+
return str(variable_context[var_name])
327+
return match.group(0) # Keep placeholder if variable not found
328+
329+
return re.sub(r'\{\{([^}]+)\}\}', replace_placeholder, text)
330+
331+
def _get_raw_content(
332+
self, variable_context: Optional[Dict[str, Any]] = None
333+
) -> Optional[str]:
334+
"""Get content for RAW mode."""
335+
return self._resolve_variables_in_text(self.raw, variable_context)
336+
337+
def _get_urlencoded_content(
338+
self, variable_context: Optional[Dict[str, Any]] = None
339+
) -> Dict[str, str]:
340+
"""Get content for URLENCODED mode."""
341+
result = {}
342+
for param in self.urlencoded:
343+
if param.is_active():
344+
value = param.get_effective_value(variable_context)
345+
if value is not None:
346+
result[param.key] = value
347+
return result
348+
349+
def _get_formdata_content(
350+
self, variable_context: Optional[Dict[str, Any]] = None
351+
) -> List[tuple]:
352+
"""Get content for FORMDATA mode."""
353+
result = []
354+
for param in self.formdata:
355+
if param.is_active():
356+
if param.is_file():
357+
# File parameter - use src if available, otherwise value
358+
file_value = param.src or param.value or ""
359+
result.append((param.key, file_value, "file"))
360+
else:
361+
# Text parameter
362+
value = param.get_effective_value(variable_context)
363+
if value is not None:
364+
result.append((param.key, value, "text"))
365+
return result
366+
367+
def _get_graphql_content(
368+
self, variable_context: Optional[Dict[str, Any]] = None
369+
) -> Optional[Union[Dict[str, Any], str]]:
370+
"""Get content for GRAPHQL mode."""
371+
if not self.raw:
372+
return None
373+
374+
resolved_content = self._resolve_variables_in_text(self.raw, variable_context)
375+
return self._parse_json_safely(resolved_content)
376+
377+
def _get_file_content(
378+
self, variable_context: Optional[Dict[str, Any]] = None
379+
) -> Optional[str]:
380+
"""Get content for FILE mode."""
381+
return self.file.get("src")
382+
305383
def get_content(
306384
self, variable_context: Optional[Dict[str, Any]] = None
307-
) -> Optional[Union[str, bytes, Dict[str, Any]]]:
385+
) -> Optional[Union[str, Dict[str, Any], List[tuple]]]:
308386
"""
309387
Get the body content in appropriate format.
310388
@@ -321,60 +399,19 @@ def get_content(
321399
if not mode:
322400
return None
323401

324-
if mode == BodyMode.RAW:
325-
content = self.raw
326-
if content and variable_context:
327-
# Resolve variables in raw content
328-
for var_name, var_value in variable_context.items():
329-
placeholder = f"{{{{{var_name}}}}}"
330-
if placeholder in content:
331-
content = content.replace(placeholder, str(var_value))
332-
return content
333-
334-
elif mode == BodyMode.URLENCODED:
335-
# Return as dictionary for URL encoding
336-
result = {}
337-
for param in self.urlencoded:
338-
if param.is_active():
339-
value = param.get_effective_value(variable_context)
340-
if value is not None:
341-
result[param.key] = value
342-
return result
343-
344-
elif mode == BodyMode.FORMDATA:
345-
# Return as list of tuples for multipart form data
346-
result = []
347-
for param in self.formdata:
348-
if param.is_active():
349-
if param.is_file():
350-
# File parameter - use src if available, otherwise value
351-
file_value = param.src or param.value or ""
352-
result.append((param.key, file_value, "file"))
353-
else:
354-
# Text parameter
355-
value = param.get_effective_value(variable_context)
356-
if value is not None:
357-
result.append((param.key, value, "text"))
358-
return result
359-
360-
elif mode == BodyMode.GRAPHQL:
361-
# GraphQL body is typically JSON with query/variables
362-
if self.raw:
363-
if variable_context:
364-
# Resolve variables in the JSON string
365-
content = self.raw
366-
for var_name, var_value in variable_context.items():
367-
placeholder = f"{{{{{var_name}}}}}"
368-
if placeholder in content:
369-
content = content.replace(placeholder, str(var_value))
370-
return self._parse_json_safely(content)
371-
else:
372-
return self._parse_json_safely(self.raw)
373-
return None
374-
375-
elif mode == BodyMode.FILE:
376-
# Return file path
377-
return self.file.get("src")
402+
# Dispatch to mode-specific handlers
403+
content_handlers = {
404+
BodyMode.RAW: self._get_raw_content,
405+
BodyMode.URLENCODED: self._get_urlencoded_content,
406+
BodyMode.FORMDATA: self._get_formdata_content,
407+
BodyMode.GRAPHQL: self._get_graphql_content,
408+
BodyMode.FILE: self._get_file_content,
409+
BodyMode.BINARY: self._get_raw_content, # Binary uses same as raw
410+
}
411+
412+
handler = content_handlers.get(mode)
413+
if handler:
414+
return handler(variable_context)
378415

379416
return None
380417

0 commit comments

Comments
 (0)