Skip to content

re.error: incomplete escape \U at position 2 #40

@charlie-dufort

Description

@charlie-dufort

Error raised on Windows, especially when executing some code with a dependency to config2py.
Comes from dol.naming.mk_pattern_from_template_and_format_dict.

Example

Executing from config2py import simple_config_getter raises:

---------------------------------------------------------------------------
error                                     Traceback (most recent call last)
Untitled-1.ipynb Cell 5 line 1
----> [1](vscode-notebook-cell:Untitled-1.ipynb?jupyter-notebook#X11sdW50aXRsZWQ%3D?line=0) from config2py import simple_config_getter, get_configs_folder_for_app

File ~\OneDrive - Analog Devices, Inc\Python\OtoSense\config2py\config2py\__init__.py:4
      1 """Tools to read and write configurations from various sources and formats"""
      3 from config2py.s_configparser import ConfigStore, ConfigReader
----> 4 from config2py.tools import (
      5     extract_exports,
      6     get_configs_local_store,
      7     simple_config_getter,
      8     config_getter,
      9     local_configs,
     10     Configs,  # user-customized configs store class (default is TextFiles)
     11     configs,  # user-customized configs store instance (default is local_configs)
     12     # or make configs be more of a default get_configs "chained Mapping"
     13 )
     14 from config2py.base import get_config, user_gettable, sources_chainmap
     15 from config2py.util import (
     16     ask_user_for_input,
     17     get_app_data_folder,
   (...)
     20     parse_assignments_from_py_source,
     21 )

File ~\OneDrive - Analog Devices, Inc\Python\OtoSense\config2py\config2py\tools.py:88
     84     return config_getter
     87 # Make a ready-to-use config getter, using the defaults
---> 88 config_getter = simple_config_getter()
     90 # --------------------------------------------------------------------
     91 # Ready to import instances
     92 #
   (...)
     97 #   Note: Perhaps there's no need for a class.
     98 #   Maybe just a function that returns a store
     99 Configs = TextFiles  # TODO: deprecate

File ~\OneDrive - Analog Devices, Inc\Python\OtoSense\config2py\config2py\tools.py:71, in simple_config_getter(configs_src, first_look_in_env_vars, ask_user_if_key_not_found, config_store_factory)
     52 """Make a simple config getter from a "central" config source specification.
     53 
     54 The purpose of this function is to implement a common pattern of getting configs:
   (...)
     68     and returns the central config store
     69 """
     70 # TODO: Resource validation block. Refactor! And add tool to config2py if not there
---> 71 central_configs = config_store_factory(configs_src)
     72 sources = []
     73 if first_look_in_env_vars:

File ~\OneDrive - Analog Devices, Inc\Python\OtoSense\config2py\config2py\tools.py:24, in get_configs_local_store(config_src)
     16 """Get the local store of configs.
     17 
     18 :param config_src: A specification of the local config store. By default:
   (...)
     21     If it's a string, it's assumed to be an app name, from which to create a folder
     22 """
     23 if os.path.isdir(config_src):
---> 24     return TextFiles(config_src)
     25 elif os.path.isfile(config_src):
     26     # TODO: Not tested
     27     # TODO: Make this open-closed plug-in via routing argument
     28     _, extension = os.path.splitext(config_src)

File ~\OneDrive - Analog Devices, Inc\Python\OtoSense\dol\dol\paths.py:688, in mk_relative_path_store.<locals>.__init__(self, *args, **kwargs)
    686 @wraps(store_cls.__init__)
    687 def __init__(self, *args, **kwargs):
--> 688     Store.__init__(self, store=store_cls(*args, **kwargs))
    689     prefix = recursive_get_attr(self.store, prefix_attr, '')
    690     setattr(
    691         self, prefix_attr, prefix
    692     )

File ~\OneDrive - Analog Devices, Inc\Python\OtoSense\dol\dol\filesys.py:215, in FileSysCollection.__init__(self, rootdir, subpath, pattern_for_field, max_levels, include_hidden, assert_rootdir_existence)
    213 self.rootdir = ensure_slash_suffix(rootdir)
    214 self.subpath = subpath
--> 215 self._key_pattern = mk_pattern_from_template_and_format_dict(
    216     os.path.join(rootdir, subpath), pattern_for_field
    217 )
    218 self._max_levels = max_levels
    219 self.include_hidden = include_hidden

File ~\OneDrive - Analog Devices, Inc\Python\OtoSense\dol\dol\naming.py:325, in mk_pattern_from_template_and_format_dict(template, format_dict, sep)
    323 format_dict = mk_format_mapping_dict(format_dict, fields, sep=sep)
    324 named_capture_patterns = mk_named_capture_patterns(format_dict)
--> 325 return re.compile(template_to_pattern(named_capture_patterns, template))

File c:\Users\cdufort\AppData\Local\Programs\Python\Python311\Lib\re\__init__.py:227, in compile(pattern, flags)
    225 def compile(pattern, flags=0):
    226     "Compile a regular expression pattern, returning a Pattern object."
--> 227     return _compile(pattern, flags)

File c:\Users\cdufort\AppData\Local\Programs\Python\Python311\Lib\re\__init__.py:294, in _compile(pattern, flags)
    288     import warnings
    289     warnings.warn("The re.TEMPLATE/re.T flag is deprecated "
    290               "as it is an undocumented flag "
    291               "without an obvious purpose. "
    292               "Don't use it.",
    293               DeprecationWarning)
--> 294 p = _compiler.compile(pattern, flags)
    295 if not (flags & DEBUG):
    296     if len(_cache) >= _MAXCACHE:
    297         # Drop the oldest item

File c:\Users\cdufort\AppData\Local\Programs\Python\Python311\Lib\re\_compiler.py:743, in compile(p, flags)
    741 if isstring(p):
    742     pattern = p
--> 743     p = _parser.parse(p, flags)
    744 else:
    745     pattern = None

File c:\Users\cdufort\AppData\Local\Programs\Python\Python311\Lib\re\_parser.py:980, in parse(str, flags, state)
    977 state.flags = flags
    978 state.str = str
--> 980 p = _parse_sub(source, state, flags & SRE_FLAG_VERBOSE, 0)
    981 p.state.flags = fix_flags(str, p.state.flags)
    983 if source.next is not None:

File c:\Users\cdufort\AppData\Local\Programs\Python\Python311\Lib\re\_parser.py:455, in _parse_sub(source, state, verbose, nested)
    453 start = source.tell()
    454 while True:
--> 455     itemsappend(_parse(source, state, verbose, nested + 1,
    456                        not nested and not items))
    457     if not sourcematch("|"):
    458         break

File c:\Users\cdufort\AppData\Local\Programs\Python\Python311\Lib\re\_parser.py:539, in _parse(source, state, verbose, nested, first)
    536         continue
    538 if this[0] == "\\":
--> 539     code = _escape(source, this, state)
    540     subpatternappend(code)
    542 elif this not in SPECIAL_CHARS:

File c:\Users\cdufort\AppData\Local\Programs\Python\Python311\Lib\re\_parser.py:393, in _escape(source, escape, state)
    391 escape += source.getwhile(8, HEXDIGITS)
    392 if len(escape) != 10:
--> 393     raise source.error("incomplete escape %s" % escape, len(escape))
    394 c = int(escape[2:], 16)
    395 chr(c) # raise ValueError for invalid code

error: incomplete escape \U at position 2

Workaround

Add re.escape to the regex to compile: return re.compile(re.escape(template_to_pattern(named_capture_patterns, template)))

I guess this annihilates some of the functionnality of mk_pattern_from_template_and_format_dict, but that's the only thing I have found to go around this error.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions