diff --git a/README.rst b/README.rst index e84d097..e730f7a 100644 --- a/README.rst +++ b/README.rst @@ -32,7 +32,7 @@ capabilities. Latest version documentation is automatically rendered by `Read the Docs`__. -__ http://json-schema.org/documentation.html +__ http://json-schema.org/docs.html __ https://python-rapidjson.readthedocs.io/en/latest/ @@ -123,3 +123,27 @@ some aspects. See `this section`__ in the documentation for further details. __ https://python-rapidjson.readthedocs.io/en/latest/quickstart.html#incompatibilities .. _RapidJSON: http://rapidjson.org/ + +Regex Engine +------------ + +By default RapidJson uses a simple NFA regular expression engine for it's schema +validation, see the section `RapidJson Regular Expression`__, it is possible +to use ``std::regex`` instead of the original implementation by setting the +environmental variable ``RAPIDJSON_SCHEMA_USE_STDREGEX=1``. + +.. code-block:: bash + + $ export RAPIDJSON_SCHEMA_USE_STDREGEX=1 + $ pip install python-rapidjson + +After installation, you can verify that std::regex is being used by checking the +constant in the module: + +.. code-block:: python + + >>> import rapidjson + >>> rapidjson.RAPIDJSON_SCHEMA_USE_STDREGEX + 1 + +__ http://rapidjson.org/md_doc_schema.html#Regex diff --git a/docs/validator.rst b/docs/validator.rst index 53b5936..7d719be 100644 --- a/docs/validator.rst +++ b/docs/validator.rst @@ -75,3 +75,27 @@ Traceback (most recent call last): File "", line 1, in rapidjson.JSONDecodeError: Invalid JSON + +============ +Regex Engine +============ +By default RapidJson uses a simple NFA regular expression engine for it's schema +validation, see the section `RapidJson Regular Expression`__, it is possible +to use ``std::regex`` instead of the original implementation by setting the +environmental variable ``RAPIDJSON_SCHEMA_USE_STDREGEX=1``. + +.. code-block:: bash + + $ export RAPIDJSON_SCHEMA_USE_STDREGEX=1 + $ pip install python-rapidjson + +After installation, you can verify that std::regex is being used by checking the +constant in the module: + +.. code-block:: python + + >>> import rapidjson + >>> rapidjson.RAPIDJSON_SCHEMA_USE_STDREGEX + 1 + +__ http://rapidjson.org/md_doc_schema.html#Regex diff --git a/rapidjson.cpp b/rapidjson.cpp index 40ce8fa..a858e75 100644 --- a/rapidjson.cpp +++ b/rapidjson.cpp @@ -4046,6 +4046,7 @@ module_exec(PyObject* m) MM_COERCE_KEYS_TO_STRINGS) || PyModule_AddIntConstant(m, "MM_SKIP_NON_STRING_KEYS", MM_SKIP_NON_STRING_KEYS) || PyModule_AddIntConstant(m, "MM_SORT_KEYS", MM_SORT_KEYS) + || PyModule_AddIntConstant(m, "RAPIDJSON_SCHEMA_USE_STDREGEX", RAPIDJSON_SCHEMA_USE_STDREGEX) || PyModule_AddStringConstant(m, "__version__", STRINGIFY(PYTHON_RAPIDJSON_VERSION)) diff --git a/setup.py b/setup.py index 085fdcb..85371ce 100644 --- a/setup.py +++ b/setup.py @@ -8,6 +8,7 @@ import os.path import sys +from os import environ try: from setuptools import setup, Extension @@ -52,13 +53,25 @@ with open('CHANGES.rst', encoding='utf-8') as f: CHANGES = f.read() +if environ.get('RAPIDJSON_SCHEMA_USE_STDREGEX', None): + RAPIDJSON_SCHEMA_USE_STDREGEX = 1 + RAPIDJSON_SCHEMA_USE_INTERNALREGEX = 0 +else: + RAPIDJSON_SCHEMA_USE_STDREGEX = 0 + RAPIDJSON_SCHEMA_USE_INTERNALREGEX = 1 + extension_options = { 'sources': ['./rapidjson.cpp'], 'include_dirs': [rj_include_dir], - 'define_macros': [('PYTHON_RAPIDJSON_VERSION', VERSION)], + 'define_macros': [ + ('PYTHON_RAPIDJSON_VERSION', VERSION), + ('RAPIDJSON_SCHEMA_USE_INTERNALREGEX', RAPIDJSON_SCHEMA_USE_INTERNALREGEX), + ('RAPIDJSON_SCHEMA_USE_STDREGEX', RAPIDJSON_SCHEMA_USE_STDREGEX), + ], 'depends': ['./rapidjson_exact_version.txt'], } + if os.path.exists('rapidjson_exact_version.txt'): with open('rapidjson_exact_version.txt', encoding='utf-8') as f: extension_options['define_macros'].append( diff --git a/tests/test_validator.py b/tests/test_validator.py index 001cc1f..3aeaf6e 100644 --- a/tests/test_validator.py +++ b/tests/test_validator.py @@ -65,3 +65,22 @@ def test_invalid(schema, json, details): def test_additional_and_pattern_properties_valid(schema, json): validate = rj.Validator(schema) validate(json) + + +def test_std_regex_used(): + schema = rj.dumps({ + "type": "object", + "patternProperties": { + "^(?!a).+": { + "type": "string" + } + } + }) + validate = rj.Validator(schema) + validate('{"b": "A string"}') + if rj.RAPIDJSON_SCHEMA_USE_STDREGEX: + with pytest.raises(ValueError) as error: + validate('{"b": 1}') + assert error.value.args == ('patternProperties', '#', '#/b') + else: + validate('{"b": 1}') diff --git a/typings/rapidjson/__init__.pyi b/typings/rapidjson/__init__.pyi index e4bab51..a8a5603 100644 --- a/typings/rapidjson/__init__.pyi +++ b/typings/rapidjson/__init__.pyi @@ -12,6 +12,8 @@ import typing as t __rapidjson_exact_version__: str __rapidjson_version__: str +RAPIDJSON_SCHEMA_USE_STDREGEX: bool + _JSONType = t.Union[ str,