Safe JSON serializer & content-length fix (issue with Routes in Revit French)#3161
Safe JSON serializer & content-length fix (issue with Routes in Revit French)#3161vinnividivicci wants to merge 4 commits intopyrevitlabs:developfrom
Conversation
Add a Unicode-safe JSON serializer (_safe_json_dumps) to handler.py to avoid json.dumps UnicodeDecodeError on IronPython by escaping non-ASCII as \uXXXX. Use json.dumps(..., ensure_ascii=True) with a fallback to _safe_json_dumps when encoding errors occur. Update HttpRequestHandler._write_response to always compute a bytes body, set a correct Content-Length header, skip duplicate Content-Length from response headers, and write the encoded body. Add unit tests covering response framing (Content-Length and body bytes) and Unicode-safe JSON serialization/parse_response behavior.
There was a problem hiding this comment.
PR Summary:
- Adds
_safe_json_dumps()fallback serializer to handleUnicodeDecodeErrorin IronPython 2.7 on French/accented Revit strings. - Updates
HttpRequestHandler._write_responseto always encode the body as bytes and set a correctContent-Lengthheader, skipping any duplicate from response headers. - Adds two unit test files covering response framing and Unicode JSON serialization.
Review Summary:
The Content-Length framing fix is a solid, correct improvement and the overall approach (try json.dumps(ensure_ascii=True), fall back to _safe_json_dumps) is sound. However, there is a critical functional bug: the fallback function _safe_json_dumps checks isinstance(obj, str) which, in IronPython 2.7, will never match unicode objects — precisely the type that carries accented Revit strings. The docstring even incorrectly claims IronPython 2.7 unifies str and unicode (they are distinct; only IronPython 3 unifies them). This means the fallback is unreachable for the exact inputs it was designed to handle. Additionally, the new \n body written for all None-data responses (including 204 No Content) violates RFC 7230. The IPY2712 repo guideline was the key lens for catching the unicode type gap.
Follow-up suggestions:
@devloaifix the identified issues: addunicodeto theisinstancecheck in_safe_json_dumps(usingpyrevit.compat.PY2), guard the\nfallback against no-body status codes (204, 304), and handleinf/nanfloats.
Handle float edge cases in _safe_json_dumps by detecting NaN and infinite values (using math.isnan/math.isinf) and returning "null" so the output remains valid JSON. Adds the math import and the corresponding check in pyrevitlib/pyrevit/routes/server/handler.py.
|
@jmcouffin Bug fixes to the routes API to work properly with Revit, French, and other multilingual Revit installations with non English characters. |
Apply consistent string quoting, spacing, and formatting across routes/server and tests. Changes include normalizing single to double quotes, consistent use of join and string concatenation, cleaning up pylint comment formatting, minor refactors (parentheses, trailing commas, line breaks), and small-safe-json-dumps tweaks. Tests updated to match the formatting changes. No functional behavior changes intended.
Make the _safe_json_dumps docstring a raw string literal to avoid accidental escape processing (e.g., \u sequences) on IronPython. Also adjust the unit test docstring capitalization for clarity in test_routes_server_unicode.py.
Safe JSON serializer & content-length fix (issue with Routes in Revit French)
Description
Add a Unicode-safe JSON serializer (_safe_json_dumps) to handler.py to avoid json.dumps UnicodeDecodeError on IronPython by escaping non-ASCII as \uXXXX. Use json.dumps(..., ensure_ascii=True) with a fallback to _safe_json_dumps when encoding errors occur. Update HttpRequestHandler._write_response to always compute a bytes body, set a correct Content-Length header, skip duplicate Content-Length from response headers, and write the encoded body. Add unit tests covering response framing (Content-Length and body bytes) and Unicode-safe JSON serialization/parse_response behavior.
Checklist
Before submitting your pull request, ensure the following requirements are met:
pipenv run black {source_file_or_directory}Related Issues
If applicable, link the issues resolved by this pull request:
Additional Notes
Include any additional context, screenshots, or considerations for reviewers.
Thank you for contributing to pyRevit! 🎉