Date: 2026-02-11 Scope: Full codebase review (source, tests, packaging, documentation) Test suite: 1240 passed, 1 skipped, 2 warnings
python-postman is a well-structured Python library with a clean two-layer architecture (model layer + optional execution layer). The codebase demonstrates solid engineering with comprehensive type hints, thorough validation, and good separation of concerns. The test suite is extensive at 1240 tests, all passing.
Across four revision cycles, all 25 actionable findings from the original audit have been addressed. The codebase is now in excellent shape. The remaining items are exclusively low-severity cosmetic concerns and inherent architectural limitations that are properly documented.
| Original Finding | Status |
|---|---|
| #1 exec() security — no sandbox | Fixed — restricted builtins + AST validation + thread timeout + docs |
| #2 Broken test file | Fixed — file deleted |
| #3 TimeoutError shadows builtin | Fixed — renamed to ExecutionTimeoutError |
| #4 AuthType enum duplication | Fixed — consolidated to single source of truth (alias) |
| #5 folder.variable vs folder.variables | Fixed — corrected to folder.variables |
| #6 PostmanResponse.json() bug | Fixed — now accesses property correctly |
| #7 Script timeout ineffective | Fixed — thread-based timeout implemented |
| #8 variable_overrides precedence | Fixed — overrides now have higher precedence |
| #10 Changelog self-contradictory | Fixed — rewritten with meaningful entries |
| #11 async_client leak in close() | Fixed — proper cleanup with fallback |
| #12 Duplicate dev dependency groups | Fixed — [dependency-groups] removed |
| #13 PostmanVariables.has() semantics | Fixed — now uses has_variable() |
| Rev2 #2 request.variable singular form | Fixed — changed to request.variables |
| Rev2 #3 VariableTracer wrong scope | Fixed — ENVIRONMENT added to VariableScope enum |
| Rev2 #5 execute_iter() not true iterator | Fixed — new _search_items_iter generator |
| Rev2 #7 Parent hierarchy not wired | Fixed — Collection/Folder.from_dict now wire references |
| Rev2 #13 troubleshooting.md warnings | Fixed — removed non-existent warnings reference |
| Rev2 #14 optional-dependencies.md [all] | Fixed — corrected to show [execution] only |
| Rev2 #18 TestResult pytest warning | Fixed — renamed to CftcTestResult |
| Rev3 #1 exec() residual risk | Fixed — AST validator blocks dunder access; type removed from safe builtins; security boundaries documented in docstring |
| Rev3 #2 AuthType enum duplicated | Fixed — AuthType = AuthTypeEnum alias, single source of truth |
| Rev3 #3 execute_collection/folder duplication | Fixed — _execute_requests extracted |
| Rev3 #4 Missing eq on ValidationResult | Fixed — eq added |
| Rev3 #8 Collection.to_json type hint | Fixed — changed to Optional[int] |
| Rev3 #11 No py.typed marker | Fixed — py.typed file added |
File: request.py:185-216
Request.to_dict() places description at the top level of the dict. In actual Postman collection JSON, the description field may appear either at the item level or inside the request object. The from_dict only reads from the top level (data.get("description")), which means descriptions nested inside the request object are silently dropped during parsing.
Postman collections often contain protocolProfileBehavior fields on items. The parser silently drops these during from_dict, and they're not restored in to_dict. This means from_dict(to_dict()) roundtrips lose data for collections that use this field.
File: url.py:57
The constructor parameter hash shadows the Python builtin hash() function within the method scope. While not a runtime issue (the parameter name matches the Postman schema field name hash), it's a naming concern flagged by linters.
File: script_runner.py:515-588
The _convert_js_to_python() method uses ~20 regex substitutions to convert JavaScript to Python. This handles only basic patterns (var/let/const, true/false/null, ===, simple if/else) and will fail on template literals, destructuring, for...of/for...in loops, complex arrow functions, class syntax, try/catch, and any modern JavaScript features. This limits script execution to only the simplest Postman scripts. This is a known design limitation.
File: init.py
The package re-exports 40+ symbols from its __init__.py. While convenient, it means importing the package loads all model classes even if the user only needs one. For a library of this size, the impact is negligible.
File: tests/test_executor.py
Two tests produce RuntimeWarning: coroutine 'AsyncMockMixin._execute_mock_call' was never awaited. This suggests the mock setup for the async executor path may not be fully correct. Harmless but noisy.
| Metric | Value |
|---|---|
| Total tests | 1240 |
| Passed | 1240 |
| Skipped | 1 |
| Errors | 0 |
| Warnings | 2 (unawaited coroutine warnings in test mocks) |
| Execution time | 0.50s |
Test coverage areas:
- Model classes: Thorough (all models have dedicated test files)
- Execution layer: Good (executor, context, variable resolver, auth handler, script runner, extensions)
- Search/statistics: Covered
- Introspection: Covered (auth resolver, variable tracer)
- Edge cases: Dedicated test file
- Real-world collections: 9 collections tested
- Integration tests: Present
Gaps:
- No property-based/fuzz testing
- No benchmarks for large collection parsing performance
Strengths:
- Clean separation between parsing (zero dependencies) and execution (optional httpx)
- Consistent
from_dict()/to_dict()pattern across all models - Fluent search API with true iterator support (
execute_iter()uses a generator) - Comprehensive exception hierarchy with contextual details
- Well-implemented variable scoping with correct precedence rules
- Good use of ABC for Item base class with factory methods
- Layered script sandbox: restricted builtins + import blocklist + AST validation + thread timeout, with security boundaries clearly documented
- Proper async client cleanup in
close()with sync/async fallback - Parent hierarchy (
_parent_folder,_collection) properly wired during parsing VariableScopeenum includes all four scopes (REQUEST, FOLDER, COLLECTION, ENVIRONMENT)- Single source of truth for
AuthTypevia alias toAuthTypeEnum - DRY execution logic via shared
_execute_requestsmethod - PEP 561 compliant with
py.typedmarker
No significant weaknesses remain. The only architectural limitations are inherent to the design (regex-based JS conversion, exec() for script execution) and are properly documented.
| Priority | Finding | Effort |
|---|---|---|
| P3 | Handle description inside request object during parsing (#1) |
Low |
| P3 | Preserve protocolProfileBehavior in roundtrips (#2) |
Low |
| P4 | No action needed — remaining items are cosmetic/informational | — |