├── .bumpversion.cfg ├── .gitattributes ├── .github ├── FUNDING.yml └── workflows │ └── release.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── MANIFEST.in ├── README.md ├── docs ├── Makefile ├── _static │ ├── .keep │ ├── logo.png │ └── logo_dark.png ├── conf.py ├── contrib │ ├── changelog.rst │ └── index.rst ├── dropin.rst ├── index.rst ├── license.rst ├── make.bat ├── native.rst └── performance.rst ├── jsonexamples ├── apache_builds.json ├── canada.json ├── citm_catalog.json ├── github_events.json ├── gsoc-2018.json ├── instruments.json ├── invalid.json ├── marine_ik.json ├── mesh.json ├── mesh.pretty.json ├── numbers.json ├── random.json ├── small │ ├── adversarial.json │ ├── demo.json │ ├── flatadversarial.json │ ├── repeat.json │ ├── truenull.json │ └── twitter_timeline.json ├── test_parsing │ ├── LICENSE │ ├── i_number_double_huge_neg_exp.json │ ├── i_number_huge_exp.json │ ├── i_number_neg_int_huge_exp.json │ ├── i_number_pos_double_huge_exp.json │ ├── i_number_real_neg_overflow.json │ ├── i_number_real_pos_overflow.json │ ├── i_number_real_underflow.json │ ├── i_number_too_big_neg_int.json │ ├── i_number_too_big_pos_int.json │ ├── i_number_very_big_negative_int.json │ ├── i_object_key_lone_2nd_surrogate.json │ ├── i_string_1st_surrogate_but_2nd_missing.json │ ├── i_string_1st_valid_surrogate_2nd_invalid.json │ ├── i_string_UTF-16LE_with_BOM.json │ ├── i_string_UTF-8_invalid_sequence.json │ ├── i_string_UTF8_surrogate_U+D800.json │ ├── i_string_incomplete_surrogate_and_escape_valid.json │ ├── i_string_incomplete_surrogate_pair.json │ ├── i_string_incomplete_surrogates_escape_valid.json │ ├── i_string_invalid_lonely_surrogate.json │ ├── i_string_invalid_surrogate.json │ ├── i_string_invalid_utf-8.json │ ├── i_string_inverted_surrogates_U+1D11E.json │ ├── i_string_iso_latin_1.json │ ├── i_string_lone_second_surrogate.json │ ├── i_string_lone_utf8_continuation_byte.json │ ├── i_string_not_in_unicode_range.json │ ├── i_string_overlong_sequence_2_bytes.json │ ├── i_string_overlong_sequence_6_bytes.json │ ├── i_string_overlong_sequence_6_bytes_null.json │ ├── i_string_truncated-utf-8.json │ ├── i_string_utf16BE_no_BOM.json │ ├── i_string_utf16LE_no_BOM.json │ ├── i_structure_500_nested_arrays.json │ ├── i_structure_UTF-8_BOM_empty_object.json │ ├── n_array_1_true_without_comma.json │ ├── n_array_a_invalid_utf8.json │ ├── n_array_colon_instead_of_comma.json │ ├── n_array_comma_after_close.json │ ├── n_array_comma_and_number.json │ ├── n_array_double_comma.json │ ├── n_array_double_extra_comma.json │ ├── n_array_extra_close.json │ ├── n_array_extra_comma.json │ ├── n_array_incomplete.json │ ├── n_array_incomplete_invalid_value.json │ ├── n_array_inner_array_no_comma.json │ ├── n_array_invalid_utf8.json │ ├── n_array_items_separated_by_semicolon.json │ ├── n_array_just_comma.json │ ├── n_array_just_minus.json │ ├── n_array_missing_value.json │ ├── n_array_newlines_unclosed.json │ ├── n_array_number_and_comma.json │ ├── n_array_number_and_several_commas.json │ ├── n_array_spaces_vertical_tab_formfeed.json │ ├── n_array_star_inside.json │ ├── n_array_unclosed.json │ ├── n_array_unclosed_trailing_comma.json │ ├── n_array_unclosed_with_new_lines.json │ ├── n_array_unclosed_with_object_inside.json │ ├── n_incomplete_false.json │ ├── n_incomplete_null.json │ ├── n_incomplete_true.json │ ├── n_multidigit_number_then_00.json │ ├── n_number_++.json │ ├── n_number_+1.json │ ├── n_number_+Inf.json │ ├── n_number_-01.json │ ├── n_number_-1.0..json │ ├── n_number_-2..json │ ├── n_number_-NaN.json │ ├── n_number_.-1.json │ ├── n_number_.2e-3.json │ ├── n_number_0.1.2.json │ ├── n_number_0.3e+.json │ ├── n_number_0.3e.json │ ├── n_number_0.e1.json │ ├── n_number_0_capital_E+.json │ ├── n_number_0_capital_E.json │ ├── n_number_0e+.json │ ├── n_number_0e.json │ ├── n_number_1.0e+.json │ ├── n_number_1.0e-.json │ ├── n_number_1.0e.json │ ├── n_number_1_000.json │ ├── n_number_1eE2.json │ ├── n_number_2.e+3.json │ ├── n_number_2.e-3.json │ ├── n_number_2.e3.json │ ├── n_number_9.e+.json │ ├── n_number_Inf.json │ ├── n_number_NaN.json │ ├── n_number_U+FF11_fullwidth_digit_one.json │ ├── n_number_expression.json │ ├── n_number_hex_1_digit.json │ ├── n_number_hex_2_digits.json │ ├── n_number_infinity.json │ ├── n_number_invalid+-.json │ ├── n_number_invalid-negative-real.json │ ├── n_number_invalid-utf-8-in-bigger-int.json │ ├── n_number_invalid-utf-8-in-exponent.json │ ├── n_number_invalid-utf-8-in-int.json │ ├── n_number_minus_infinity.json │ ├── n_number_minus_sign_with_trailing_garbage.json │ ├── n_number_minus_space_1.json │ ├── n_number_neg_int_starting_with_zero.json │ ├── n_number_neg_real_without_int_part.json │ ├── n_number_neg_with_garbage_at_end.json │ ├── n_number_real_garbage_after_e.json │ ├── n_number_real_with_invalid_utf8_after_e.json │ ├── n_number_real_without_fractional_part.json │ ├── n_number_starting_with_dot.json │ ├── n_number_with_alpha.json │ ├── n_number_with_alpha_char.json │ ├── n_number_with_leading_zero.json │ ├── n_object_bad_value.json │ ├── n_object_bracket_key.json │ ├── n_object_comma_instead_of_colon.json │ ├── n_object_double_colon.json │ ├── n_object_emoji.json │ ├── n_object_garbage_at_end.json │ ├── n_object_key_with_single_quotes.json │ ├── n_object_lone_continuation_byte_in_key_and_trailing_comma.json │ ├── n_object_missing_colon.json │ ├── n_object_missing_key.json │ ├── n_object_missing_semicolon.json │ ├── n_object_missing_value.json │ ├── n_object_no-colon.json │ ├── n_object_non_string_key.json │ ├── n_object_non_string_key_but_huge_number_instead.json │ ├── n_object_repeated_null_null.json │ ├── n_object_several_trailing_commas.json │ ├── n_object_single_quote.json │ ├── n_object_trailing_comma.json │ ├── n_object_trailing_comment.json │ ├── n_object_trailing_comment_open.json │ ├── n_object_trailing_comment_slash_open.json │ ├── n_object_trailing_comment_slash_open_incomplete.json │ ├── n_object_two_commas_in_a_row.json │ ├── n_object_unquoted_key.json │ ├── n_object_unterminated-value.json │ ├── n_object_with_single_string.json │ ├── n_object_with_trailing_garbage.json │ ├── n_single_space.json │ ├── n_string_1_surrogate_then_escape.json │ ├── n_string_1_surrogate_then_escape_u.json │ ├── n_string_1_surrogate_then_escape_u1.json │ ├── n_string_1_surrogate_then_escape_u1x.json │ ├── n_string_accentuated_char_no_quotes.json │ ├── n_string_backslash_00.json │ ├── n_string_escape_x.json │ ├── n_string_escaped_backslash_bad.json │ ├── n_string_escaped_ctrl_char_tab.json │ ├── n_string_escaped_emoji.json │ ├── n_string_incomplete_escape.json │ ├── n_string_incomplete_escaped_character.json │ ├── n_string_incomplete_surrogate.json │ ├── n_string_incomplete_surrogate_escape_invalid.json │ ├── n_string_invalid-utf-8-in-escape.json │ ├── n_string_invalid_backslash_esc.json │ ├── n_string_invalid_unicode_escape.json │ ├── n_string_invalid_utf8_after_escape.json │ ├── n_string_leading_uescaped_thinspace.json │ ├── n_string_no_quotes_with_bad_escape.json │ ├── n_string_single_doublequote.json │ ├── n_string_single_quote.json │ ├── n_string_single_string_no_double_quotes.json │ ├── n_string_start_escape_unclosed.json │ ├── n_string_unescaped_crtl_char.json │ ├── n_string_unescaped_newline.json │ ├── n_string_unescaped_tab.json │ ├── n_string_unicode_CapitalU.json │ ├── n_string_with_trailing_garbage.json │ ├── n_structure_100000_opening_arrays.json │ ├── n_structure_U+2060_word_joined.json │ ├── n_structure_UTF8_BOM_no_data.json │ ├── n_structure_angle_bracket_..json │ ├── n_structure_angle_bracket_null.json │ ├── n_structure_array_trailing_garbage.json │ ├── n_structure_array_with_extra_array_close.json │ ├── n_structure_array_with_unclosed_string.json │ ├── n_structure_ascii-unicode-identifier.json │ ├── n_structure_capitalized_True.json │ ├── n_structure_close_unopened_array.json │ ├── n_structure_comma_instead_of_closing_brace.json │ ├── n_structure_double_array.json │ ├── n_structure_end_array.json │ ├── n_structure_incomplete_UTF8_BOM.json │ ├── n_structure_lone-invalid-utf-8.json │ ├── n_structure_lone-open-bracket.json │ ├── n_structure_no_data.json │ ├── n_structure_null-byte-outside-string.json │ ├── n_structure_number_with_trailing_garbage.json │ ├── n_structure_object_followed_by_closing_object.json │ ├── n_structure_object_unclosed_no_value.json │ ├── n_structure_object_with_comment.json │ ├── n_structure_object_with_trailing_garbage.json │ ├── n_structure_open_array_apostrophe.json │ ├── n_structure_open_array_comma.json │ ├── n_structure_open_array_object.json │ ├── n_structure_open_array_open_object.json │ ├── n_structure_open_array_open_string.json │ ├── n_structure_open_array_string.json │ ├── n_structure_open_object.json │ ├── n_structure_open_object_close_array.json │ ├── n_structure_open_object_comma.json │ ├── n_structure_open_object_open_array.json │ ├── n_structure_open_object_open_string.json │ ├── n_structure_open_object_string_with_apostrophes.json │ ├── n_structure_open_open.json │ ├── n_structure_single_eacute.json │ ├── n_structure_single_star.json │ ├── n_structure_trailing_#.json │ ├── n_structure_uescaped_LF_before_string.json │ ├── n_structure_unclosed_array.json │ ├── n_structure_unclosed_array_partial_null.json │ ├── n_structure_unclosed_array_unfinished_false.json │ ├── n_structure_unclosed_array_unfinished_true.json │ ├── n_structure_unclosed_object.json │ ├── n_structure_unicode-identifier.json │ ├── n_structure_whitespace_U+2060_word_joiner.json │ ├── n_structure_whitespace_formfeed.json │ ├── y_array_arraysWithSpaces.json │ ├── y_array_empty-string.json │ ├── y_array_empty.json │ ├── y_array_ending_with_newline.json │ ├── y_array_false.json │ ├── y_array_heterogeneous.json │ ├── y_array_null.json │ ├── y_array_with_1_and_newline.json │ ├── y_array_with_leading_space.json │ ├── y_array_with_several_null.json │ ├── y_array_with_trailing_space.json │ ├── y_number.json │ ├── y_number_0e+1.json │ ├── y_number_0e1.json │ ├── y_number_after_space.json │ ├── y_number_double_close_to_zero.json │ ├── y_number_int_with_exp.json │ ├── y_number_minus_zero.json │ ├── y_number_negative_int.json │ ├── y_number_negative_one.json │ ├── y_number_negative_zero.json │ ├── y_number_real_capital_e.json │ ├── y_number_real_capital_e_neg_exp.json │ ├── y_number_real_capital_e_pos_exp.json │ ├── y_number_real_exponent.json │ ├── y_number_real_fraction_exponent.json │ ├── y_number_real_neg_exp.json │ ├── y_number_real_pos_exponent.json │ ├── y_number_simple_int.json │ ├── y_number_simple_real.json │ ├── y_object.json │ ├── y_object_basic.json │ ├── y_object_duplicated_key.json │ ├── y_object_duplicated_key_and_value.json │ ├── y_object_empty.json │ ├── y_object_empty_key.json │ ├── y_object_escaped_null_in_key.json │ ├── y_object_extreme_numbers.json │ ├── y_object_long_strings.json │ ├── y_object_simple.json │ ├── y_object_string_unicode.json │ ├── y_object_with_newlines.json │ ├── y_string_1_2_3_bytes_UTF-8_sequences.json │ ├── y_string_accepted_surrogate_pair.json │ ├── y_string_accepted_surrogate_pairs.json │ ├── y_string_allowed_escapes.json │ ├── y_string_backslash_and_u_escaped_zero.json │ ├── y_string_backslash_doublequotes.json │ ├── y_string_comments.json │ ├── y_string_double_escape_a.json │ ├── y_string_double_escape_n.json │ ├── y_string_escaped_control_character.json │ ├── y_string_escaped_noncharacter.json │ ├── y_string_in_array.json │ ├── y_string_in_array_with_leading_space.json │ ├── y_string_last_surrogates_1_and_2.json │ ├── y_string_nbsp_uescaped.json │ ├── y_string_nonCharacterInUTF-8_U+10FFFF.json │ ├── y_string_nonCharacterInUTF-8_U+FFFF.json │ ├── y_string_null_escape.json │ ├── y_string_one-byte-utf-8.json │ ├── y_string_pi.json │ ├── y_string_reservedCharacterInUTF-8_U+1BFFF.json │ ├── y_string_simple_ascii.json │ ├── y_string_space.json │ ├── y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json │ ├── y_string_three-byte-utf-8.json │ ├── y_string_two-byte-utf-8.json │ ├── y_string_u+2028_line_sep.json │ ├── y_string_u+2029_par_sep.json │ ├── y_string_uEscape.json │ ├── y_string_uescaped_newline.json │ ├── y_string_unescaped_char_delete.json │ ├── y_string_unicode.json │ ├── y_string_unicodeEscapedBackslash.json │ ├── y_string_unicode_2.json │ ├── y_string_unicode_U+10FFFE_nonchar.json │ ├── y_string_unicode_U+1FFFE_nonchar.json │ ├── y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json │ ├── y_string_unicode_U+2064_invisible_plus.json │ ├── y_string_unicode_U+FDD0_nonchar.json │ ├── y_string_unicode_U+FFFE_nonchar.json │ ├── y_string_unicode_escaped_double_quote.json │ ├── y_string_utf8.json │ ├── y_string_with_del_character.json │ ├── y_structure_lonely_false.json │ ├── y_structure_lonely_int.json │ ├── y_structure_lonely_negative_real.json │ ├── y_structure_lonely_null.json │ ├── y_structure_lonely_string.json │ ├── y_structure_lonely_true.json │ ├── y_structure_string_empty.json │ ├── y_structure_trailing_newline.json │ ├── y_structure_true_in_array.json │ └── y_structure_whitespace_array.json ├── test_transform │ ├── LICENSE │ ├── number_-9223372036854775808.json │ ├── number_-9223372036854775809.json │ ├── number_1.0.json │ ├── number_1.000000000000000005.json │ ├── number_1000000000000000.json │ ├── number_10000000000000000999.json │ ├── number_1e-999.json │ ├── number_1e6.json │ ├── number_9223372036854775807.json │ ├── number_9223372036854775808.json │ ├── object_key_nfc_nfd.json │ ├── object_key_nfd_nfc.json │ ├── object_same_key_different_values.json │ ├── object_same_key_same_value.json │ ├── object_same_key_unclear_values.json │ ├── string_1_escaped_invalid_codepoint.json │ ├── string_1_invalid_codepoint.json │ ├── string_2_escaped_invalid_codepoints.json │ ├── string_2_invalid_codepoints.json │ ├── string_3_escaped_invalid_codepoints.json │ ├── string_3_invalid_codepoints.json │ └── string_with_escaped_NULL.json ├── twitter.json ├── twitterescaped.json └── update-center.json ├── pyproject.toml ├── scripts └── coverage.py ├── setup.cfg ├── simdjson ├── __init__.py ├── __init__.pyi ├── csimdjson.pxd ├── csimdjson.pyx ├── py.typed ├── simdjson.cpp ├── simdjson.h ├── util.cpp └── util.h └── tests ├── conftest.py ├── test_array.py ├── test_element.py ├── test_minefield.py ├── test_numpy.py ├── test_object.py ├── test_parser.py ├── test_safety.py └── test_shim.py /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 6.0.2 3 | commit = True 4 | tag = True 5 | 6 | [bumpversion:file:setup.py] 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * linguist-vendored 2 | *.py linguist-vendored=false 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: TkTech 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with a single custom sponsorship URL 13 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_dispatch: 3 | release: 4 | types: 5 | - published 6 | push: 7 | branches: 8 | - main 9 | pull_request: 10 | 11 | name: Tests/Release 12 | jobs: 13 | # Build & test simple source release before wasting hours building and 14 | # testing the binary build matrix. 15 | sdist: 16 | name: Creating source release 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4.1.7 20 | 21 | - name: Setting up Python 22 | uses: actions/setup-python@v5 23 | with: 24 | python-version: 3.13 25 | 26 | - name: Installing python build dependencies 27 | run: | 28 | pip install uv 29 | 30 | - name: Building source distribution 31 | run: | 32 | uv build --sdist 33 | 34 | - name: Ensuring documentation builds 35 | run: | 36 | cd docs && uv run make clean html 37 | 38 | - uses: actions/upload-artifact@v4.6.0 39 | with: 40 | name: dist-sdist 41 | path: dist/*.tar.gz 42 | 43 | build_wheels: 44 | needs: [sdist] 45 | name: "[${{ strategy.job-index }}/${{ strategy.job-total }}] py${{ matrix.py }} on ${{ matrix.os }}" 46 | runs-on: ${{ matrix.os }} 47 | strategy: 48 | fail-fast: true 49 | matrix: 50 | os: [ubuntu-latest, windows-latest, macos-14] 51 | py: ["cp39", "cp310", "cp311", "cp312", "cp313"] 52 | 53 | steps: 54 | - uses: actions/checkout@v4.1.7 55 | 56 | - name: Setting up Python 57 | uses: actions/setup-python@v5 58 | with: 59 | python-version: "3.13" 60 | 61 | - name: Set up QEMU 62 | if: runner.os == 'Linux' 63 | uses: docker/setup-qemu-action@v3 64 | with: 65 | platforms: all 66 | 67 | - name: Build & test wheels 68 | uses: pypa/cibuildwheel@v2.22.0 69 | env: 70 | CIBW_BUILD: "${{ matrix.py }}-*" 71 | 72 | - uses: actions/upload-artifact@v4.6.0 73 | with: 74 | name: dist-${{ matrix.os }}-${{ matrix.py }} 75 | path: ./wheelhouse/*.whl 76 | 77 | upload_all: 78 | name: Uploading built packages to pypi for release. 79 | needs: [build_wheels, sdist] 80 | if: github.event_name == 'release' 81 | runs-on: ubuntu-latest 82 | steps: 83 | - uses: actions/download-artifact@v4.1.8 84 | with: 85 | pattern: dist-* 86 | merge-multiple: true 87 | path: dist 88 | 89 | - uses: pypa/gh-action-pypi-publish@v1.4.2 90 | with: 91 | user: ${{ secrets.PYPI_USERNAME }} 92 | password: ${{ secrets.PYPI_PASSWORD }} 93 | 94 | build_documentation: 95 | name: Building & uploading documentation. 96 | needs: [upload_all] 97 | if: github.event_name == 'release' 98 | runs-on: ubuntu-latest 99 | steps: 100 | - uses: actions/checkout@v4.1.7 101 | 102 | - name: Setting up Python 103 | uses: actions/setup-python@v5 104 | with: 105 | python-version: 3.13 106 | 107 | - name: Installing python build dependencies 108 | run: | 109 | pip install uv 110 | 111 | - name: Installing release dependencies. 112 | run: | 113 | uv sync 114 | 115 | - name: Building documentation 116 | run: | 117 | cd docs && uv run make clean html 118 | 119 | - name: Publishing documentation 120 | run: | 121 | uv run ghp-import -f -n -c pysimdjson.tkte.ch -p docs/_build/html 122 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Python cruft 2 | *.pyc 3 | *.pyd 4 | venv 5 | .eggs 6 | cython_debug/* 7 | build/ 8 | _build/ 9 | .benchmarks/ 10 | *.egg-info 11 | 12 | # Extension building cruft 13 | *.so 14 | 15 | # coverage.py default output file 16 | .coverage 17 | .idea 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 7.0.1 4 | 5 | - Ensure csimdjson.pxd is included in the sdist (#129) 6 | 7 | ## 7.0.0 8 | 9 | - Drop python 3.8, pypy builds, add python 3.13 (#117, #123) 10 | - Add proper .load/.loads type signatures (#116) 11 | - Updating and modernize github actions, simplify packaging and CI. 12 | - Update upstream simdjson to 3.12.3. 13 | - Add alias to json.JSONEncoder to drop-in API. (#118) 14 | - Deterministic build / static build metadata 15 | 16 | ## 6.0.0 17 | 18 | - Dropped support for CPython 3.6 - 3.8 which are long past their support window, 19 | added support for CPython for 3.11 & 3.12. 20 | - Updated upstream simdjson library to 3.6.4. 21 | - Various packaging, CI, and compiler version bumps. 22 | 23 | ## 5.0.1 24 | 25 | - Expanded PyPy prebuilt binary support (packaging change only). 26 | 27 | ## 5.0.0 28 | 29 | - Updated upstream simdjson library to 2.0.1, which brings AVX-512 support. 30 | - `Parser.implementations` property replaced with `Parser.get_implementations` 31 | to support optionally filtering to just the ones supported by the current 32 | runtime. 33 | 34 | ## 4.0.3 35 | 36 | - Updated upstream simdjson library to 1.0.2. 37 | - Binary wheels are now tested and available for py3.6-py3.10 on x86[_64], 38 | ppc64le and aarch64. 39 | - Under Linux, wheels are built for both manylinux and musl (Alpine). 40 | - Under Linux, wheels are also available for PyPy3.7. 41 | - Minor documentation fixes. 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tyler Kennedy 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | 21 | ======== 22 | 23 | simdjson.cpp and simdjson.h are used under the Apache License 2.0. Find a copy 24 | at https://github.com/simdjson/simdjson/blob/master/LICENSE. 25 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include simdjson/simdjson.h 2 | include simdjson/simdjson.cpp 3 | include simdjson/util.h 4 | include simdjson/util.cpp 5 | include simdjson/csimdjson.pxd -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![PyPI - License](https://img.shields.io/pypi/l/pysimdjson.svg?style=flat-square) 2 | ![Tests](https://github.com/TkTech/pysimdjson/workflows/Run%20tests/badge.svg) 3 | 4 | # pysimdjson 5 | 6 | Python bindings for the [simdjson][] project, a SIMD-accelerated JSON parser. 7 | If SIMD instructions are unavailable a fallback parser is used, making 8 | pysimdjson safe to use anywhere. 9 | 10 | Bindings are currently tested on OS X, Linux, and Windows for Python version 11 | 3.9 to 3.12. 12 | 13 | ## 📝 Documentation 14 | 15 | The latest documentation can be found at https://pysimdjson.tkte.ch. 16 | 17 | If you've checked out the source code (for example to review a PR), you can 18 | build the latest documentation by running `cd docs && make html`. 19 | 20 | ## 📈 Benchmarks 21 | 22 | pysimdjson compares well against most libraries. The full benchmarks can be 23 | found in its sister project [json_benchmark][]. 24 | 25 | [simdjson]: https://github.com/lemire/simdjson 26 | [json_benchmark]: https://github.com/tktech/json_benchmark 27 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | import: 16 | ghp-import -n -c pysimdjson.tkte.ch "$(BUILDDIR)/html" 17 | 18 | .PHONY: help Makefile 19 | 20 | # Catch-all target: route all unknown targets to Sphinx using the new 21 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 22 | %: Makefile 23 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 24 | -------------------------------------------------------------------------------- /docs/_static/.keep: -------------------------------------------------------------------------------- 1 | This is here to ensure this directory exists, preventing warnings in sphinx. 2 | -------------------------------------------------------------------------------- /docs/_static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/docs/_static/logo.png -------------------------------------------------------------------------------- /docs/_static/logo_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/docs/_static/logo_dark.png -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | # import os 14 | # import sys 15 | 16 | # -- Project information ----------------------------------------------------- 17 | 18 | project = 'pysimdjson' 19 | copyright = '2021, Tyler Kennedy' 20 | author = 'Tyler Kennedy' 21 | 22 | 23 | # -- General configuration --------------------------------------------------- 24 | 25 | # Add any Sphinx extension module names here, as strings. They can be 26 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 27 | # ones. 28 | extensions = [ 29 | 'sphinx.ext.autodoc', 30 | 'sphinx.ext.viewcode', 31 | 'sphinx.ext.todo' 32 | ] 33 | 34 | # Add any paths that contain templates here, relative to this directory. 35 | templates_path = ['_templates'] 36 | 37 | # The language for content autogenerated by Sphinx. Refer to documentation 38 | # for a list of supported languages. 39 | # 40 | # This is also used if you do content translation via gettext catalogs. 41 | # Usually you set "language" from the command line for these cases. 42 | language = 'en' 43 | 44 | # List of patterns, relative to source directory, that match files and 45 | # directories to ignore when looking for source files. 46 | # This pattern also affects html_static_path and html_extra_path. 47 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 48 | 49 | 50 | # -- Options for HTML output ------------------------------------------------- 51 | 52 | # The theme to use for HTML and HTML Help pages. See the documentation for 53 | # a list of builtin themes. 54 | # 55 | html_theme = 'furo' 56 | html_title = 'pysimdjson' 57 | 58 | # Add any paths that contain custom static files (such as style sheets) here, 59 | # relative to this directory. They are copied after the builtin static files, 60 | # so a file named "default.css" will overwrite the builtin "default.css". 61 | html_static_path = ['_static'] 62 | html_theme_options = { 63 | 'light_logo': 'logo.png', 64 | 'dark_logo': 'logo_dark.png', 65 | 'sidebar_hide_name': True 66 | } 67 | 68 | 69 | # -- Extension configuration ------------------------------------------------- 70 | 71 | # -- Options for todo extension ---------------------------------------------- 72 | 73 | # If true, `todo` and `todoList` produce output, else they produce nothing. 74 | todo_include_todos = True 75 | -------------------------------------------------------------------------------- /docs/contrib/changelog.rst: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | 4 | Version 4.0.0 5 | ------------- 6 | 7 | Changes: 8 | 9 | - Completely rewritten from the ground up, switching from pybind11 (back) to 10 | Cython due to unacceptable overhead on function calls. 11 | - New project logo! 12 | - Typings (thanks kornicameister!) 13 | - Python 3.5 support has been removed (here we come f-strings!) 14 | - Official pypy3 support has been temporarily removed (due to memory safety 15 | concerns with PyPy's delayed __del__). Still works if you build yourself 16 | and re-use the Parser with care. Are you a pypy expert? We could use your 17 | help! 18 | - Using `as_buffer()` will now always return a buffer typed as a flat array 19 | of bytes. 20 | - Array.slots() has been removed. As we prepare to support the simdjson 21 | On-Demand and future streaming API, details specific to the DOM API will be 22 | removed and/or abstracted. 23 | 24 | Bugfixes: 25 | 26 | - Enforces the simdjson document lifecycle, preventing the unsafe usage of 27 | Object or Array when parsers are re-used. 28 | - Prevents Parser instances from going out of scope when an Object or Array 29 | 30 | Deprecation: 31 | 32 | - Python 3.6 support will be removed with the next major release, so that we 33 | can take advantage of new features in 3.7 (PEP 562, insert-order-dict, PEP 34 | 539) for future work. 35 | -------------------------------------------------------------------------------- /docs/contrib/index.rst: -------------------------------------------------------------------------------- 1 | Development 2 | =========== 3 | 4 | This project comes with a full test suite. To install development and testing 5 | dependencies, use: 6 | 7 | .. code:: 8 | 9 | pip install -e ".[test]" 10 | 11 | To run the tests, just type ``pytest``. To also run some slow integration 12 | tests, use ``pytest --runslow``. 13 | 14 | To properly test builds on Windows, you need both a recent version of Visual 15 | Studio as well as VS2015, patch 3. Older versions of CPython required portable 16 | C/C++ extensions to be built with the same version of VS as the interpreter. 17 | Use the `Developer Command Prompt`_ to easily switch between versions. 18 | 19 | Cythonize 20 | --------- 21 | 22 | pysimdjson is written using `Cython`_. However, by default ``setup.py`` will 23 | use the already-generated ``csimdjson.cpp`` instead of regenerating it. This 24 | is to avoid making Cython an install-time requirement. 25 | 26 | To force the usage of Cython, use ``BUILD_WITH_CYTHON``: 27 | 28 | .. code:: 29 | 30 | BUILD_WITH_CYTHON=1 python setup.py develop 31 | 32 | This will cause Cython to regenerate the ``csimdjson.cpp`` from the 33 | ``csimdjson.pyx`` and ``csimdjson.pxd`` files. 34 | 35 | To build pysimdjson with support for linetracing and coverage, use ``BUILD_FOR_DEBUG``: 36 | 37 | .. code:: 38 | 39 | BUILD_WITH_CYTHON=1 BUILD_FOR_DEBUG=1 python setup.py develop 40 | 41 | pysimdjson will also reuse the generated .so file if you build it more than 42 | once, so to force Cython to rebuild it, use ``FORCE_REBUILD``: 43 | 44 | .. code:: 45 | 46 | BUILD_WITH_CYTHON=1 FORCE_REBUILD=1 python setup.py develop 47 | 48 | Benchmarks 49 | ---------- 50 | 51 | The benchmarks that used to exist in this project have been moved into a 52 | sister project, `json_benchmark`_. This project contains a number of 53 | benchmarks for various JSON libraries, including pysimdjson. It also tests 54 | for correctness, so it can be used to verify that simdjson is working 55 | correctly. 56 | 57 | .. _Developer Command Prompt: https://docs.microsoft.com/en-us/dotnet/ 58 | framework/tools/developer-command-prompt-for-vs 59 | .. _Cython: https://cython.readthedocs.io/en/latest/ 60 | .. _json_benchmark: https://github.com/tktech/json_benchmark -------------------------------------------------------------------------------- /docs/dropin.rst: -------------------------------------------------------------------------------- 1 | Drop-in API 2 | =========== 3 | 4 | .. module:: simdjson 5 | 6 | These methods are provided as drop-in replacements to the built-in JSON module. 7 | They sacrifice some of the speed provided by the :class:`~Parser` interface in 8 | exchange for "just working". 9 | 10 | .. autofunction:: load 11 | .. autofunction:: loads 12 | 13 | .. note:: 14 | 15 | The dump and dumps module are currently just aliased to the built-in JSON 16 | serializer. 17 | 18 | .. autofunction:: dump 19 | .. autofunction:: dumps 20 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | pysimdjson 2 | ========== 3 | 4 | .. toctree:: 5 | :caption: Contents: 6 | :hidden: 7 | :maxdepth: 4 8 | :titlesonly: 9 | 10 | self 11 | performance 12 | dropin 13 | native 14 | 15 | .. toctree:: 16 | :caption: Development: 17 | :hidden: 18 | 19 | contrib/index.rst 20 | contrib/changelog.rst 21 | license 22 | 23 | Python bindings for the `simdjson`_ project, a SIMD-accelerated JSON parser. 24 | If SIMD instructions are unavailable a fallback parser is used, making 25 | pysimdjson safe to use anywhere. 26 | 27 | Bindings are currently tested on OS X, Linux, and Windows for Python version 28 | 3.9 to 3.12. 29 | 30 | Installation 31 | ------------ 32 | 33 | If binary wheels are available for your platform, you can install from pip 34 | with no further requirements: 35 | 36 | .. code:: 37 | 38 | pip install pysimdjson 39 | 40 | Binary wheels are available for the following: 41 | 42 | +--------------+-------+-------+-------+---------+---------+ 43 | | | x86_64 | ARM64 | PowerPC | 44 | +--------------+-------+-------+-------+---------+---------+ 45 | | Interpreter | OS X | Win | Linux | Linux | Linux | 46 | +==============+=======+=======+=======+=========+=========+ 47 | | CPython 3.9 | Yes | Yes | Yes | Yes | Yes | 48 | +--------------+-------+-------+-------+---------+---------+ 49 | | CPython 3.10 | Yes | Yes | Yes | Yes | Yes | 50 | +--------------+-------+-------+-------+---------+---------+ 51 | | CPython 3.11 | Yes | Yes | Yes | Yes | Yes | 52 | +--------------+-------+-------+-------+---------+---------+ 53 | | CPython 3.12 | Yes | Yes | Yes | Yes | Yes | 54 | +--------------+-------+-------+-------+---------+---------+ 55 | 56 | When binary wheels are not available, a C++11 (or better) compiler is required 57 | when installing in order to build the underlying simdjson library. 58 | 59 | If you would prefer to always install pysimdjson from source even when 60 | pre-compiled binaries are available (to take advantage of a newer compiler for 61 | example), use: 62 | 63 | .. code:: 64 | 65 | pip install pysimdjson --no-binary :all: 66 | 67 | .. admonition:: Packages 68 | :class: tip 69 | 70 | pysimdjson is also available from unofficial packages contributed by the 71 | community. You can currently get it from Gentoo and conda-forge. Note these 72 | may lag behind in releases. 73 | 74 | .. _simdjson: https://github.com/simdjson/simdjson 75 | .. _LICENSE: https://github.com/tktech/pysimdjson/blob/master/LICENSE 76 | -------------------------------------------------------------------------------- /docs/license.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | License 3 | ======= 4 | 5 | **MIT License** 6 | 7 | .. include:: ../LICENSE 8 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/native.rst: -------------------------------------------------------------------------------- 1 | Native API 2 | ========== 3 | 4 | .. currentmodule:: simdjson 5 | 6 | The native simdjson API offers significant performance improvements over the 7 | builtin-compatible API if only part of a document is of interest. 8 | 9 | Objects and arrays are returned as fake dicts (:class:`~Object`) and lists 10 | (:class:`~Array`) that delay the creation of Python objects until they are 11 | accessed. 12 | 13 | .. autoclass:: Parser 14 | :members: 15 | 16 | .. autoclass:: Array 17 | :members: 18 | 19 | .. autoclass:: Object 20 | :members: 21 | 22 | Constants 23 | --------- 24 | 25 | .. py:data:: MAXSIZE_BYTES 26 | :type: int 27 | :value: 4294967295 28 | 29 | The maximum document size (in bytes) supported by simdjson. 30 | 31 | .. py:data:: PADDING 32 | :type: int 33 | :value: 32 34 | 35 | The amount of padding needed in a buffer to parse JSON. 36 | 37 | In general, pysimdjson takes care of padding for you and you do not need 38 | to worry about this. 39 | 40 | .. py:data:: VERSION 41 | :type: str 42 | 43 | The version of the embedded simdjson library. 44 | -------------------------------------------------------------------------------- /docs/performance.rst: -------------------------------------------------------------------------------- 1 | Performance 2 | =========== 3 | 4 | pysimdjson is fast, typically tying or beating all other Python JSON libraries 5 | when simply using :func:`simdjson.loads()` or :func:`simdjson.load()`. 6 | 7 | However, 95% of the time spent loading a JSON document into Python is spent in 8 | the creation of Python objects, not the actual parsing of the document. You can 9 | avoid all of this overhead by ignoring parts of the document you don't want. 10 | 11 | pysimdjson also has optimizations for loading homogeneous arrays into tools 12 | like `numpy`_ via :func:`simdjson.Array.as_buffer()`. This is typically at 13 | least 8x faster than other methods. 14 | 15 | Don't load the entire document 16 | ------------------------------ 17 | 18 | pysimdjson supports this in two ways - the use of JSON pointers via 19 | `at_pointer()`, or proxies for objects and lists. 20 | 21 | .. code:: python 22 | 23 | import simdjson 24 | parser = simdjson.Parser() 25 | doc = parser.parse(b'{"res": [{"name": "first"}, {"name": "second"}]}') 26 | 27 | For our sample above, we really just want the second entry in `res`, we 28 | don't care about anything else. We can do this two ways: 29 | 30 | .. code:: python 31 | 32 | assert doc['res'][1]['name'] == 'second' # True 33 | assert doc.at_pointer('/res/1/name') == 'second' # True 34 | 35 | Both of these approaches will be much faster than using `load/s()`, since 36 | they avoid loading the parts of the document we didn't care about. 37 | 38 | Both `Object` and `Array` have a `mini` property that returns their entire 39 | content as a minified Python `str`. A message router for example would only 40 | parse the document and retrieve a single property, the destination, and forward 41 | the payload without ever turning it into a Python object. Here's a (bad) 42 | example: 43 | 44 | .. code:: python 45 | 46 | import simdjson 47 | 48 | @app.route('/store', methods=['POST']) 49 | def store(): 50 | parser = simdjson.Parser() 51 | doc = parser.parse(request.data) 52 | redis.set(doc['key'], doc.mini) 53 | 54 | With this, doc could contain thousands of objects, but the only one loaded 55 | into a python object was `key`, and we even minified the content as we went. 56 | 57 | Re-use the parser 58 | ----------------- 59 | 60 | One of the easiest performance gains if you're working on many documents is 61 | to re-use the parser. 62 | 63 | .. code:: python 64 | 65 | import simdjson 66 | parser = simdjson.Parser() 67 | 68 | for i in range(0, 100): 69 | doc = parser.parse(b'{"a": "b"}') 70 | del doc 71 | 72 | This will drastically reduce the number of allocations being made, as it will 73 | reuse the existing buffer when possible. If it's too small, it'll grow to fit. 74 | 75 | .. _numpy: https://numpy.org/ 76 | -------------------------------------------------------------------------------- /jsonexamples/invalid.json: -------------------------------------------------------------------------------- 1 | { 2 | -------------------------------------------------------------------------------- /jsonexamples/small/adversarial.json: -------------------------------------------------------------------------------- 1 | { 2 | "\"Name rue": [ 3 | [ 116, 4 | "\"", 5 | 234, 6 | "true", 7 | false ] 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /jsonexamples/small/demo.json: -------------------------------------------------------------------------------- 1 | { 2 | "Image": { 3 | "Width": 800, 4 | "Height": 600, 5 | "Title": "View from 15th Floor", 6 | "Thumbnail": { 7 | "Url": "http://www.example.com/image/481989943", 8 | "Height": 125, 9 | "Width": 100 10 | }, 11 | "Animated" : false, 12 | "IDs": [116, 943, 234, 38793] 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /jsonexamples/small/flatadversarial.json: -------------------------------------------------------------------------------- 1 | { "\"Name": [ 116,"\\\"", 234, "true", false ], "t": 1.0e+10} 2 | -------------------------------------------------------------------------------- /jsonexamples/small/repeat.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "jsonrpc": "2.0", 4 | "total": 100, 5 | "result": [ 6 | { 7 | "id": 1, 8 | "name": "Юрий Титов" 9 | }, 10 | { 11 | "id": 2, 12 | "name": "Валерий Васильев" 13 | }, 14 | { 15 | "id": 3, 16 | "name": "Парамон Белов" 17 | }, 18 | { 19 | "id": 4, 20 | "name": "Александр Иванов" 21 | }, 22 | { 23 | "id": 5, 24 | "name": "Дмитрий Фролов" 25 | }, 26 | { 27 | "id": 6, 28 | "name": "Яков Олейник" 29 | }, 30 | { 31 | "id": 7, 32 | "name": "Леонтий Зайцев" 33 | }, 34 | { 35 | "id": 8, 36 | "name": "Олег Егоров" 37 | }, 38 | { 39 | "id": 9, 40 | "name": "Леонтий Зайцев" 41 | }, 42 | { 43 | "id": 10, 44 | "name": "Федор Никитин" 45 | }, 46 | { 47 | "id": 11, 48 | "name": "Александр Иванов" 49 | }, 50 | { 51 | "id": 12, 52 | "name": "Рудольф Логинов" 53 | }, 54 | { 55 | "id": 13, 56 | "name": "Анатолий Бондаренко" 57 | }, 58 | { 59 | "id": 14, 60 | "name": "Константин Павлов" 61 | }, 62 | { 63 | "id": 15, 64 | "name": "Ефим Марченко" 65 | }, 66 | { 67 | "id": 16, 68 | "name": "Николай Макаров" 69 | }, 70 | { 71 | "id": 17, 72 | "name": "Мирослав Фролов" 73 | }, 74 | { 75 | "id": 18, 76 | "name": "Гордей Соколов" 77 | }, 78 | { 79 | "id": 19, 80 | "name": "Арсен Попов" 81 | }, 82 | { 83 | "id": 20, 84 | "name": "Павел Степанов" 85 | }, 86 | { 87 | "id": 21, 88 | "name": "Степан Баранов" 89 | }, 90 | { 91 | "id": 22, 92 | "name": "Захар Новиков" 93 | }, 94 | { 95 | "id": 23, 96 | "name": "Казимир Макаров" 97 | }, 98 | { 99 | "id": 24, 100 | "name": "Оскар Данилов" 101 | }, 102 | { 103 | "id": 25, 104 | "name": "Любомир Денисов" 105 | }, 106 | { 107 | "id": 26, 108 | "name": "Карл Рябов" 109 | }, 110 | { 111 | "id": 27, 112 | "name": "Владимир Смирнов" 113 | }, 114 | { 115 | "id": 28, 116 | "name": "Степан Баранов" 117 | }, 118 | { 119 | "id": 29, 120 | "name": "Карл Рябов" 121 | }, 122 | { 123 | "id": 30, 124 | "name": "Иоан Орлов" 125 | }, 126 | { 127 | "id": 31, 128 | "name": "Максим Степанов" 129 | }, 130 | { 131 | "id": 32, 132 | "name": "Арсений Кузнецов" 133 | }, 134 | { 135 | "id": 33, 136 | "name": "Борис Левченко" 137 | }, 138 | { 139 | "id": 34, 140 | "name": "Захар Новиков" 141 | }, 142 | { 143 | "id": 35, 144 | "name": "Мирослав Фролов" 145 | }, 146 | { 147 | "id": 36, 148 | "name": "Евдоким Демченко" 149 | }, 150 | { 151 | "id": 37, 152 | "name": "Осип Григорьев" 153 | }, 154 | { 155 | "id": 38, 156 | "name": "Станислав Тарасов" 157 | }, 158 | { 159 | "id": 39, 160 | "name": "Вениамин Нестеренко" 161 | }, 162 | { 163 | "id": 40, 164 | "name": "Эдуард Лебедев" 165 | }, 166 | { 167 | "id": 41, 168 | "name": "Гавриил Мельник" 169 | }, 170 | { 171 | "id": 42, 172 | "name": "Мартин Козлов" 173 | }, 174 | { 175 | "id": 43, 176 | "name": "Валентин Шевченко" 177 | }, 178 | { 179 | "id": 44, 180 | "name": "Артем Смирнов" 181 | }, 182 | { 183 | "id": 45, 184 | "name": "Федор Никитин" 185 | }, 186 | { 187 | "id": 46, 188 | "name": "Никита Яковлев" 189 | }, 190 | { 191 | "id": 47, 192 | "name": "Андрей Петров" 193 | }, 194 | { 195 | "id": 48, 196 | "name": "Гарри Морозов" 197 | }, 198 | { 199 | "id": 49, 200 | "name": "Егор Мальцев" 201 | }, 202 | { 203 | "id": 50, 204 | "name": "Иоан Орлов" 205 | }, 206 | { 207 | "id": 51, 208 | "name": "Арсен Попов" 209 | }, 210 | { 211 | "id": 52, 212 | "name": "Казимир Макаров" 213 | }, 214 | { 215 | "id": 53, 216 | "name": "Герман Морозов" 217 | }, 218 | { 219 | "id": 54, 220 | "name": "Тарас Алексеев" 221 | }, 222 | { 223 | "id": 55, 224 | "name": "Семен Козлов" 225 | }, 226 | { 227 | "id": 56, 228 | "name": "Любомир Денисов" 229 | }, 230 | { 231 | "id": 57, 232 | "name": "Даниил Соколов" 233 | }, 234 | { 235 | "id": 58, 236 | "name": "Олег Егоров" 237 | }, 238 | { 239 | "id": 59, 240 | "name": "Леонид Приходько" 241 | }, 242 | { 243 | "id": 60, 244 | "name": "Андрей Петров" 245 | }, 246 | { 247 | "id": 61, 248 | "name": "Георгий Василенко" 249 | }, 250 | { 251 | "id": 62, 252 | "name": "Лазарь Михайлов" 253 | }, 254 | { 255 | "id": 63, 256 | "name": "Станислав Тарасов" 257 | }, 258 | { 259 | "id": 64, 260 | "name": "Денис Данилов" 261 | }, 262 | { 263 | "id": 65, 264 | "name": "Степан Баранов" 265 | }, 266 | { 267 | "id": 66, 268 | "name": "Денис Данилов" 269 | }, 270 | { 271 | "id": 67, 272 | "name": "Станислав Тарасов" 273 | }, 274 | { 275 | "id": 68, 276 | "name": "Аркадий Кравченко" 277 | }, 278 | { 279 | "id": 69, 280 | "name": "Рубен Сорокин" 281 | }, 282 | { 283 | "id": 70, 284 | "name": "Мартын Гусев" 285 | }, 286 | { 287 | "id": 71, 288 | "name": "Федор Никитин" 289 | }, 290 | { 291 | "id": 72, 292 | "name": "Борис Левченко" 293 | }, 294 | { 295 | "id": 73, 296 | "name": "Гарри Морозов" 297 | }, 298 | { 299 | "id": 74, 300 | "name": "Иоан Орлов" 301 | }, 302 | { 303 | "id": 75, 304 | "name": "Максим Степанов" 305 | }, 306 | { 307 | "id": 76, 308 | "name": "Рудольф Логинов" 309 | }, 310 | { 311 | "id": 77, 312 | "name": "Роман Чернов" 313 | }, 314 | { 315 | "id": 78, 316 | "name": "Филипп Литвинов" 317 | }, 318 | { 319 | "id": 79, 320 | "name": "Гордей Соколов" 321 | }, 322 | { 323 | "id": 80, 324 | "name": "Леонтий Зайцев" 325 | }, 326 | { 327 | "id": 81, 328 | "name": "Донат Михайлов" 329 | }, 330 | { 331 | "id": 82, 332 | "name": "Александр Иванов" 333 | }, 334 | { 335 | "id": 83, 336 | "name": "Арсен Попов" 337 | }, 338 | { 339 | "id": 84, 340 | "name": "Валерий Васильев" 341 | }, 342 | { 343 | "id": 85, 344 | "name": "Никита Яковлев" 345 | }, 346 | { 347 | "id": 86, 348 | "name": "Гарри Морозов" 349 | }, 350 | { 351 | "id": 87, 352 | "name": "Любомир Денисов" 353 | }, 354 | { 355 | "id": 88, 356 | "name": "Евгений Новиков" 357 | }, 358 | { 359 | "id": 89, 360 | "name": "Степан Баранов" 361 | }, 362 | { 363 | "id": 90, 364 | "name": "Карл Рябов" 365 | }, 366 | { 367 | "id": 91, 368 | "name": "Владислав Бабич" 369 | }, 370 | { 371 | "id": 92, 372 | "name": "Филипп Литвинов" 373 | }, 374 | { 375 | "id": 93, 376 | "name": "Эдвард Давыдов" 377 | }, 378 | { 379 | "id": 94, 380 | "name": "Арнольд Бойко" 381 | }, 382 | { 383 | "id": 95, 384 | "name": "Оскар Данилов" 385 | }, 386 | { 387 | "id": 96, 388 | "name": "Семен Козлов" 389 | }, 390 | { 391 | "id": 97, 392 | "name": "Тарас Алексеев" 393 | }, 394 | { 395 | "id": 98, 396 | "name": "Людвиг Сергеев" 397 | }, 398 | { 399 | "id": 99, 400 | "name": "Роман Чернов" 401 | }, 402 | { 403 | "id": 100, 404 | "name": "Игнат Волков" 405 | } 406 | ] 407 | } -------------------------------------------------------------------------------- /jsonexamples/small/truenull.json: -------------------------------------------------------------------------------- 1 | [true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null, true, null] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Nicolas Seriot 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_number_double_huge_neg_exp.json: -------------------------------------------------------------------------------- 1 | [123.456e-789] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_number_huge_exp.json: -------------------------------------------------------------------------------- 1 | [0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_number_neg_int_huge_exp.json: -------------------------------------------------------------------------------- 1 | [-1e+9999] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_number_pos_double_huge_exp.json: -------------------------------------------------------------------------------- 1 | [1.5e+9999] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_number_real_neg_overflow.json: -------------------------------------------------------------------------------- 1 | [-123123e100000] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_number_real_pos_overflow.json: -------------------------------------------------------------------------------- 1 | [123123e100000] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_number_real_underflow.json: -------------------------------------------------------------------------------- 1 | [123e-10000000] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_number_too_big_neg_int.json: -------------------------------------------------------------------------------- 1 | [-123123123123123123123123123123] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_number_too_big_pos_int.json: -------------------------------------------------------------------------------- 1 | [100000000000000000000] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_number_very_big_negative_int.json: -------------------------------------------------------------------------------- 1 | [-237462374673276894279832749832423479823246327846] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_object_key_lone_2nd_surrogate.json: -------------------------------------------------------------------------------- 1 | {"\uDFAA":0} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_1st_surrogate_but_2nd_missing.json: -------------------------------------------------------------------------------- 1 | ["\uDADA"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_1st_valid_surrogate_2nd_invalid.json: -------------------------------------------------------------------------------- 1 | ["\uD888\u1234"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_UTF-16LE_with_BOM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/i_string_UTF-16LE_with_BOM.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_UTF-8_invalid_sequence.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/i_string_UTF-8_invalid_sequence.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_UTF8_surrogate_U+D800.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/i_string_UTF8_surrogate_U+D800.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_incomplete_surrogate_and_escape_valid.json: -------------------------------------------------------------------------------- 1 | ["\uD800\n"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_incomplete_surrogate_pair.json: -------------------------------------------------------------------------------- 1 | ["\uDd1ea"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_incomplete_surrogates_escape_valid.json: -------------------------------------------------------------------------------- 1 | ["\uD800\uD800\n"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_invalid_lonely_surrogate.json: -------------------------------------------------------------------------------- 1 | ["\ud800"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_invalid_surrogate.json: -------------------------------------------------------------------------------- 1 | ["\ud800abc"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_invalid_utf-8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/i_string_invalid_utf-8.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_inverted_surrogates_U+1D11E.json: -------------------------------------------------------------------------------- 1 | ["\uDd1e\uD834"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_iso_latin_1.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/i_string_iso_latin_1.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_lone_second_surrogate.json: -------------------------------------------------------------------------------- 1 | ["\uDFAA"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_lone_utf8_continuation_byte.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/i_string_lone_utf8_continuation_byte.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_not_in_unicode_range.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/i_string_not_in_unicode_range.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_overlong_sequence_2_bytes.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/i_string_overlong_sequence_2_bytes.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_overlong_sequence_6_bytes.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/i_string_overlong_sequence_6_bytes.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_overlong_sequence_6_bytes_null.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/i_string_overlong_sequence_6_bytes_null.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_truncated-utf-8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/i_string_truncated-utf-8.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_utf16BE_no_BOM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/i_string_utf16BE_no_BOM.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_string_utf16LE_no_BOM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/i_string_utf16LE_no_BOM.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_structure_500_nested_arrays.json: -------------------------------------------------------------------------------- 1 | [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/i_structure_UTF-8_BOM_empty_object.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_1_true_without_comma.json: -------------------------------------------------------------------------------- 1 | [1 true] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_a_invalid_utf8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/n_array_a_invalid_utf8.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_colon_instead_of_comma.json: -------------------------------------------------------------------------------- 1 | ["": 1] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_comma_after_close.json: -------------------------------------------------------------------------------- 1 | [""], -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_comma_and_number.json: -------------------------------------------------------------------------------- 1 | [,1] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_double_comma.json: -------------------------------------------------------------------------------- 1 | [1,,2] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_double_extra_comma.json: -------------------------------------------------------------------------------- 1 | ["x",,] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_extra_close.json: -------------------------------------------------------------------------------- 1 | ["x"]] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_extra_comma.json: -------------------------------------------------------------------------------- 1 | ["",] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_incomplete.json: -------------------------------------------------------------------------------- 1 | ["x" -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_incomplete_invalid_value.json: -------------------------------------------------------------------------------- 1 | [x -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_inner_array_no_comma.json: -------------------------------------------------------------------------------- 1 | [3[4]] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_invalid_utf8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/n_array_invalid_utf8.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_items_separated_by_semicolon.json: -------------------------------------------------------------------------------- 1 | [1:2] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_just_comma.json: -------------------------------------------------------------------------------- 1 | [,] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_just_minus.json: -------------------------------------------------------------------------------- 1 | [-] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_missing_value.json: -------------------------------------------------------------------------------- 1 | [ , ""] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_newlines_unclosed.json: -------------------------------------------------------------------------------- 1 | ["a", 2 | 4 3 | ,1, -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_number_and_comma.json: -------------------------------------------------------------------------------- 1 | [1,] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_number_and_several_commas.json: -------------------------------------------------------------------------------- 1 | [1,,] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_spaces_vertical_tab_formfeed.json: -------------------------------------------------------------------------------- 1 | [" a"\f] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_star_inside.json: -------------------------------------------------------------------------------- 1 | [*] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_unclosed.json: -------------------------------------------------------------------------------- 1 | ["" -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_unclosed_trailing_comma.json: -------------------------------------------------------------------------------- 1 | [1, -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_unclosed_with_new_lines.json: -------------------------------------------------------------------------------- 1 | [1, 2 | 1 3 | ,1 -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_array_unclosed_with_object_inside.json: -------------------------------------------------------------------------------- 1 | [{} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_incomplete_false.json: -------------------------------------------------------------------------------- 1 | [fals] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_incomplete_null.json: -------------------------------------------------------------------------------- 1 | [nul] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_incomplete_true.json: -------------------------------------------------------------------------------- 1 | [tru] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_multidigit_number_then_00.json: -------------------------------------------------------------------------------- 1 | 123 -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_++.json: -------------------------------------------------------------------------------- 1 | [++1234] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_+1.json: -------------------------------------------------------------------------------- 1 | [+1] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_+Inf.json: -------------------------------------------------------------------------------- 1 | [+Inf] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_-01.json: -------------------------------------------------------------------------------- 1 | [-01] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_-1.0..json: -------------------------------------------------------------------------------- 1 | [-1.0.] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_-2..json: -------------------------------------------------------------------------------- 1 | [-2.] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_-NaN.json: -------------------------------------------------------------------------------- 1 | [-NaN] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_.-1.json: -------------------------------------------------------------------------------- 1 | [.-1] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_.2e-3.json: -------------------------------------------------------------------------------- 1 | [.2e-3] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_0.1.2.json: -------------------------------------------------------------------------------- 1 | [0.1.2] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_0.3e+.json: -------------------------------------------------------------------------------- 1 | [0.3e+] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_0.3e.json: -------------------------------------------------------------------------------- 1 | [0.3e] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_0.e1.json: -------------------------------------------------------------------------------- 1 | [0.e1] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_0_capital_E+.json: -------------------------------------------------------------------------------- 1 | [0E+] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_0_capital_E.json: -------------------------------------------------------------------------------- 1 | [0E] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_0e+.json: -------------------------------------------------------------------------------- 1 | [0e+] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_0e.json: -------------------------------------------------------------------------------- 1 | [0e] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_1.0e+.json: -------------------------------------------------------------------------------- 1 | [1.0e+] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_1.0e-.json: -------------------------------------------------------------------------------- 1 | [1.0e-] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_1.0e.json: -------------------------------------------------------------------------------- 1 | [1.0e] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_1_000.json: -------------------------------------------------------------------------------- 1 | [1 000.0] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_1eE2.json: -------------------------------------------------------------------------------- 1 | [1eE2] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_2.e+3.json: -------------------------------------------------------------------------------- 1 | [2.e+3] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_2.e-3.json: -------------------------------------------------------------------------------- 1 | [2.e-3] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_2.e3.json: -------------------------------------------------------------------------------- 1 | [2.e3] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_9.e+.json: -------------------------------------------------------------------------------- 1 | [9.e+] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_Inf.json: -------------------------------------------------------------------------------- 1 | [Inf] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_NaN.json: -------------------------------------------------------------------------------- 1 | [NaN] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_U+FF11_fullwidth_digit_one.json: -------------------------------------------------------------------------------- 1 | [1] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_expression.json: -------------------------------------------------------------------------------- 1 | [1+2] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_hex_1_digit.json: -------------------------------------------------------------------------------- 1 | [0x1] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_hex_2_digits.json: -------------------------------------------------------------------------------- 1 | [0x42] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_infinity.json: -------------------------------------------------------------------------------- 1 | [Infinity] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_invalid+-.json: -------------------------------------------------------------------------------- 1 | [0e+-1] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_invalid-negative-real.json: -------------------------------------------------------------------------------- 1 | [-123.123foo] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_invalid-utf-8-in-bigger-int.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/n_number_invalid-utf-8-in-bigger-int.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_invalid-utf-8-in-exponent.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/n_number_invalid-utf-8-in-exponent.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_invalid-utf-8-in-int.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/n_number_invalid-utf-8-in-int.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_minus_infinity.json: -------------------------------------------------------------------------------- 1 | [-Infinity] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_minus_sign_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | [-foo] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_minus_space_1.json: -------------------------------------------------------------------------------- 1 | [- 1] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_neg_int_starting_with_zero.json: -------------------------------------------------------------------------------- 1 | [-012] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_neg_real_without_int_part.json: -------------------------------------------------------------------------------- 1 | [-.123] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_neg_with_garbage_at_end.json: -------------------------------------------------------------------------------- 1 | [-1x] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_real_garbage_after_e.json: -------------------------------------------------------------------------------- 1 | [1ea] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_real_with_invalid_utf8_after_e.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/n_number_real_with_invalid_utf8_after_e.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_real_without_fractional_part.json: -------------------------------------------------------------------------------- 1 | [1.] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_starting_with_dot.json: -------------------------------------------------------------------------------- 1 | [.123] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_with_alpha.json: -------------------------------------------------------------------------------- 1 | [1.2a-3] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_with_alpha_char.json: -------------------------------------------------------------------------------- 1 | [1.8011670033376514H-308] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_number_with_leading_zero.json: -------------------------------------------------------------------------------- 1 | [012] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_bad_value.json: -------------------------------------------------------------------------------- 1 | ["x", truth] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_bracket_key.json: -------------------------------------------------------------------------------- 1 | {[: "x"} 2 | -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_comma_instead_of_colon.json: -------------------------------------------------------------------------------- 1 | {"x", null} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_double_colon.json: -------------------------------------------------------------------------------- 1 | {"x"::"b"} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_emoji.json: -------------------------------------------------------------------------------- 1 | {🇨🇭} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_garbage_at_end.json: -------------------------------------------------------------------------------- 1 | {"a":"a" 123} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_key_with_single_quotes.json: -------------------------------------------------------------------------------- 1 | {key: 'value'} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_lone_continuation_byte_in_key_and_trailing_comma.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/n_object_lone_continuation_byte_in_key_and_trailing_comma.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_missing_colon.json: -------------------------------------------------------------------------------- 1 | {"a" b} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_missing_key.json: -------------------------------------------------------------------------------- 1 | {:"b"} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_missing_semicolon.json: -------------------------------------------------------------------------------- 1 | {"a" "b"} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_missing_value.json: -------------------------------------------------------------------------------- 1 | {"a": -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_no-colon.json: -------------------------------------------------------------------------------- 1 | {"a" -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_non_string_key.json: -------------------------------------------------------------------------------- 1 | {1:1} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_non_string_key_but_huge_number_instead.json: -------------------------------------------------------------------------------- 1 | {9999E9999:1} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_repeated_null_null.json: -------------------------------------------------------------------------------- 1 | {null:null,null:null} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_several_trailing_commas.json: -------------------------------------------------------------------------------- 1 | {"id":0,,,,,} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_single_quote.json: -------------------------------------------------------------------------------- 1 | {'a':0} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_trailing_comma.json: -------------------------------------------------------------------------------- 1 | {"id":0,} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_trailing_comment.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}/**/ -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_trailing_comment_open.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}/**// -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_trailing_comment_slash_open.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}// -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_trailing_comment_slash_open_incomplete.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}/ -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_two_commas_in_a_row.json: -------------------------------------------------------------------------------- 1 | {"a":"b",,"c":"d"} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_unquoted_key.json: -------------------------------------------------------------------------------- 1 | {a: "b"} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_unterminated-value.json: -------------------------------------------------------------------------------- 1 | {"a":"a -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_with_single_string.json: -------------------------------------------------------------------------------- 1 | { "foo" : "bar", "a" } -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_object_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}# -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_single_space.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_1_surrogate_then_escape.json: -------------------------------------------------------------------------------- 1 | ["\uD800\"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_1_surrogate_then_escape_u.json: -------------------------------------------------------------------------------- 1 | ["\uD800\u"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_1_surrogate_then_escape_u1.json: -------------------------------------------------------------------------------- 1 | ["\uD800\u1"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_1_surrogate_then_escape_u1x.json: -------------------------------------------------------------------------------- 1 | ["\uD800\u1x"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_accentuated_char_no_quotes.json: -------------------------------------------------------------------------------- 1 | [é] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_backslash_00.json: -------------------------------------------------------------------------------- 1 | ["\"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_escape_x.json: -------------------------------------------------------------------------------- 1 | ["\x00"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_escaped_backslash_bad.json: -------------------------------------------------------------------------------- 1 | ["\\\"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_escaped_ctrl_char_tab.json: -------------------------------------------------------------------------------- 1 | ["\ "] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_escaped_emoji.json: -------------------------------------------------------------------------------- 1 | ["\🌀"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_incomplete_escape.json: -------------------------------------------------------------------------------- 1 | ["\"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_incomplete_escaped_character.json: -------------------------------------------------------------------------------- 1 | ["\u00A"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_incomplete_surrogate.json: -------------------------------------------------------------------------------- 1 | ["\uD834\uDd"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_incomplete_surrogate_escape_invalid.json: -------------------------------------------------------------------------------- 1 | ["\uD800\uD800\x"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_invalid-utf-8-in-escape.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/n_string_invalid-utf-8-in-escape.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_invalid_backslash_esc.json: -------------------------------------------------------------------------------- 1 | ["\a"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_invalid_unicode_escape.json: -------------------------------------------------------------------------------- 1 | ["\uqqqq"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_invalid_utf8_after_escape.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/n_string_invalid_utf8_after_escape.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_leading_uescaped_thinspace.json: -------------------------------------------------------------------------------- 1 | [\u0020"asd"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_no_quotes_with_bad_escape.json: -------------------------------------------------------------------------------- 1 | [\n] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_single_doublequote.json: -------------------------------------------------------------------------------- 1 | " -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_single_quote.json: -------------------------------------------------------------------------------- 1 | ['single quote'] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_single_string_no_double_quotes.json: -------------------------------------------------------------------------------- 1 | abc -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_start_escape_unclosed.json: -------------------------------------------------------------------------------- 1 | ["\ -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_unescaped_crtl_char.json: -------------------------------------------------------------------------------- 1 | ["aa"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_unescaped_newline.json: -------------------------------------------------------------------------------- 1 | ["new 2 | line"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_unescaped_tab.json: -------------------------------------------------------------------------------- 1 | [" "] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_unicode_CapitalU.json: -------------------------------------------------------------------------------- 1 | "\UA66D" -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_string_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | ""x -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_U+2060_word_joined.json: -------------------------------------------------------------------------------- 1 | [⁠] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_UTF8_BOM_no_data.json: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_angle_bracket_..json: -------------------------------------------------------------------------------- 1 | <.> -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_angle_bracket_null.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_array_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | [1]x -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_array_with_extra_array_close.json: -------------------------------------------------------------------------------- 1 | [1]] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_array_with_unclosed_string.json: -------------------------------------------------------------------------------- 1 | ["asd] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_ascii-unicode-identifier.json: -------------------------------------------------------------------------------- 1 | aå -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_capitalized_True.json: -------------------------------------------------------------------------------- 1 | [True] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_close_unopened_array.json: -------------------------------------------------------------------------------- 1 | 1] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_comma_instead_of_closing_brace.json: -------------------------------------------------------------------------------- 1 | {"x": true, -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_double_array.json: -------------------------------------------------------------------------------- 1 | [][] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_end_array.json: -------------------------------------------------------------------------------- 1 | ] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_incomplete_UTF8_BOM.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/n_structure_incomplete_UTF8_BOM.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_lone-invalid-utf-8.json: -------------------------------------------------------------------------------- 1 | � -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_lone-open-bracket.json: -------------------------------------------------------------------------------- 1 | [ -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_no_data.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_parsing/n_structure_no_data.json -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_null-byte-outside-string.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_number_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | 2@ -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_object_followed_by_closing_object.json: -------------------------------------------------------------------------------- 1 | {}} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_object_unclosed_no_value.json: -------------------------------------------------------------------------------- 1 | {"": -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_object_with_comment.json: -------------------------------------------------------------------------------- 1 | {"a":/*comment*/"b"} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_object_with_trailing_garbage.json: -------------------------------------------------------------------------------- 1 | {"a": true} "x" -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_open_array_apostrophe.json: -------------------------------------------------------------------------------- 1 | [' -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_open_array_comma.json: -------------------------------------------------------------------------------- 1 | [, -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_open_array_open_object.json: -------------------------------------------------------------------------------- 1 | [{ -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_open_array_open_string.json: -------------------------------------------------------------------------------- 1 | ["a -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_open_array_string.json: -------------------------------------------------------------------------------- 1 | ["a" -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_open_object.json: -------------------------------------------------------------------------------- 1 | { -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_open_object_close_array.json: -------------------------------------------------------------------------------- 1 | {] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_open_object_comma.json: -------------------------------------------------------------------------------- 1 | {, -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_open_object_open_array.json: -------------------------------------------------------------------------------- 1 | {[ -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_open_object_open_string.json: -------------------------------------------------------------------------------- 1 | {"a -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_open_object_string_with_apostrophes.json: -------------------------------------------------------------------------------- 1 | {'a' -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_open_open.json: -------------------------------------------------------------------------------- 1 | ["\{["\{["\{["\{ -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_single_eacute.json: -------------------------------------------------------------------------------- 1 | � -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_single_star.json: -------------------------------------------------------------------------------- 1 | * -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_trailing_#.json: -------------------------------------------------------------------------------- 1 | {"a":"b"}#{} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_uescaped_LF_before_string.json: -------------------------------------------------------------------------------- 1 | [\u000A""] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_unclosed_array.json: -------------------------------------------------------------------------------- 1 | [1 -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_unclosed_array_partial_null.json: -------------------------------------------------------------------------------- 1 | [ false, nul -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_unclosed_array_unfinished_false.json: -------------------------------------------------------------------------------- 1 | [ true, fals -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_unclosed_array_unfinished_true.json: -------------------------------------------------------------------------------- 1 | [ false, tru -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_unclosed_object.json: -------------------------------------------------------------------------------- 1 | {"asd":"asd" -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_unicode-identifier.json: -------------------------------------------------------------------------------- 1 | å -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_whitespace_U+2060_word_joiner.json: -------------------------------------------------------------------------------- 1 | [⁠] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/n_structure_whitespace_formfeed.json: -------------------------------------------------------------------------------- 1 | [ ] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_array_arraysWithSpaces.json: -------------------------------------------------------------------------------- 1 | [[] ] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_array_empty-string.json: -------------------------------------------------------------------------------- 1 | [""] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_array_empty.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_array_ending_with_newline.json: -------------------------------------------------------------------------------- 1 | ["a"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_array_false.json: -------------------------------------------------------------------------------- 1 | [false] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_array_heterogeneous.json: -------------------------------------------------------------------------------- 1 | [null, 1, "1", {}] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_array_null.json: -------------------------------------------------------------------------------- 1 | [null] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_array_with_1_and_newline.json: -------------------------------------------------------------------------------- 1 | [1 2 | ] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_array_with_leading_space.json: -------------------------------------------------------------------------------- 1 | [1] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_array_with_several_null.json: -------------------------------------------------------------------------------- 1 | [1,null,null,null,2] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_array_with_trailing_space.json: -------------------------------------------------------------------------------- 1 | [2] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_number.json: -------------------------------------------------------------------------------- 1 | [123e65] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_number_0e+1.json: -------------------------------------------------------------------------------- 1 | [0e+1] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_number_0e1.json: -------------------------------------------------------------------------------- 1 | [0e1] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_number_after_space.json: -------------------------------------------------------------------------------- 1 | [ 4] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_number_double_close_to_zero.json: -------------------------------------------------------------------------------- 1 | [-0.000000000000000000000000000000000000000000000000000000000000000000000000000001] 2 | -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_number_int_with_exp.json: -------------------------------------------------------------------------------- 1 | [20e1] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_number_minus_zero.json: -------------------------------------------------------------------------------- 1 | [-0] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_number_negative_int.json: -------------------------------------------------------------------------------- 1 | [-123] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_number_negative_one.json: -------------------------------------------------------------------------------- 1 | [-1] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_number_negative_zero.json: -------------------------------------------------------------------------------- 1 | [-0] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_number_real_capital_e.json: -------------------------------------------------------------------------------- 1 | [1E22] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_number_real_capital_e_neg_exp.json: -------------------------------------------------------------------------------- 1 | [1E-2] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_number_real_capital_e_pos_exp.json: -------------------------------------------------------------------------------- 1 | [1E+2] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_number_real_exponent.json: -------------------------------------------------------------------------------- 1 | [123e45] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_number_real_fraction_exponent.json: -------------------------------------------------------------------------------- 1 | [123.456e78] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_number_real_neg_exp.json: -------------------------------------------------------------------------------- 1 | [1e-2] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_number_real_pos_exponent.json: -------------------------------------------------------------------------------- 1 | [1e+2] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_number_simple_int.json: -------------------------------------------------------------------------------- 1 | [123] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_number_simple_real.json: -------------------------------------------------------------------------------- 1 | [123.456789] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_object.json: -------------------------------------------------------------------------------- 1 | {"asd":"sdf", "dfg":"fgh"} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_object_basic.json: -------------------------------------------------------------------------------- 1 | {"asd":"sdf"} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_object_duplicated_key.json: -------------------------------------------------------------------------------- 1 | {"a":"b","a":"c"} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_object_duplicated_key_and_value.json: -------------------------------------------------------------------------------- 1 | {"a":"b","a":"b"} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_object_empty.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_object_empty_key.json: -------------------------------------------------------------------------------- 1 | {"":0} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_object_escaped_null_in_key.json: -------------------------------------------------------------------------------- 1 | {"foo\u0000bar": 42} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_object_extreme_numbers.json: -------------------------------------------------------------------------------- 1 | { "min": -1.0e+28, "max": 1.0e+28 } -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_object_long_strings.json: -------------------------------------------------------------------------------- 1 | {"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_object_simple.json: -------------------------------------------------------------------------------- 1 | {"a":[]} -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_object_string_unicode.json: -------------------------------------------------------------------------------- 1 | {"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" } -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_object_with_newlines.json: -------------------------------------------------------------------------------- 1 | { 2 | "a": "b" 3 | } -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_1_2_3_bytes_UTF-8_sequences.json: -------------------------------------------------------------------------------- 1 | ["\u0060\u012a\u12AB"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_accepted_surrogate_pair.json: -------------------------------------------------------------------------------- 1 | ["\uD801\udc37"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_accepted_surrogate_pairs.json: -------------------------------------------------------------------------------- 1 | ["\ud83d\ude39\ud83d\udc8d"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_allowed_escapes.json: -------------------------------------------------------------------------------- 1 | ["\"\\\/\b\f\n\r\t"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_backslash_and_u_escaped_zero.json: -------------------------------------------------------------------------------- 1 | ["\\u0000"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_backslash_doublequotes.json: -------------------------------------------------------------------------------- 1 | ["\""] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_comments.json: -------------------------------------------------------------------------------- 1 | ["a/*b*/c/*d//e"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_double_escape_a.json: -------------------------------------------------------------------------------- 1 | ["\\a"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_double_escape_n.json: -------------------------------------------------------------------------------- 1 | ["\\n"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_escaped_control_character.json: -------------------------------------------------------------------------------- 1 | ["\u0012"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_escaped_noncharacter.json: -------------------------------------------------------------------------------- 1 | ["\uFFFF"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_in_array.json: -------------------------------------------------------------------------------- 1 | ["asd"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_in_array_with_leading_space.json: -------------------------------------------------------------------------------- 1 | [ "asd"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_last_surrogates_1_and_2.json: -------------------------------------------------------------------------------- 1 | ["\uDBFF\uDFFF"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_nbsp_uescaped.json: -------------------------------------------------------------------------------- 1 | ["new\u00A0line"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_nonCharacterInUTF-8_U+10FFFF.json: -------------------------------------------------------------------------------- 1 | ["􏿿"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_nonCharacterInUTF-8_U+FFFF.json: -------------------------------------------------------------------------------- 1 | ["￿"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_null_escape.json: -------------------------------------------------------------------------------- 1 | ["\u0000"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_one-byte-utf-8.json: -------------------------------------------------------------------------------- 1 | ["\u002c"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_pi.json: -------------------------------------------------------------------------------- 1 | ["π"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_reservedCharacterInUTF-8_U+1BFFF.json: -------------------------------------------------------------------------------- 1 | ["𛿿"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_simple_ascii.json: -------------------------------------------------------------------------------- 1 | ["asd "] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_space.json: -------------------------------------------------------------------------------- 1 | " " -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json: -------------------------------------------------------------------------------- 1 | ["\uD834\uDd1e"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_three-byte-utf-8.json: -------------------------------------------------------------------------------- 1 | ["\u0821"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_two-byte-utf-8.json: -------------------------------------------------------------------------------- 1 | ["\u0123"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_u+2028_line_sep.json: -------------------------------------------------------------------------------- 1 | ["
"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_u+2029_par_sep.json: -------------------------------------------------------------------------------- 1 | ["
"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_uEscape.json: -------------------------------------------------------------------------------- 1 | ["\u0061\u30af\u30EA\u30b9"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_uescaped_newline.json: -------------------------------------------------------------------------------- 1 | ["new\u000Aline"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_unescaped_char_delete.json: -------------------------------------------------------------------------------- 1 | [""] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_unicode.json: -------------------------------------------------------------------------------- 1 | ["\uA66D"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_unicodeEscapedBackslash.json: -------------------------------------------------------------------------------- 1 | ["\u005C"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_unicode_2.json: -------------------------------------------------------------------------------- 1 | ["⍂㈴⍂"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_unicode_U+10FFFE_nonchar.json: -------------------------------------------------------------------------------- 1 | ["\uDBFF\uDFFE"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_unicode_U+1FFFE_nonchar.json: -------------------------------------------------------------------------------- 1 | ["\uD83F\uDFFE"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json: -------------------------------------------------------------------------------- 1 | ["\u200B"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_unicode_U+2064_invisible_plus.json: -------------------------------------------------------------------------------- 1 | ["\u2064"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_unicode_U+FDD0_nonchar.json: -------------------------------------------------------------------------------- 1 | ["\uFDD0"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_unicode_U+FFFE_nonchar.json: -------------------------------------------------------------------------------- 1 | ["\uFFFE"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_unicode_escaped_double_quote.json: -------------------------------------------------------------------------------- 1 | ["\u0022"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_utf8.json: -------------------------------------------------------------------------------- 1 | ["€𝄞"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_string_with_del_character.json: -------------------------------------------------------------------------------- 1 | ["aa"] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_structure_lonely_false.json: -------------------------------------------------------------------------------- 1 | false -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_structure_lonely_int.json: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_structure_lonely_negative_real.json: -------------------------------------------------------------------------------- 1 | -0.1 -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_structure_lonely_null.json: -------------------------------------------------------------------------------- 1 | null -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_structure_lonely_string.json: -------------------------------------------------------------------------------- 1 | "asd" -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_structure_lonely_true.json: -------------------------------------------------------------------------------- 1 | true -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_structure_string_empty.json: -------------------------------------------------------------------------------- 1 | "" -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_structure_trailing_newline.json: -------------------------------------------------------------------------------- 1 | ["a"] 2 | -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_structure_true_in_array.json: -------------------------------------------------------------------------------- 1 | [true] -------------------------------------------------------------------------------- /jsonexamples/test_parsing/y_structure_whitespace_array.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /jsonexamples/test_transform/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Nicolas Seriot 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /jsonexamples/test_transform/number_-9223372036854775808.json: -------------------------------------------------------------------------------- 1 | [-9223372036854775808] 2 | -------------------------------------------------------------------------------- /jsonexamples/test_transform/number_-9223372036854775809.json: -------------------------------------------------------------------------------- 1 | [-9223372036854775809] 2 | -------------------------------------------------------------------------------- /jsonexamples/test_transform/number_1.0.json: -------------------------------------------------------------------------------- 1 | [1.0] 2 | -------------------------------------------------------------------------------- /jsonexamples/test_transform/number_1.000000000000000005.json: -------------------------------------------------------------------------------- 1 | [1.000000000000000005] 2 | -------------------------------------------------------------------------------- /jsonexamples/test_transform/number_1000000000000000.json: -------------------------------------------------------------------------------- 1 | [1000000000000000] 2 | -------------------------------------------------------------------------------- /jsonexamples/test_transform/number_10000000000000000999.json: -------------------------------------------------------------------------------- 1 | [10000000000000000999] 2 | -------------------------------------------------------------------------------- /jsonexamples/test_transform/number_1e-999.json: -------------------------------------------------------------------------------- 1 | [1E-999] 2 | -------------------------------------------------------------------------------- /jsonexamples/test_transform/number_1e6.json: -------------------------------------------------------------------------------- 1 | [1E6] 2 | -------------------------------------------------------------------------------- /jsonexamples/test_transform/number_9223372036854775807.json: -------------------------------------------------------------------------------- 1 | [9223372036854775807] 2 | -------------------------------------------------------------------------------- /jsonexamples/test_transform/number_9223372036854775808.json: -------------------------------------------------------------------------------- 1 | [9223372036854775808] 2 | -------------------------------------------------------------------------------- /jsonexamples/test_transform/object_key_nfc_nfd.json: -------------------------------------------------------------------------------- 1 | {"é":"NFC","é":"NFD"} -------------------------------------------------------------------------------- /jsonexamples/test_transform/object_key_nfd_nfc.json: -------------------------------------------------------------------------------- 1 | {"é":"NFD","é":"NFC"} -------------------------------------------------------------------------------- /jsonexamples/test_transform/object_same_key_different_values.json: -------------------------------------------------------------------------------- 1 | {"a":1,"a":2} -------------------------------------------------------------------------------- /jsonexamples/test_transform/object_same_key_same_value.json: -------------------------------------------------------------------------------- 1 | {"a":1,"a":1} -------------------------------------------------------------------------------- /jsonexamples/test_transform/object_same_key_unclear_values.json: -------------------------------------------------------------------------------- 1 | {"a":0, "a":-0} 2 | -------------------------------------------------------------------------------- /jsonexamples/test_transform/string_1_escaped_invalid_codepoint.json: -------------------------------------------------------------------------------- 1 | ["\uD800"] -------------------------------------------------------------------------------- /jsonexamples/test_transform/string_1_invalid_codepoint.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_transform/string_1_invalid_codepoint.json -------------------------------------------------------------------------------- /jsonexamples/test_transform/string_2_escaped_invalid_codepoints.json: -------------------------------------------------------------------------------- 1 | ["\uD800\uD800"] -------------------------------------------------------------------------------- /jsonexamples/test_transform/string_2_invalid_codepoints.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_transform/string_2_invalid_codepoints.json -------------------------------------------------------------------------------- /jsonexamples/test_transform/string_3_escaped_invalid_codepoints.json: -------------------------------------------------------------------------------- 1 | ["\uD800\uD800\uD800"] -------------------------------------------------------------------------------- /jsonexamples/test_transform/string_3_invalid_codepoints.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TkTech/pysimdjson/0fcd806a4aabbf382b768b5ebd8c4b0e532662e6/jsonexamples/test_transform/string_3_invalid_codepoints.json -------------------------------------------------------------------------------- /jsonexamples/test_transform/string_with_escaped_NULL.json: -------------------------------------------------------------------------------- 1 | ["A\u0000B"] -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=74.1", "Cython"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "pysimdjson" 7 | version = "7.0.1" 8 | description = "Add your description here" 9 | readme = "README.md" 10 | requires-python = ">=3.9" 11 | dependencies = [ 12 | "pysimdjson", 13 | ] 14 | 15 | [tool.uv.sources] 16 | pysimdjson = { workspace = true } 17 | 18 | [tool.setuptools] 19 | ext-modules = [ 20 | { name = "csimdjson", sources = ["simdjson/simdjson.cpp", "simdjson/util.cpp", "simdjson/csimdjson.pyx"], py-limited-api = true }, 21 | ] 22 | 23 | [tool.setuptools.packages.find] 24 | include = ["simdjson"] 25 | 26 | [dependency-groups] 27 | dev = [ 28 | "build>=1.2.2.post1", 29 | "bumpversion>=0.6.0", 30 | "coverage>=7.6.12", 31 | "furo>=2024.8.6", 32 | "ghp-import>=2.1.0", 33 | "numpy>=2.0.2", 34 | "pytest>=8.3.4", 35 | "pytest-benchmark>=5.1.0", 36 | "sphinx>=7.4.7", 37 | ] 38 | 39 | 40 | [tool.cibuildwheel] 41 | before-test = "pip install pytest pytest-benchmark" 42 | test-command = "pytest {project}/tests" 43 | test-skip = "*_arm64 *_universal2:arm64" 44 | # This should be part of ext-modules but is blocked by setuptools issue #4810. 45 | environment = { CPPFLAGS="-DSIMDJSON_IMPLEMENTATION_FALLBACK=1" } 46 | 47 | [tool.cibuildwheel.linux] 48 | archs = ["auto", "aarch64", "ppc64le"] 49 | 50 | [tool.cibuildwheel.macos] 51 | environment = { CXXFLAGS="-std=c++11" } 52 | archs = ["x86_64", "universal2"] -------------------------------------------------------------------------------- /scripts/coverage.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is a backport and modernization of Cython's coverage.py support from the 3 | 3.* branch to the stable 0.29.* branch. 4 | 5 | Most importantly for us, it includes support for coverage.py's `exclude_lines` 6 | configuration option, allowing us to filter things like MemoryError from the 7 | coverage reports. 8 | 9 | It is standalone, and does not require Cython itself. 10 | 11 | The complete license for this file can be found at: 12 | 13 | https://github.com/cython/cython/blob/0.29.22/LICENSE.txt 14 | 15 | Changelog 16 | --------- 17 | 18 | 1.0.0 19 | ^^^^^ 20 | - Support for excluded_lines 21 | - Fixed inconsistent quotations, PEP8'd. 22 | """ 23 | import io 24 | import re 25 | import os.path 26 | import sys 27 | from collections import defaultdict 28 | 29 | from coverage.plugin import CoveragePlugin, FileTracer, FileReporter 30 | from coverage.files import canonical_filename 31 | 32 | 33 | C_FILE_EXTENSIONS = {'.c', '.cpp', '.cc', '.cxx'} 34 | MODULE_FILE_EXTENSIONS = {'.py', '.pyx', '.pxd'} | C_FILE_EXTENSIONS 35 | 36 | 37 | def is_package_dir(dir_path): 38 | for filename in ('__init__.py', 39 | '__init__.pyc', 40 | '__init__.pyx', 41 | '__init__.pxd'): 42 | path = os.path.join(dir_path, filename) 43 | if path_exists(path): 44 | return 1 45 | 46 | 47 | _match_file_encoding = re.compile(br'(\w*coding)[:=]\s*([-\w.]+)').search 48 | 49 | 50 | def detect_opened_file_encoding(f): 51 | # PEPs 263 and 3120 52 | # Most of the time the first two lines fall in the first couple of hundred 53 | # chars, and this bulk read/split is much faster. 54 | lines = () 55 | start = b'' 56 | while len(lines) < 3: 57 | data = f.read(500) 58 | start += data 59 | lines = start.split(b'\n') 60 | if not data: 61 | break 62 | m = _match_file_encoding(lines[0]) 63 | if m and m.group(1) != b'c_string_encoding': 64 | return m.group(2).decode('iso8859-1') 65 | elif len(lines) > 1: 66 | m = _match_file_encoding(lines[1]) 67 | if m: 68 | return m.group(2).decode('iso8859-1') 69 | return 'UTF-8' 70 | 71 | 72 | def path_exists(path): 73 | # try on the filesystem first 74 | if os.path.exists(path): 75 | return True 76 | # figure out if a PEP 302 loader is around 77 | try: 78 | loader = __loader__ 79 | # XXX the code below assumes a 'zipimport.zipimporter' instance 80 | # XXX should be easy to generalize, but too lazy right now to write it 81 | archive_path = getattr(loader, 'archive', None) 82 | if archive_path: 83 | normpath = os.path.normpath(path) 84 | if normpath.startswith(archive_path): 85 | arcname = normpath[len(archive_path)+1:] 86 | try: 87 | loader.get_data(arcname) 88 | return True 89 | except IOError: 90 | return False 91 | except NameError: 92 | pass 93 | return False 94 | 95 | 96 | def find_root_package_dir(file_path): 97 | dir = os.path.dirname(file_path) 98 | if file_path == dir: 99 | return dir 100 | elif is_package_dir(dir): 101 | return find_root_package_dir(dir) 102 | else: 103 | return dir 104 | 105 | 106 | def open_source_file(source_filename, encoding=None, error_handling=None): 107 | stream = None 108 | try: 109 | if encoding is None: 110 | # Most of the time the encoding is not specified, so try hard to 111 | # open the file only once. 112 | f = io.open(source_filename, 'rb') 113 | encoding = detect_opened_file_encoding(f) 114 | f.seek(0) 115 | stream = io.TextIOWrapper( 116 | f, 117 | encoding=encoding, 118 | errors=error_handling 119 | ) 120 | else: 121 | stream = io.open( 122 | source_filename, 123 | encoding=encoding, 124 | errors=error_handling 125 | ) 126 | 127 | except OSError: 128 | if os.path.exists(source_filename): 129 | raise # File is there, but something went wrong reading from it. 130 | # Allow source files to be in zip files etc. 131 | try: 132 | loader = __loader__ 133 | if source_filename.startswith(loader.archive): 134 | stream = open_source_from_loader( 135 | loader, source_filename, 136 | encoding, error_handling) 137 | except (NameError, AttributeError): 138 | pass 139 | 140 | if stream is None: 141 | raise FileNotFoundError(source_filename) 142 | 143 | if stream.read(1) != u'\uFEFF': 144 | stream.seek(0) 145 | 146 | return stream 147 | 148 | 149 | def _find_c_source(base_path): 150 | file_exists = os.path.exists 151 | for ext in C_FILE_EXTENSIONS: 152 | file_name = base_path + ext 153 | if file_exists(file_name): 154 | return file_name 155 | return None 156 | 157 | 158 | def _find_dep_file_path(main_file, file_path, relative_path_search=False): 159 | abs_path = os.path.abspath(file_path) 160 | if not os.path.exists(abs_path) and (file_path.endswith('.pxi') or 161 | relative_path_search): 162 | # files are looked up relative to the main source file 163 | rel_file_path = os.path.join(os.path.dirname(main_file), file_path) 164 | if os.path.exists(rel_file_path): 165 | abs_path = os.path.abspath(rel_file_path) 166 | 167 | # search sys.path for external locations if a valid file hasn't been found 168 | if not os.path.exists(abs_path): 169 | for sys_path in sys.path: 170 | test_path = os.path.realpath(os.path.join(sys_path, file_path)) 171 | if os.path.exists(test_path): 172 | return canonical_filename(test_path) 173 | 174 | return canonical_filename(abs_path) 175 | 176 | 177 | class Plugin(CoveragePlugin): 178 | # map from traced file paths to absolute file paths 179 | _file_path_map = None 180 | # map from traced file paths to corresponding C files 181 | _c_files_map = None 182 | # map from parsed C files to their content 183 | _parsed_c_files = None 184 | # map from traced files to lines that are excluded from coverage 185 | _excluded_lines_map = None 186 | # list of regex patterns for lines to exclude 187 | _excluded_line_patterns = () 188 | 189 | def sys_info(self): 190 | return [] 191 | 192 | def configure(self, config): 193 | # Entry point for coverage "configurer". 194 | # Read the regular expressions from the coverage config that match 195 | # lines to be excluded from coverage. 196 | self._excluded_line_patterns = config.get_option( 197 | 'report:exclude_lines' 198 | ) 199 | 200 | def file_tracer(self, filename): 201 | """ 202 | Try to find a C source file for a file path found by the tracer. 203 | """ 204 | if filename.startswith('<') or filename.startswith('memory:'): 205 | return None 206 | c_file = py_file = None 207 | filename = canonical_filename(os.path.abspath(filename)) 208 | if self._c_files_map and filename in self._c_files_map: 209 | c_file = self._c_files_map[filename][0] 210 | 211 | if c_file is None: 212 | c_file, py_file = self._find_source_files(filename) 213 | if not c_file: 214 | return None # unknown file 215 | 216 | # parse all source file paths and lines from C file 217 | # to learn about all relevant source files right away (pyx/pxi/pxd) 218 | # FIXME: this might already be too late if the first executed line 219 | # is not from the main .pyx file but a file with a different 220 | # name than the .c file (which prevents us from finding the 221 | # .c file) 222 | _, code = self._read_source_lines(c_file, filename) 223 | if code is None: 224 | return None # no source found 225 | 226 | if self._file_path_map is None: 227 | self._file_path_map = {} 228 | 229 | return CythonModuleTracer( 230 | filename, 231 | py_file, 232 | c_file, 233 | self._c_files_map, 234 | self._file_path_map 235 | ) 236 | 237 | def file_reporter(self, filename): 238 | # TODO: let coverage.py handle .py files itself 239 | # ext = os.path.splitext(filename)[1].lower() 240 | # if ext == '.py': 241 | # from coverage.python import PythonFileReporter 242 | # return PythonFileReporter(filename) 243 | 244 | filename = canonical_filename(os.path.abspath(filename)) 245 | if self._c_files_map and filename in self._c_files_map: 246 | c_file, rel_file_path, code = self._c_files_map[filename] 247 | else: 248 | c_file, _ = self._find_source_files(filename) 249 | if not c_file: 250 | return None # unknown file 251 | 252 | rel_file_path, code = self._read_source_lines(c_file, filename) 253 | if code is None: 254 | return None # no source found 255 | 256 | return CythonModuleReporter( 257 | c_file, 258 | filename, 259 | rel_file_path, 260 | code, 261 | self._excluded_lines_map.get(rel_file_path, frozenset()) 262 | ) 263 | 264 | def _find_source_files(self, filename): 265 | basename, ext = os.path.splitext(filename) 266 | ext = ext.lower() 267 | if ext in MODULE_FILE_EXTENSIONS: 268 | pass 269 | elif ext == '.pyd': 270 | # Windows extension module 271 | platform_suffix = re.search( 272 | r'[.]cp[0-9]+-win[_a-z0-9]*$', 273 | basename, 274 | re.I 275 | ) 276 | 277 | if platform_suffix: 278 | basename = basename[:platform_suffix.start()] 279 | elif ext == '.so': 280 | # Linux/Unix/Mac extension module 281 | platform_suffix = re.search( 282 | r'[.](?:cpython|pypy)-[0-9]+[-_a-z0-9]*$', 283 | basename, 284 | re.I 285 | ) 286 | 287 | if platform_suffix: 288 | basename = basename[:platform_suffix.start()] 289 | elif ext == '.pxi': 290 | # if we get here, it means that the first traced line of a Cython 291 | # module was not in the main module but in an include file, so try 292 | # a little harder to find the main source file 293 | self._find_c_source_files(os.path.dirname(filename), filename) 294 | if filename in self._c_files_map: 295 | return self._c_files_map[filename][0], None 296 | else: 297 | # none of our business 298 | return None, None 299 | 300 | if ext in C_FILE_EXTENSIONS: 301 | c_file = filename 302 | else: 303 | c_file = _find_c_source(basename) 304 | 305 | if c_file is None: 306 | # a module "pkg/mod.so" can have a source file "pkg/pkg.mod.c" 307 | package_root = find_root_package_dir(filename) 308 | package_path = os.path.relpath( 309 | basename, 310 | package_root 311 | ).split(os.path.sep) 312 | 313 | if len(package_path) > 1: 314 | test_basepath = os.path.join( 315 | os.path.dirname(filename), 316 | '.'.join(package_path) 317 | ) 318 | c_file = _find_c_source(test_basepath) 319 | 320 | py_source_file = None 321 | if c_file: 322 | py_source_file = os.path.splitext(c_file)[0] + '.py' 323 | if not os.path.exists(py_source_file): 324 | py_source_file = None 325 | 326 | try: 327 | with open(c_file, 'rb') as f: 328 | if b'/* Generated by Cython ' not in f.read(30): 329 | return None, None # not a Cython file 330 | except (IOError, OSError): 331 | c_file = None 332 | 333 | return c_file, py_source_file 334 | 335 | def _find_c_source_files(self, dir_path, source_file): 336 | """ 337 | Desperately parse all C files in the directory or its package parents 338 | (not re-descending) to find the (included) source file in one of them. 339 | """ 340 | if not os.path.isdir(dir_path): 341 | return 342 | 343 | splitext = os.path.splitext 344 | for filename in os.listdir(dir_path): 345 | ext = splitext(filename)[1].lower() 346 | if ext in C_FILE_EXTENSIONS: 347 | self._read_source_lines( 348 | os.path.join(dir_path, filename), 349 | source_file 350 | ) 351 | if source_file in self._c_files_map: 352 | return 353 | 354 | # not found? then try one package up 355 | if is_package_dir(dir_path): 356 | self._find_c_source_files(os.path.dirname(dir_path), source_file) 357 | 358 | def _read_source_lines(self, c_file, sourcefile): 359 | """ 360 | Parse a Cython generated C/C++ source file and find the executable 361 | lines. Each executable line starts with a comment header that states 362 | source file and line number, as well as the surrounding range of source 363 | code lines. 364 | """ 365 | if self._parsed_c_files is None: 366 | self._parsed_c_files = {} 367 | if c_file in self._parsed_c_files: 368 | code_lines = self._parsed_c_files[c_file] 369 | else: 370 | code_lines = self._parse_cfile_lines(c_file) 371 | self._parsed_c_files[c_file] = code_lines 372 | 373 | if self._c_files_map is None: 374 | self._c_files_map = {} 375 | 376 | for filename, code in code_lines.items(): 377 | abs_path = _find_dep_file_path(c_file, filename, 378 | relative_path_search=True) 379 | self._c_files_map[abs_path] = (c_file, filename, code) 380 | 381 | if sourcefile not in self._c_files_map: 382 | return (None,) * 2 # e.g. shared library file 383 | return self._c_files_map[sourcefile][1:] 384 | 385 | def _parse_cfile_lines(self, c_file): 386 | """ 387 | Parse a C file and extract all source file lines that generated 388 | executable code. 389 | """ 390 | match_source_path_line = re.compile(r' */[*] +"(.*)":([0-9]+)$').match 391 | match_current_code_line = re.compile(r' *[*] (.*) # <<<<<<+$').match 392 | match_comment_end = re.compile(r' *[*]/$').match 393 | match_trace_line = re.compile(r' *__Pyx_TraceLine\(([0-9]+),').match 394 | not_executable = re.compile( 395 | r'\s*c(?:type)?def\s+' 396 | r'(?:(?:public|external)\s+)?' 397 | r'(?:struct|union|enum|class)' 398 | r'(\s+[^:]+|)\s*:' 399 | ).match 400 | 401 | line_is_excluded = None 402 | if self._excluded_line_patterns: 403 | line_is_excluded = re.compile( 404 | '|'.join([ 405 | '(?:{0})'.format(regex) 406 | for regex in self._excluded_line_patterns 407 | ]) 408 | ).search 409 | 410 | code_lines = defaultdict(dict) 411 | executable_lines = defaultdict(set) 412 | current_filename = None 413 | 414 | if self._excluded_lines_map is None: 415 | self._excluded_lines_map = defaultdict(set) 416 | 417 | with open(c_file) as lines: 418 | lines = iter(lines) 419 | for line in lines: 420 | match = match_source_path_line(line) 421 | if not match: 422 | if ('__Pyx_TraceLine(' in line and 423 | current_filename is not None): 424 | trace_line = match_trace_line(line) 425 | if trace_line: 426 | executable_lines[current_filename].add( 427 | int(trace_line.group(1)) 428 | ) 429 | continue 430 | 431 | filename, lineno = match.groups() 432 | current_filename = filename 433 | lineno = int(lineno) 434 | for comment_line in lines: 435 | match = match_current_code_line(comment_line) 436 | if match: 437 | code_line = match.group(1).rstrip() 438 | if not_executable(code_line): 439 | break 440 | if (line_is_excluded is not None and 441 | line_is_excluded(code_line)): 442 | self._excluded_lines_map[filename].add(lineno) 443 | break 444 | code_lines[filename][lineno] = code_line 445 | break 446 | elif match_comment_end(comment_line): 447 | # unexpected comment format - false positive? 448 | break 449 | 450 | # Remove lines that generated code but are not traceable. 451 | for filename, lines in code_lines.items(): 452 | dead_lines = set(lines).difference( 453 | executable_lines.get(filename, ()) 454 | ) 455 | for lineno in dead_lines: 456 | del lines[lineno] 457 | return code_lines 458 | 459 | 460 | class CythonModuleTracer(FileTracer): 461 | """ 462 | Find the Python/Cython source file for a Cython module. 463 | """ 464 | def __init__(self, module_file, py_file, c_file, c_files_map, 465 | file_path_map): 466 | super(CythonModuleTracer, self).__init__() 467 | self.module_file = module_file 468 | self.py_file = py_file 469 | self.c_file = c_file 470 | self._c_files_map = c_files_map 471 | self._file_path_map = file_path_map 472 | 473 | def has_dynamic_source_filename(self): 474 | return True 475 | 476 | def dynamic_source_filename(self, filename, frame): 477 | """ 478 | Determine source file path. Called by the function call tracer. 479 | """ 480 | source_file = frame.f_code.co_filename 481 | try: 482 | return self._file_path_map[source_file] 483 | except KeyError: 484 | pass 485 | 486 | abs_path = _find_dep_file_path(filename, source_file) 487 | 488 | if self.py_file and source_file[-3:].lower() == '.py': 489 | # always let coverage.py handle this case itself 490 | self._file_path_map[source_file] = self.py_file 491 | return self.py_file 492 | 493 | assert self._c_files_map is not None 494 | if abs_path not in self._c_files_map: 495 | self._c_files_map[abs_path] = (self.c_file, source_file, None) 496 | self._file_path_map[source_file] = abs_path 497 | return abs_path 498 | 499 | 500 | class CythonModuleReporter(FileReporter): 501 | """ 502 | Provide detailed trace information for one source file to coverage.py. 503 | """ 504 | def __init__(self, c_file, source_file, rel_file_path, code, 505 | excluded_lines): 506 | super(CythonModuleReporter, self).__init__(source_file) 507 | self.name = rel_file_path 508 | self.c_file = c_file 509 | self._code = code 510 | self._excluded_lines = excluded_lines 511 | 512 | def lines(self): 513 | """ 514 | Return set of line numbers that are possibly executable. 515 | """ 516 | return set(self._code) 517 | 518 | def excluded_lines(self): 519 | """ 520 | Return set of line numbers that are excluded from coverage. 521 | """ 522 | return self._excluded_lines 523 | 524 | def _iter_source_tokens(self): 525 | current_line = 1 526 | for line_no, code_line in sorted(self._code.items()): 527 | while line_no > current_line: 528 | yield [] 529 | current_line += 1 530 | yield [('txt', code_line)] 531 | current_line += 1 532 | 533 | def source(self): 534 | """ 535 | Return the source code of the file as a string. 536 | """ 537 | if os.path.exists(self.filename): 538 | with open_source_file(self.filename) as f: 539 | return f.read() 540 | else: 541 | return '\n'.join( 542 | (tokens[0][1] if tokens else '') 543 | for tokens in self._iter_source_tokens()) 544 | 545 | def source_token_lines(self): 546 | """ 547 | Iterate over the source code tokens. 548 | """ 549 | if os.path.exists(self.filename): 550 | with open_source_file(self.filename) as f: 551 | for line in f: 552 | yield [('txt', line.rstrip('\n'))] 553 | else: 554 | for line in self._iter_source_tokens(): 555 | yield [('txt', line)] 556 | 557 | 558 | def coverage_init(reg, options): 559 | plugin = Plugin() 560 | reg.add_configurer(plugin) 561 | reg.add_file_tracer(plugin) 562 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | license_file = LICENSE 3 | 4 | [coverage:run] 5 | plugins = scripts.coverage 6 | source = csimdjson 7 | omit = 8 | # Coverage is picking up the Cython memoryview implementation, which 9 | # causes errors when generating reports. 10 | stringsource 11 | 12 | [coverage:report] 13 | exclude_lines = 14 | pragma: no cover 15 | 16 | [tool:pytest] 17 | required_plugins=pytest-benchmark 18 | 19 | [flake8] 20 | filename = *.pyx,*.pxd,*.pxi,*.py 21 | per-file-ignores = 22 | *.pyx:E211,E901,E999,E225,E226,E227,W504 23 | *.pyi:E211,E901,E999,E225,E226,E227,W504 24 | *.pxd:E211,E901,E999,E225,E226,E227,W504 25 | exclude = 26 | venv 27 | -------------------------------------------------------------------------------- /simdjson/__init__.py: -------------------------------------------------------------------------------- 1 | """High-level bindings for the simdjson project.""" 2 | import json 3 | 4 | try: 5 | from csimdjson import ( 6 | Parser, 7 | Array, 8 | Object, 9 | MAXSIZE_BYTES, 10 | PADDING 11 | ) 12 | except ImportError: 13 | raise RuntimeError('Unable to import low-level simdjson bindings.') 14 | 15 | _ALL_IMPORTS = [ 16 | Parser, 17 | Array, 18 | Object, 19 | MAXSIZE_BYTES, 20 | PADDING 21 | ] 22 | 23 | 24 | def load(fp, *, cls=None, object_hook=None, parse_float=None, parse_int=None, 25 | parse_constant=None, object_pairs_hook=None, **kwargs): 26 | """ 27 | Parse the JSON document in the file-like object fp and return the parsed 28 | object. 29 | 30 | All other arguments are ignored, and are provided only for compatibility 31 | with the built-in json module. 32 | """ 33 | parser = Parser() 34 | return parser.parse(fp.read(), True) 35 | 36 | 37 | def loads(s, *, cls=None, object_hook=None, parse_float=None, parse_int=None, 38 | parse_constant=None, object_pairs_hook=None, **kwargs): 39 | """ 40 | Parse the JSON document s and return the parsed object. 41 | 42 | All other arguments are ignored, and are provided only for compatibility 43 | with the built-in json module. 44 | """ 45 | parser = Parser() 46 | return parser.parse(s, True) 47 | 48 | 49 | dumps = json.dumps 50 | dump = json.dump 51 | JSONEncoder = json.JSONEncoder 52 | -------------------------------------------------------------------------------- /simdjson/__init__.pyi: -------------------------------------------------------------------------------- 1 | import json 2 | from pathlib import Path 3 | from typing import ( 4 | AbstractSet, 5 | Any, 6 | Dict, 7 | Final, 8 | Iterator, 9 | List, 10 | Mapping, 11 | Optional, 12 | Sequence, 13 | Tuple, 14 | Union, 15 | ValuesView, 16 | overload, 17 | ) 18 | 19 | try: 20 | from typing import Literal 21 | except ImportError: 22 | from typing_extensions import Literal # type: ignore 23 | 24 | Primitives = Union[int, float, str, bool] 25 | SimValue = Optional[Union['Object', 'Array', Primitives]] 26 | UnboxedValue = Optional[Union[Primitives, Dict[str, Any], List[Any]]] 27 | 28 | 29 | class Object(Mapping[str, SimValue]): 30 | def __getitem__(self, key: str) -> SimValue: 31 | ... 32 | 33 | def __iter__(self) -> Iterator[str]: 34 | ... 35 | 36 | def __len__(self) -> int: 37 | ... 38 | 39 | def as_dict(self) -> Dict[str, UnboxedValue]: 40 | ... 41 | 42 | def at_pointer(self, key: str) -> SimValue: 43 | ... 44 | 45 | def keys(self) -> AbstractSet[str]: 46 | ... 47 | 48 | def values(self) -> ValuesView[SimValue]: 49 | ... 50 | 51 | def items(self) -> AbstractSet[Tuple[str, SimValue]]: 52 | ... 53 | 54 | @property 55 | def mini(self) -> str: 56 | ... 57 | 58 | 59 | class Array(Sequence[SimValue]): 60 | def __len__(self) -> int: 61 | ... 62 | 63 | def __getitem__(self, idx: Union[int, slice]) -> 'Array': 64 | ... 65 | 66 | def as_list(self) -> List[Optional[Union[Primitives, dict, list]]]: 67 | ... 68 | 69 | def as_buffer(self, *, of_type: Literal['d', 'i', 'u']) -> bytes: 70 | ... 71 | 72 | def at_pointer(self, key: str) -> SimValue: 73 | ... 74 | 75 | @property 76 | def mini(self) -> str: 77 | ... 78 | 79 | 80 | class Parser: 81 | def __init__(self, max_capacity: int = ...) -> None: 82 | ... 83 | 84 | def get_implementations( 85 | self, 86 | supported_by_runtime: Literal[True] = ... 87 | ) -> Sequence[Tuple[str, str]]: 88 | ... 89 | 90 | @property 91 | def implementation(self) -> Tuple[str, str]: 92 | ... 93 | 94 | @implementation.setter 95 | def implementation(self, name: str): 96 | ... 97 | 98 | @overload 99 | def load( 100 | self, 101 | path: Union[str, Path], 102 | recursive: Literal[False] = ..., 103 | ) -> SimValue: 104 | ... 105 | 106 | @overload 107 | def load( 108 | self, 109 | path: Union[str, Path], 110 | recursive: Literal[True], 111 | ) -> UnboxedValue: 112 | ... 113 | 114 | @overload 115 | def parse( 116 | self, 117 | data: Union[str, bytes, bytearray, memoryview], 118 | recursive: Literal[False] = ..., 119 | ) -> SimValue: 120 | ... 121 | 122 | @overload 123 | def parse( 124 | self, 125 | data: Union[str, bytes, bytearray, memoryview], 126 | recursive: Literal[True], 127 | ) -> UnboxedValue: 128 | ... 129 | 130 | 131 | dumps = json.dumps 132 | dump = json.dump 133 | JSONEncoder = json.JSONEncoder 134 | loads = json.loads 135 | load = json.load 136 | 137 | MAXSIZE_BYTES: Final[int] = ... 138 | PADDING: Final[int] = ... 139 | VERSION: Final[str] = ... 140 | -------------------------------------------------------------------------------- /simdjson/csimdjson.pxd: -------------------------------------------------------------------------------- 1 | # cython: language_level=3 2 | # distutils: language=c++ 3 | from libc.stdint cimport uint32_t, uint64_t, int64_t 4 | from libcpp.string cimport string 5 | 6 | cdef extern from "Python.h": 7 | # Correct signature is const, but this was only fixed in Py3.7+ 8 | cdef char* PyUnicode_AsUTF8AndSize(object, Py_ssize_t *) 9 | 10 | 11 | cdef extern from "util.h": 12 | cdef void simdjson_error_handler() 13 | cdef void * flatten_array[T](simd_array src) \ 14 | except +simdjson_error_handler 15 | cdef void set_active_implementation(Implementation *) 16 | 17 | 18 | cdef extern from "simdjson.h" namespace "simdjson": 19 | cdef size_t SIMDJSON_MAXSIZE_BYTES 20 | cdef size_t SIMDJSON_PADDING 21 | cdef enum: 22 | SIMDJSON_VERSION_MAJOR 23 | SIMDJSON_VERSION_MINOR 24 | SIMDJSON_VERSION_REVISION 25 | 26 | cdef string minify[T](T) except +simdjson_error_handler 27 | 28 | cdef cppclass Implementation "simdjson::implementation": 29 | const string &name() 30 | const string &description() 31 | bint supported_by_runtime_system() const; 32 | 33 | # This is marked as private and internal, but we don't have a choice. 34 | cdef cppclass AvailableImplementationList \ 35 | "simdjson::internal::available_implementation_list": 36 | const Implementation * const *begin() 37 | const Implementation * const *end() 38 | 39 | const Implementation * operator[](string) 40 | 41 | cdef cppclass atomic_ptr[T]: 42 | pass 43 | 44 | const AvailableImplementationList& get_available_implementations() 45 | atomic_ptr["const Implementation"]* get_active_implementation() 46 | 47 | 48 | cdef extern from "simdjson.h" namespace "simdjson::dom::element_type": 49 | cdef enum element_type "simdjson::dom::element_type": 50 | OBJECT, 51 | ARRAY, 52 | STRING, 53 | INT64, 54 | UINT64, 55 | DOUBLE, 56 | BOOL, 57 | NULL_VALUE 58 | 59 | 60 | cdef extern from "simdjson.h" namespace "simdjson::dom": 61 | cdef cppclass simd_array "simdjson::dom::array": 62 | cppclass iterator: 63 | iterator() 64 | 65 | iterator operator++() 66 | bint operator!=(iterator) 67 | simd_element operator*() 68 | 69 | simd_array.iterator begin() 70 | simd_array.iterator end() 71 | 72 | size_t size() 73 | size_t number_of_slots() 74 | 75 | simd_element at(int) except +simdjson_error_handler 76 | simd_element at_pointer(const char*) except +simdjson_error_handler 77 | 78 | 79 | cdef cppclass simd_object "simdjson::dom::object": 80 | cppclass iterator: 81 | iterator() 82 | 83 | iterator operator++() 84 | bint operator!=(iterator) 85 | 86 | uint32_t key_length() 87 | const char *key_c_str() 88 | simd_element value() 89 | 90 | simd_object.iterator begin() 91 | simd_object.iterator end() 92 | 93 | size_t size() 94 | 95 | simd_element at_pointer(const char*) except +simdjson_error_handler 96 | simd_element operator[](const char*) except +simdjson_error_handler 97 | 98 | 99 | cdef cppclass simd_element "simdjson::dom::element": 100 | element_type type() except +simdjson_error_handler 101 | 102 | const char *get_c_str() except +simdjson_error_handler 103 | size_t get_string_length() except +simdjson_error_handler 104 | 105 | simd_array get_array() except +simdjson_error_handler 106 | simd_object get_object() except +simdjson_error_handler 107 | int64_t get_int64() except +simdjson_error_handler 108 | uint64_t get_uint64() except +simdjson_error_handler 109 | double get_double() except +simdjson_error_handler 110 | bint get_bool() except +simdjson_error_handler 111 | 112 | 113 | cdef cppclass simd_parser "simdjson::dom::parser": 114 | simd_parser() except +simdjson_error_handler 115 | simd_parser(size_t max_capacity) except +simdjson_error_handler 116 | 117 | simd_element parse(const char *, size_t, bint) \ 118 | except +simdjson_error_handler 119 | simd_element load(const char *) except +simdjson_error_handler 120 | -------------------------------------------------------------------------------- /simdjson/csimdjson.pyx: -------------------------------------------------------------------------------- 1 | # cython: language_level=3, c_string_type=unicode, c_string_encoding=utf8 2 | # distutils: language=c++ 3 | import pathlib 4 | 5 | from cython.operator cimport preincrement, dereference # noqa 6 | from libcpp.memory cimport shared_ptr, make_shared 7 | from cpython.ref cimport Py_INCREF 8 | from cpython.list cimport PyList_New, PyList_SET_ITEM 9 | from cpython.bytes cimport PyBytes_AsStringAndSize 10 | from cpython.slice cimport PySlice_GetIndicesEx, PySlice_New 11 | from cpython.mem cimport PyMem_Free 12 | from cpython.buffer cimport PyBuffer_FillInfo 13 | 14 | from simdjson.csimdjson cimport * # noqa 15 | 16 | MAXSIZE_BYTES = SIMDJSON_MAXSIZE_BYTES 17 | PADDING = SIMDJSON_PADDING 18 | VERSION = ( 19 | f'{SIMDJSON_VERSION_MAJOR}.' 20 | f'{SIMDJSON_VERSION_MINOR}.' 21 | f'{SIMDJSON_VERSION_REVISION}' 22 | ) 23 | 24 | 25 | cdef bytes str_as_bytes(s): 26 | if isinstance(s, unicode): 27 | return (s).encode('utf-8') 28 | return s 29 | 30 | 31 | cdef dict object_to_dict(Parser p, simd_object obj, bint recursive): 32 | cdef: 33 | dict result = {} 34 | object pyobj 35 | size_t size 36 | const char *data 37 | simd_object.iterator it = obj.begin() 38 | 39 | while it != obj.end(): 40 | pyobj = element_to_primitive(p, it.value(), recursive) 41 | 42 | data = it.key_c_str() 43 | size = it.key_length() 44 | 45 | result[data[:size]] = pyobj 46 | preincrement(it) 47 | 48 | return result 49 | 50 | 51 | cdef list array_to_list(Parser p, simd_array arr, bint recursive): 52 | cdef: 53 | list result = PyList_New(arr.size()) 54 | size_t i = 0 55 | 56 | for element in arr: 57 | primitive = element_to_primitive(p, element, recursive) 58 | Py_INCREF(primitive) 59 | PyList_SET_ITEM( 60 | result, 61 | i, 62 | primitive 63 | ) 64 | i += 1 65 | 66 | return result 67 | 68 | 69 | cdef inline object element_to_primitive(Parser p, simd_element e, 70 | bint recursive=False): 71 | cdef: 72 | const char *data 73 | size_t size 74 | element_type type_ = e.type() 75 | 76 | if type_ == element_type.OBJECT: 77 | if recursive: 78 | return object_to_dict(p, e.get_object(), recursive) 79 | return Object.from_element(p, e) 80 | elif type_ == element_type.ARRAY: 81 | if recursive: 82 | return array_to_list(p, e.get_array(), recursive) 83 | return Array.from_element(p, e) 84 | elif type_ == element_type.STRING: 85 | data = e.get_c_str() 86 | size = e.get_string_length() 87 | return data[:size] 88 | elif type_ == element_type.INT64: 89 | return e.get_int64() 90 | elif type_ == element_type.UINT64: 91 | return e.get_uint64() 92 | elif type_ == element_type.DOUBLE: 93 | return e.get_double() 94 | elif type_ == element_type.BOOL: 95 | return e.get_bool() 96 | elif type_ == element_type.NULL_VALUE: 97 | return None 98 | else: 99 | raise ValueError( # pragma: no cover 100 | 'Encountered an unknown element_type.' 101 | ) 102 | 103 | 104 | cdef class ArrayBuffer: 105 | """ 106 | A container for the flattened data of a homogeneous :class:`Array`. 107 | 108 | .. admonition:: 109 | :class: note 110 | 111 | This object is responsible for keeping the contents of an Array alive 112 | even after the simdjson Parser has been reused or destroyed. 113 | 114 | .. admonition:: 115 | :class: warning 116 | 117 | You should never create this class on your own. It is created and 118 | returned for you by :func:`Array.as_buffer`. 119 | """ 120 | cdef void *buffer 121 | cdef readonly size_t size 122 | 123 | def __cinit__(self): 124 | self.buffer = NULL 125 | self.size = 0 126 | 127 | def __dealloc__(self): 128 | if self.buffer != NULL: 129 | PyMem_Free(self.buffer) 130 | 131 | @staticmethod 132 | cdef inline from_element(simd_array src, of_type): 133 | cdef: 134 | ArrayBuffer self = ArrayBuffer.__new__(ArrayBuffer) 135 | 136 | if of_type == 'd': 137 | self.buffer = flatten_array[double](src, &self.size) 138 | elif of_type == 'i': 139 | self.buffer = flatten_array[int64_t](src, &self.size) 140 | elif of_type == 'u': 141 | self.buffer = flatten_array[uint64_t](src, &self.size) 142 | else: 143 | raise ValueError('of_type must be one of {d,i,u}.') 144 | 145 | if not self.buffer: 146 | raise MemoryError() # pragma: no cover 147 | 148 | return self 149 | 150 | def __getbuffer__(self, Py_buffer *buffer, int flags): 151 | PyBuffer_FillInfo(buffer, self, self.buffer, self.size, 0, flags) 152 | 153 | def __releasebuffer__(self, Py_buffer *buffer): 154 | pass 155 | 156 | 157 | cdef class Array: 158 | """A proxy object that behaves much like a real `list()`. 159 | 160 | Python objects are not created until an element in the list is accessed. 161 | When you only need a subset of an Array, this can be much faster than 162 | converting an entire array (and all of its children) into real Python 163 | objects. 164 | """ 165 | cdef readonly Parser parser 166 | cdef simd_array c_element 167 | cdef shared_ptr[simd_parser] c_parser 168 | 169 | @staticmethod 170 | cdef inline from_element(Parser parser, simd_element src): 171 | cdef Array self = Array.__new__(Array) 172 | self.parser = parser 173 | self.c_element = src.get_array() 174 | self.c_parser = parser.c_parser 175 | return self 176 | 177 | def __getitem__(self, key): 178 | cdef: 179 | Py_ssize_t start = 0, stop = 0, step = 0, slice_length = 0 180 | Py_ssize_t dst, src 181 | list result 182 | 183 | if isinstance(key, slice): 184 | PySlice_GetIndicesEx( 185 | key, 186 | self.c_element.size(), 187 | &start, 188 | &stop, 189 | &step, 190 | &slice_length 191 | ) 192 | 193 | result = PyList_New(slice_length) 194 | for dst, src in enumerate(range(start, stop, step)): 195 | primitive = element_to_primitive( 196 | self.parser, 197 | self.c_element.at(src), 198 | True 199 | ) 200 | Py_INCREF(primitive) 201 | PyList_SET_ITEM( 202 | result, 203 | dst, 204 | primitive 205 | ) 206 | 207 | return result 208 | elif isinstance(key, int): 209 | # Wrap around negative indexes. 210 | if key < 0: 211 | key += self.c_element.size() 212 | 213 | return element_to_primitive(self.parser, self.c_element.at(key)) 214 | 215 | def __len__(self): 216 | return self.c_element.size() 217 | 218 | def __iter__(self): 219 | cdef simd_array.iterator it = self.c_element.begin() 220 | while it != self.c_element.end(): 221 | yield element_to_primitive( 222 | self.parser, 223 | dereference(it), 224 | False 225 | ) 226 | preincrement(it) 227 | 228 | def at_pointer(self, json_pointer): 229 | """Get the value at the given JSON pointer.""" 230 | return element_to_primitive( 231 | self.parser, 232 | self.c_element.at_pointer( 233 | str_as_bytes(json_pointer) 234 | ) 235 | ) 236 | 237 | def as_list(self): 238 | """ 239 | Convert this Array to a regular python list, recursively 240 | converting any objects/lists it finds. 241 | """ 242 | return array_to_list(self.parser, self.c_element, True) 243 | 244 | def as_buffer(self, *, of_type): 245 | """ 246 | **Copies** the contents of a **homogeneous** array to an 247 | object that can be used as a `buffer`. This means it can be 248 | used as input for `numpy.frombuffer`, `bytearray`, 249 | `memoryview`, etc. 250 | 251 | When n-dimensional arrays are encountered, this method will recursively 252 | flatten them. 253 | 254 | .. note:: 255 | 256 | The object returned by this method contains a *copy* of the Array's 257 | data. Thus, it's safe to use even after the Array or Parser are 258 | destroyed or reused. 259 | 260 | :param of_type: One of 'd' (double), 'i' (signed 64-bit integer) or 'u' 261 | (unsigned 64-bit integer). 262 | """ 263 | return ArrayBuffer.from_element(self.c_element, of_type) 264 | 265 | @property 266 | def mini(self): 267 | """ 268 | Returns the minified JSON representation of this Array. 269 | 270 | :rtype: bytes 271 | """ 272 | return minify(self.c_element) 273 | 274 | 275 | cdef class Object: 276 | """A proxy object that behaves much like a real `dict()`. 277 | 278 | Python objects are not created until an element in the Object 279 | is accessed. When you only need a subset of an Object, this can be much 280 | faster than converting an entire Object (and all of its children) into real 281 | Python objects. 282 | """ 283 | cdef readonly Parser parser 284 | cdef simd_object c_element 285 | cdef shared_ptr[simd_parser] c_parser 286 | 287 | @staticmethod 288 | cdef inline from_element(Parser parser, simd_element src): 289 | cdef Object self = Object.__new__(Object) 290 | self.parser = parser 291 | self.c_element = src.get_object() 292 | self.c_parser = parser.c_parser 293 | return self 294 | 295 | def __getitem__(self, key): 296 | return element_to_primitive( 297 | self.parser, 298 | self.c_element[str_as_bytes(key)] 299 | ) 300 | 301 | def get(self, key, default=None): 302 | """ 303 | Return the value of `key`, or `default` if the key does 304 | not exist. 305 | """ 306 | try: 307 | return self[key] 308 | except KeyError: 309 | return default 310 | 311 | def __len__(self): 312 | return self.c_element.size() 313 | 314 | def __contains__(self, key): 315 | try: 316 | self.c_element[str_as_bytes(key)] 317 | except KeyError: 318 | return False 319 | return True 320 | 321 | def __iter__(self): 322 | """ 323 | Returns an iterator over all keys in this `Object`. 324 | """ 325 | cdef: 326 | size_t size 327 | const char *data 328 | simd_object.iterator it = self.c_element.begin() 329 | 330 | while it != self.c_element.end(): 331 | data = it.key_c_str() 332 | size = it.key_length() 333 | yield data[:size] 334 | preincrement(it) 335 | 336 | keys = __iter__ 337 | 338 | def values(self): 339 | """ 340 | Returns an iterator over of all values in this `Object`. 341 | """ 342 | cdef simd_object.iterator it = self.c_element.begin() 343 | while it != self.c_element.end(): 344 | yield element_to_primitive(self.parser, it.value(), True) 345 | preincrement(it) 346 | 347 | def items(self): 348 | """ 349 | Returns an iterator over all the (key, value) pairs in this 350 | `Object`. 351 | """ 352 | cdef: 353 | size_t size 354 | const char *data 355 | simd_object.iterator it = self.c_element.begin() 356 | 357 | while it != self.c_element.end(): 358 | data = it.key_c_str() 359 | size = it.key_length() 360 | yield ( 361 | data[:size], 362 | element_to_primitive(self.parser, it.value(), True) 363 | ) 364 | preincrement(it) 365 | 366 | def at_pointer(self, json_pointer): 367 | """Get the value at the given JSON pointer.""" 368 | return element_to_primitive( 369 | self.parser, 370 | self.c_element.at_pointer( 371 | str_as_bytes(json_pointer) 372 | ) 373 | ) 374 | 375 | def as_dict(self): 376 | """ 377 | Convert this `Object` to a regular python dictionary, 378 | recursively converting any objects or lists it finds. 379 | """ 380 | return object_to_dict(self.parser, self.c_element, True) 381 | 382 | @property 383 | def mini(self): 384 | """ 385 | Returns the minified JSON representation of this Object. 386 | 387 | :rtype: bytes 388 | """ 389 | return minify(self.c_element) 390 | 391 | 392 | cdef class Parser: 393 | """ 394 | A `Parser` instance is used to load and/or parse a JSON document. 395 | 396 | A Parser can be reused to parse multiple documents, in which case it wil 397 | reuse its internal buffer, only increasing it if needed. 398 | 399 | :param max_capacity: The maximum size the internal buffer can 400 | grow to. [default: SIMDJSON_MAXSIZE_BYTES] 401 | """ 402 | cdef shared_ptr[simd_parser] c_parser 403 | 404 | def __cinit__(self, size_t max_capacity=SIMDJSON_MAXSIZE_BYTES): 405 | self.c_parser = make_shared[simd_parser](max_capacity) 406 | 407 | def __dealloc__(self): 408 | self.c_parser.reset() 409 | 410 | def parse(self, src not None, bint recursive=False): 411 | """Parse the given JSON document. 412 | 413 | The source document may be a `str`, `bytes`, `bytearray`, or any other 414 | object that implements the buffer protocol. 415 | 416 | .. admonition:: Performance 417 | :class: tip 418 | 419 | While you can pass quite a few things to this method to be parsed, 420 | simple ``bytes`` will almost always be the fastest. 421 | 422 | If any :class:`~Object` or :class:`~Array` proxies still pointing to 423 | a previously-parsed document exist when this method is called, a 424 | ``RuntimeError`` may be raised. 425 | 426 | :param src: The document to parse. 427 | :param recursive: Recursively turn the document into real 428 | python objects instead of pysimdjson proxies. 429 | [default: False] 430 | """ 431 | # This may be very non-intuitive on PyPy, where cleanup of references 432 | # may not occur until much later than expected by a user. We may need 433 | # to recommend against re-use on PyPy. 434 | if self.c_parser.use_count() > 1: 435 | raise RuntimeError( 436 | 'Tried to re-use a parser while simdjson.Object and/or' 437 | ' simdjson.Array objects still exist referencing the old' 438 | ' parser.' 439 | ) 440 | 441 | cdef: 442 | const unsigned char[::1] data 443 | const char * str_data = NULL 444 | char * bytes_data = NULL 445 | Py_ssize_t str_size = 0 446 | 447 | if isinstance(src, bytes): 448 | # Handling bytes is drastically faster than using the buffer API. 449 | PyBytes_AsStringAndSize(src, &bytes_data, &str_size) 450 | return element_to_primitive( 451 | self, 452 | dereference(self.c_parser).parse( 453 | bytes_data, 454 | str_size, 455 | True 456 | ), 457 | recursive 458 | ) 459 | elif isinstance(src, str): 460 | # str can't be handled using the buffer API, oddly, even if you 461 | # know the encoding. 462 | str_data = PyUnicode_AsUTF8AndSize(src, &str_size) 463 | return element_to_primitive( 464 | self, 465 | dereference(self.c_parser).parse( 466 | str_data, 467 | str_size, 468 | True 469 | ), 470 | recursive 471 | ) 472 | else: 473 | # Handle any type that provides the buffer API (bytes, bytearray, 474 | # memoryview, etc). This is significantly slower than the 475 | # type-specific APIs, but gives much greater compatibility. 476 | data = src 477 | 478 | if data.size == 0: 479 | # If we were given a completely empty buffer, trying to access 480 | # a stride in the next step will cause a (potentially 481 | # confusing) IndexError. This isn't a very good error message, 482 | # but it's identical to the one simdjson would have raised. 483 | raise ValueError('EMPTY: no JSON found') 484 | 485 | return element_to_primitive( 486 | self, 487 | dereference(self.c_parser).parse( 488 | &data[0], 489 | data.shape[0], 490 | True 491 | ), 492 | recursive 493 | ) 494 | 495 | def load(self, path, bint recursive=False): 496 | """Load a JSON document from the file system path `path`. 497 | 498 | If any :class:`~Object` or :class:`~Array` proxies still pointing to 499 | a previously-parsed document exist when this method is called, a 500 | `RuntimeError` may be raised. 501 | 502 | :param path: A filesystem path. 503 | :param recursive: Recursively turn the document into real 504 | python objects instead of pysimdjson proxies. 505 | """ 506 | if self.c_parser.use_count() > 1: 507 | raise RuntimeError( 508 | 'Tried to re-use a parser while simdjson.Object and/or' 509 | ' simdjson.Array objects still exist referencing the old' 510 | ' parser.' 511 | ) 512 | 513 | if isinstance(path, unicode): 514 | path = (path).encode('utf-8') 515 | elif isinstance(path, pathlib.Path): 516 | path = str(path).encode('utf-8') 517 | 518 | cdef simd_element document = dereference(self.c_parser).load(path) 519 | return element_to_primitive(self, document, recursive) 520 | 521 | def get_implementations(self, supported_by_runtime=True): 522 | """ 523 | A list of available parser implementations in the form of [(name, 524 | description),…]. 525 | 526 | By default, this only returns the implementations that are usable on 527 | the current runtime. Setting `supported_by_runtime` to False will 528 | instead return all the implementations _compiled_ into this build of 529 | simdjson. 530 | """ 531 | for impl in get_available_implementations(): 532 | if supported_by_runtime and not impl.supported_by_runtime_system(): 533 | continue 534 | 535 | yield impl.name(), impl.description() 536 | 537 | @property 538 | def implementation(self): 539 | """ 540 | The active parser Implementation as (name, description). Can be 541 | any value from :py:attr:`implementations`. The best Implementation 542 | for your current platform will be picked by default. 543 | 544 | Can be set to the name of any valid Implementation to globally 545 | change underlying Parser Implementation, such as to disable AVX-512 546 | if it is causing down-clocking. 547 | """ 548 | cdef const Implementation * impl = ( 549 | get_active_implementation() 550 | ) 551 | return impl.name(), impl.description() 552 | 553 | @implementation.setter 554 | def implementation(self, name): 555 | for impl in get_available_implementations(): 556 | if impl.name() != str_as_bytes(name): 557 | continue 558 | 559 | if not impl.supported_by_runtime_system(): 560 | raise RuntimeError( 561 | 'Attempted to set a runtime Implementation that is not' 562 | 'supported on the current host.' 563 | ) 564 | 565 | set_active_implementation(impl) 566 | return 567 | 568 | raise ValueError('Unknown Implementation') 569 | -------------------------------------------------------------------------------- /simdjson/py.typed: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /simdjson/util.cpp: -------------------------------------------------------------------------------- 1 | #define PY_SSIZE_T_CLEAN 2 | #include 3 | #include "simdjson.h" 4 | #include "util.h" 5 | 6 | /** 7 | * Error translator, converting simdjson C++ exceptions into sensible Python 8 | * exceptions. 9 | * 10 | * Use it like: 11 | * 12 | * simd_element at(int) except +simdjson_error_handler 13 | */ 14 | void 15 | simdjson_error_handler() { 16 | using namespace simdjson; 17 | 18 | try { 19 | if(PyErr_Occurred()) { 20 | ; // Exception pass-through. 21 | } else { 22 | throw; 23 | } 24 | } catch (const simdjson_error &e) { 25 | switch (e.error()) { 26 | case error_code::NO_SUCH_FIELD: 27 | PyErr_SetString(PyExc_KeyError, e.what()); 28 | return; 29 | case error_code::INDEX_OUT_OF_BOUNDS: 30 | PyErr_SetString(PyExc_IndexError, e.what()); 31 | return; 32 | case error_code::INCORRECT_TYPE: 33 | PyErr_SetString(PyExc_TypeError, e.what()); 34 | return; 35 | case error_code::MEMALLOC: 36 | PyErr_SetNone(PyExc_MemoryError); 37 | return; 38 | case error_code::EMPTY: 39 | case error_code::STRING_ERROR: 40 | case error_code::T_ATOM_ERROR: 41 | case error_code::F_ATOM_ERROR: 42 | case error_code::N_ATOM_ERROR: 43 | case error_code::NUMBER_ERROR: 44 | case error_code::UNESCAPED_CHARS: 45 | case error_code::UNCLOSED_STRING: 46 | case error_code::NUMBER_OUT_OF_RANGE: 47 | case error_code::INVALID_JSON_POINTER: 48 | case error_code::INVALID_URI_FRAGMENT: 49 | case error_code::CAPACITY: 50 | case error_code::TAPE_ERROR: 51 | PyErr_SetString(PyExc_ValueError, e.what()); 52 | return; 53 | case error_code::IO_ERROR: 54 | PyErr_SetString(PyExc_IOError, e.what()); 55 | return; 56 | case error_code::UTF8_ERROR: 57 | { 58 | // simdjson doesn't yet give us any precise details on 59 | // where the error occured. See upstream#46. 60 | // PyUnicodeDecodeError_* methods are stubs on PyPy3, 61 | // so we can't use that helper.. 62 | PyObject *unicode_error = PyObject_CallFunction( 63 | PyExc_UnicodeDecodeError, 64 | "sy#nns", 65 | "utf-8", 66 | "", 67 | 0, 68 | 0, 69 | 1, 70 | e.what() 71 | ); 72 | PyErr_SetObject( 73 | PyExc_UnicodeDecodeError, 74 | unicode_error 75 | ); 76 | Py_XDECREF(unicode_error); 77 | return; 78 | } 79 | default: 80 | PyErr_SetString(PyExc_RuntimeError, e.what()); 81 | return; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /simdjson/util.h: -------------------------------------------------------------------------------- 1 | #define PY_SSIZE_T_CLEAN 2 | #include 3 | #include "simdjson.h" 4 | 5 | #ifndef _PY_SIMDJSON_ERRORS 6 | #define _PY_SIMDJSON_ERRORS 7 | void simdjson_error_handler(); 8 | template 9 | void * flatten_array(simdjson::dom::array src, size_t *size); 10 | 11 | template 12 | void _flatten_array(T ** buffer, simdjson::dom::array src) { 13 | for (simdjson::dom::element field : src) { 14 | if (field.type() == simdjson::dom::element_type::ARRAY) { 15 | _flatten_array(buffer, field); 16 | } else { 17 | **buffer = (T)field; 18 | (*buffer)++; 19 | } 20 | } 21 | } 22 | 23 | template 24 | void * flatten_array(simdjson::dom::array src, size_t *size) { 25 | // This will over-allocate if the array is not flat, since array starts 26 | // and ends each count as a slot on their own. However, this prevents 27 | // us from having to grow whenever we find a new child array. 28 | T * data = (T*)PyMem_Malloc(sizeof(T) * (src.number_of_slots() / 2)); 29 | T * start = data; 30 | if (!data) return NULL; 31 | 32 | try { 33 | _flatten_array(&start, src); 34 | } catch(...) { 35 | PyMem_Free(data); 36 | throw; 37 | } 38 | 39 | *size = (char*)start - (char*)data; 40 | // TODO: Realloc if too large 41 | return (void*)data; 42 | } 43 | 44 | // This exists as a workaround to Cython 0.29 apparently not supporting 45 | // overloading "atomic_ptr& operator=(T*)" on atomic_ptr, meaning we 46 | // can't assign an implementation to the pointer. I'm probably just 47 | // using it wrong :) 48 | inline void set_active_implementation(const simdjson::implementation *t) { 49 | simdjson::get_active_implementation() = t; 50 | return; 51 | } 52 | #endif 53 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | from pathlib import Path 3 | 4 | import pytest 5 | 6 | 7 | def pytest_addoption(parser): 8 | parser.addoption( 9 | '--runslow', 10 | action='store_true', 11 | default=False, 12 | help='run slow tests' 13 | ) 14 | 15 | 16 | def pytest_configure(config): 17 | config.addinivalue_line('markers', 'slow: mark test as slow to run') 18 | 19 | 20 | def pytest_collection_modifyitems(config, items): 21 | if config.getoption('--runslow'): 22 | # --runslow given in cli: do not skip slow tests 23 | return 24 | 25 | skip_slow = pytest.mark.skip(reason='need --runslow option to run') 26 | for item in items: 27 | if 'slow' in item.keywords: 28 | item.add_marker(skip_slow) 29 | 30 | 31 | @pytest.fixture 32 | def parser(): 33 | import csimdjson 34 | yield csimdjson.Parser() 35 | 36 | 37 | @pytest.fixture 38 | def doc(parser): 39 | yield parser.parse(b'''{ 40 | "array": [1, 2, 3], 41 | "object": {"hello": "world"}, 42 | "int64": -1, 43 | "uint64": 18446744073709551615, 44 | "double": 1.1, 45 | "string": "test", 46 | "bool": true, 47 | "null_value": null 48 | }''') 49 | 50 | 51 | @pytest.fixture 52 | def parsing_tests(): 53 | return { 54 | 'y': (Path('jsonexamples') / 'test_parsing').glob('y_*.json'), 55 | 'n': (Path('jsonexamples') / 'test_parsing').glob('n_*.json'), 56 | 'i': (Path('jsonexamples') / 'test_parsing').glob('i_*.json') 57 | } 58 | 59 | 60 | @pytest.fixture 61 | def jsonexamples(): 62 | return os.path.abspath( 63 | os.path.join( 64 | os.path.dirname(__file__), 65 | '..', 66 | 'jsonexamples' 67 | ) 68 | ) 69 | -------------------------------------------------------------------------------- /tests/test_array.py: -------------------------------------------------------------------------------- 1 | """Tests for the csimdjson.Array proxy object.""" 2 | import pytest 3 | 4 | import simdjson 5 | 6 | 7 | def test_array_abc_sequence(parser): 8 | """Ensure our Array type complies with the collections.abc.Sequence 9 | interface. 10 | 11 | Complying with this interface requires `__iter__`, `__len__`, 12 | `__contains__`, `__getitem__`, `__reversed__`, `index`, and `count`. 13 | """ 14 | obj = parser.parse(b'[1, 2, 3, 4, 5]') 15 | assert isinstance(obj, simdjson.Array) 16 | 17 | # __iter__ 18 | assert list(iter(obj)) == [1, 2, 3, 4, 5] 19 | # __len__ 20 | assert len(obj) == 5 21 | # __contains__ 22 | assert 3 in obj 23 | assert 7 not in obj 24 | # __getitem__ 25 | assert obj[2] == 3 26 | with pytest.raises(IndexError): 27 | obj[99] 28 | # __reversed__, implemented via __len__ and __getitem__ for now. 29 | assert list(reversed(obj)) == [5, 4, 3, 2, 1] 30 | 31 | 32 | def test_array_slicing(parser): 33 | """Ensure we can slice our csimdjson.Array just like a real array.""" 34 | doc = parser.parse(b'[0, 1, 2, 3, 4, 5]') 35 | assert isinstance(doc, simdjson.Array) 36 | 37 | assert list(doc) == [0, 1, 2, 3, 4, 5] 38 | assert doc[-1] == 5 39 | assert doc[0:2] == [0, 1] 40 | assert doc[::2] == [0, 2, 4] 41 | assert doc[::-1] == [5, 4, 3, 2, 1, 0] 42 | 43 | 44 | def test_array_uplift(parser): 45 | """Ensure we can turn our Array into a python list.""" 46 | doc = parser.parse(b'[0, 1, 2, 3, 4, 5]') 47 | assert isinstance(doc, simdjson.Array) 48 | 49 | assert doc.as_list() == [0, 1, 2, 3, 4, 5] 50 | assert isinstance(doc.as_list(), list) 51 | 52 | 53 | def test_array_mini(parser): 54 | """Test JSON minifier.""" 55 | doc = parser.parse(b'[ 0, 1, 2, 3, 4, 5]') 56 | assert doc.mini == b'[0,1,2,3,4,5]' 57 | 58 | 59 | def test_array_as_buffer(parser): 60 | """Ensure we can export homogeneous arrays as buffers.""" 61 | doc = parser.parse(b'''{ 62 | "d": [1.2, 2.3, 3.4], 63 | "i": [-1, 2, -3, 4], 64 | "u": [1, 2, 3, 4, 5], 65 | "x": [1, 2, 3, "not valid"] 66 | }''') 67 | 68 | memoryview(doc['d'].as_buffer(of_type='d')) 69 | memoryview(doc['i'].as_buffer(of_type='i')) 70 | memoryview(doc['u'].as_buffer(of_type='u')) 71 | 72 | # Not a valid `of_type`. 73 | with pytest.raises(ValueError): 74 | doc['i'].as_buffer(of_type='x') 75 | 76 | # Not a valid homogeneous array. 77 | with pytest.raises(TypeError): 78 | doc['x'].as_buffer(of_type='u') 79 | 80 | # Signed elements should error on cast. 81 | with pytest.raises(ValueError): 82 | doc['i'].as_buffer(of_type='u') 83 | 84 | 85 | def test_array_as_buffer_ndim(parser): 86 | """Ensure n-dimensional arrays are flattened when converting to a 87 | buffer.""" 88 | doc = parser.parse(b'''[[ 89 | [1.0, 2.0], 90 | [3.0, 4.0] 91 | ]]''') 92 | view = memoryview(doc.as_buffer(of_type='d')) 93 | assert len(view) == 32 94 | 95 | 96 | def test_array_pointer(parser): 97 | """Ensure we can access an array element by pointer.""" 98 | doc = parser.parse(b'[0, 1, 2, 3, 4, 5]') 99 | assert doc.at_pointer('/1') == 1 100 | -------------------------------------------------------------------------------- /tests/test_element.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | def test_json_pointer(parser): 5 | """Ensure JSON pointers work as expected and all possible exceptions 6 | are converted to Python types. 7 | """ 8 | doc = parser.parse(b'{"key": "value", "array": [0, 1, 2]}') 9 | 10 | assert isinstance(doc.at_pointer('/key'), str) 11 | assert isinstance(doc.at_pointer('/array/0'), int) 12 | 13 | with pytest.raises(KeyError): 14 | doc.at_pointer('/no_such_key') 15 | 16 | with pytest.raises(IndexError): 17 | doc.at_pointer('/array/9') 18 | 19 | with pytest.raises(TypeError): 20 | doc.at_pointer('/array/not_a_num') 21 | 22 | with pytest.raises(ValueError): 23 | doc.at_pointer('/array/') 24 | 25 | 26 | def test_uplift(doc): 27 | """Test uplifting of primitive types to their Python types.""" 28 | assert doc['int64'] == -1 29 | assert doc['uint64'] == 18446744073709551615 30 | assert doc['double'] == 1.1 31 | assert doc['string'] == 'test' 32 | assert doc['bool'] is True 33 | assert doc['null_value'] is None 34 | -------------------------------------------------------------------------------- /tests/test_minefield.py: -------------------------------------------------------------------------------- 1 | """Test simdjson against the JSON minefield by Nicholas Seriot. 2 | 3 | See https://github.com/nst/JSONTestSuite for more. 4 | """ 5 | 6 | 7 | def test_parsing(parser, parsing_tests): 8 | """Ensure all parsing tests complete as expected.""" 9 | for expected_result, files in parsing_tests.items(): 10 | for file in files: 11 | try: 12 | parser.load(file) 13 | except (ValueError, RuntimeError): 14 | # The source document was not expected to fail. 15 | if expected_result == 'y': 16 | raise 17 | -------------------------------------------------------------------------------- /tests/test_numpy.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import pytest 4 | 5 | import simdjson 6 | 7 | 8 | def with_buffer(content): 9 | import numpy 10 | 11 | parser = simdjson.Parser() 12 | doc = parser.parse(content) 13 | assert len(numpy.frombuffer(doc.as_buffer(of_type='d'))) == 10001 14 | 15 | 16 | def without_buffer(content): 17 | import numpy 18 | 19 | parser = simdjson.Parser() 20 | doc = parser.parse(content) 21 | assert len(numpy.array(doc.as_list())) == 10001 22 | 23 | 24 | def with_builtin(content): 25 | import numpy 26 | assert len(numpy.array(json.loads(content))) == 10001 27 | 28 | 29 | def with_orjson(content): 30 | import numpy 31 | import orjson 32 | 33 | assert len(numpy.array(orjson.loads(content))) == 10001 34 | 35 | 36 | @pytest.mark.slow 37 | @pytest.mark.parametrize('loader', [ 38 | with_buffer, without_buffer, with_builtin, with_orjson]) 39 | def test_array_to_numpy(benchmark, loader): 40 | """Test how quickly we can load a homogeneous array of floats into a 41 | numpy array.""" 42 | with open('jsonexamples/numbers.json', 'rb') as src: 43 | content = src.read() 44 | 45 | benchmark.group = 'numpy array (deserialize)' 46 | benchmark.extra_info['group'] = 'numpy' 47 | benchmark(loader, content) 48 | -------------------------------------------------------------------------------- /tests/test_object.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | import simdjson 4 | 5 | 6 | def test_object_abc_mapping(parser): 7 | """Ensure our Object type complies with the collections.abc.Mapping 8 | interface. 9 | 10 | Complying with this interface requires `__iter__`, `__len__`, 11 | `__contains__`, `__getitem__`, `keys`, `items`, `values`, and `get`. 12 | """ 13 | doc = parser.parse(b'{"a": "b", "c": [0, 1, 2], "x": {"f": "z"}}') 14 | assert isinstance(doc, simdjson.Object) 15 | 16 | # __iter__ 17 | assert list(iter(doc)) == ['a', 'c', 'x'] 18 | # __len__ 19 | assert len(doc) == 3 20 | # __contains__ 21 | assert 'a' in doc 22 | assert 'd' not in doc 23 | # __getitem__ 24 | # Individual key access returns proxy objects. 25 | assert isinstance(doc['x'], simdjson.Object) 26 | assert isinstance(doc['c'], simdjson.Array) 27 | 28 | # Key lookup by byte or str 29 | assert doc['a'] == 'b' 30 | assert doc[b'a'] == 'b' 31 | 32 | with pytest.raises(KeyError): 33 | doc['z'] 34 | 35 | # keys() 36 | assert list(doc.keys()) == ['a', 'c', 'x'] 37 | # values() 38 | assert list(doc.values()) == ['b', [0, 1, 2], {'f': 'z'}] 39 | # items() 40 | assert list(doc.items()) == [ 41 | ('a', 'b'), 42 | ('c', [0, 1, 2]), 43 | ('x', {'f': 'z'}) 44 | ] 45 | # get() 46 | assert doc.get('a') == 'b' 47 | assert doc.get('z') is None 48 | assert doc.get('z', True) is True 49 | 50 | 51 | def test_object_uplift(parser): 52 | """Ensure we can turn our Object into a python dict.""" 53 | doc = parser.parse(b'{"a": "b", "c": [0, 1, 2], "x": {"f": "z"}}') 54 | assert isinstance(doc, simdjson.Object) 55 | 56 | assert doc.as_dict() == { 57 | 'a': 'b', 58 | 'c': [0, 1, 2], 59 | 'x': {'f': 'z'} 60 | } 61 | assert isinstance(doc.as_dict(), dict) 62 | 63 | 64 | def test_object_mini(parser): 65 | """Test JSON minifier.""" 66 | doc = parser.parse(b'{"a" : "z" }') 67 | assert doc.mini == b'{"a":"z"}' 68 | 69 | 70 | def test_object_pointer(parser): 71 | """Ensure we can access an object element by pointer.""" 72 | doc = parser.parse(b'{"a" : "z" }') 73 | assert doc.at_pointer('/a') == 'z' 74 | -------------------------------------------------------------------------------- /tests/test_parser.py: -------------------------------------------------------------------------------- 1 | import io 2 | import pathlib 3 | import os.path 4 | 5 | import pytest 6 | 7 | import simdjson 8 | 9 | 10 | def test_load_str(parser, jsonexamples): 11 | """Ensure we can load a file from disk using a string.""" 12 | with pytest.raises(ValueError): 13 | parser.load(os.path.join(jsonexamples, 'invalid.json')) 14 | 15 | doc = parser.load(os.path.join(jsonexamples, 'small', 'demo.json')) 16 | doc.at_pointer('/Image/Width') 17 | 18 | 19 | def test_load_path(parser, jsonexamples): 20 | """Ensure we can load a file using a Path object.""" 21 | doc = parser.load(pathlib.Path(jsonexamples) / 'small' / 'demo.json') 22 | doc.at_pointer('/Image/Width') 23 | 24 | 25 | def test_parse_bytes(parser): 26 | """Ensure we can load from byte string fragments.""" 27 | doc = parser.parse(b'{"hello": "world"}') 28 | assert doc.as_dict() == {'hello': 'world'} 29 | 30 | 31 | def test_parse_str(parser): 32 | """Ensure we can load from string fragments.""" 33 | doc = parser.parse('{"hello": "world"}') 34 | assert doc.as_dict() == {'hello': 'world'} 35 | 36 | 37 | def test_parse_empty_buffer(parser): 38 | """Ensure trying to parse an empty buffer returns an error consistent 39 | with attempting to parse an empty bytestring.""" 40 | # Issue #81 41 | with pytest.raises(ValueError) as bytes_exc: 42 | parser.parse(b'') 43 | 44 | with pytest.raises(ValueError) as buffer_exc: 45 | parser.parse(io.BytesIO(b'').getbuffer()) 46 | 47 | assert str(bytes_exc.value) == str(buffer_exc.value) 48 | 49 | 50 | def test_unicode_decode_error(parser, jsonexamples): 51 | """Ensure the parser raises encoding issues.""" 52 | # Not all implementations are equal. When using the byte-by-byte fallback 53 | # Implementation, a ValueError will be raised for improper tape structure. 54 | # When using most (all?) other implementations, the expected 55 | # UnicodeDecodeError will be raised instead. 56 | with pytest.raises((UnicodeDecodeError, ValueError)): 57 | parser.load( 58 | os.path.join( 59 | jsonexamples, 60 | 'test_parsing', 61 | 'n_array_invalid_utf8.json' 62 | ) 63 | ) 64 | 65 | 66 | def test_implementation(): 67 | """Ensure we can set, get, and list the Implementation.""" 68 | parser = simdjson.Parser() 69 | # Ensure a rubbish Implementation does not get set - simdjson does not do 70 | # a safety check, buy pysimdjson does. A break in this check will cause 71 | # a segfault. 72 | with pytest.raises(ValueError): 73 | parser.implementation = 'rubbish' 74 | 75 | # The generic, always-available Implementation. 76 | parser.implementation = 'fallback' 77 | parser.parse(b'{"hello": "world"}') 78 | 79 | assert parser.implementation[0] == 'fallback' 80 | 81 | implementations = [imp[0] for imp in parser.get_implementations()] 82 | assert 'fallback' in implementations 83 | -------------------------------------------------------------------------------- /tests/test_safety.py: -------------------------------------------------------------------------------- 1 | import gc 2 | import pytest 3 | 4 | 5 | def test_parser_reuse(parser): 6 | """ 7 | In the simdjson DOM model, if the parser is re-used, existing Object and 8 | Array wrappers may point either into freed memory, random memory, or the 9 | new document. pysimdjson should prevent this. 10 | """ 11 | p = parser.parse(b'{"deep": {"object": "lifecycle"}}') 12 | # Not a typo, keep this, we're keeping the object alive for the next call 13 | # to parse(). 14 | p 15 | 16 | # Assuming our safety checks are working, this will see that an object (p) 17 | # still exists that references the parser document and will refuse to 18 | # parse. 19 | with pytest.raises(RuntimeError): 20 | parser.parse(b'{"deep": {"lifecycle": "object"}}') 21 | 22 | # Explicitly delete the existing object pointing into the parser. 23 | del p 24 | # ... and force a garbage collection for PyPy. 25 | gc.collect() 26 | 27 | # ... and try re-using the parser again. 28 | parser.parse(b'{"deep": {"lifecycle": "object"}}') 29 | -------------------------------------------------------------------------------- /tests/test_shim.py: -------------------------------------------------------------------------------- 1 | import json 2 | import simdjson 3 | 4 | 5 | def _test_load(): 6 | """Ensure basic usage of load is the same.""" 7 | # We don't use a binary file here because pre-py3.6 the built-in couldn't 8 | # handle bytes. 9 | with open('jsonexamples/canada.json', 'r') as fin: 10 | builtin_json = json.load(fin) 11 | 12 | with open('jsonexamples/canada.json', 'rb') as fin: 13 | simd_json = simdjson.load(fin) 14 | 15 | assert builtin_json == simd_json 16 | 17 | 18 | def _test_loads(): 19 | """Ensure basic usage of loads is the same.""" 20 | # We don't use a binary file here because pre-py3.6 the built-in couldn't 21 | # handle bytes. 22 | with open('jsonexamples/canada.json', 'r') as fin: 23 | content = fin.read() 24 | 25 | assert json.loads(content) == simdjson.loads(content) 26 | --------------------------------------------------------------------------------