Skip to content

Commit

Permalink
Revert "Optimize hyper module load time using a lazy re.compile for r…
Browse files Browse the repository at this point in the history
…fc3986 regexps"

This reverts commit 86e8571.
  • Loading branch information
cvaroqui committed Oct 23, 2020
1 parent 4f7ef2f commit 43f2cf0
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 198 deletions.
27 changes: 13 additions & 14 deletions opensvc/foreign/rfc3986/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import re

from . import abnf_regexp
from utilities.string import _lazy__lazy_re_compile

# These are enumerated for the named tuple used as a superclass of
# URIReference
Expand All @@ -48,9 +47,9 @@
UNRESERVED_CHARS = abnf_regexp.UNRESERVED_CHARS_SET
NON_PCT_ENCODED = abnf_regexp.NON_PCT_ENCODED_SET

URI_MATCHER = _lazy__lazy_re_compile(abnf_regexp.URL_PARSING_RE)
URI_MATCHER = re.compile(abnf_regexp.URL_PARSING_RE)

SUBAUTHORITY_MATCHER = _lazy_re_compile((
SUBAUTHORITY_MATCHER = re.compile((
'^(?:(?P<userinfo>{0})@)?' # userinfo
'(?P<host>{1})' # host
':?(?P<port>{2})?$' # port
Expand All @@ -59,38 +58,38 @@
abnf_regexp.PORT_RE))


HOST_MATCHER = _lazy_re_compile('^' + abnf_regexp.HOST_RE + '$')
IPv4_MATCHER = _lazy_re_compile('^' + abnf_regexp.IPv4_RE + '$')
IPv6_MATCHER = _lazy_re_compile(r'^\[' + abnf_regexp.IPv6_ADDRZ_RFC4007_RE + r'\]$')
HOST_MATCHER = re.compile('^' + abnf_regexp.HOST_RE + '$')
IPv4_MATCHER = re.compile('^' + abnf_regexp.IPv4_RE + '$')
IPv6_MATCHER = re.compile(r'^\[' + abnf_regexp.IPv6_ADDRZ_RFC4007_RE + r'\]$')

# Used by host validator
IPv6_NO_RFC4007_MATCHER = _lazy_re_compile(r'^\[%s\]$' % (
IPv6_NO_RFC4007_MATCHER = re.compile(r'^\[%s\]$' % (
abnf_regexp.IPv6_ADDRZ_RE
))

# Matcher used to validate path components
PATH_MATCHER = _lazy_re_compile(abnf_regexp.PATH_RE)
PATH_MATCHER = re.compile(abnf_regexp.PATH_RE)


# ##################################
# Query and Fragment Matcher Section
# ##################################

QUERY_MATCHER = _lazy_re_compile(abnf_regexp.QUERY_RE)
QUERY_MATCHER = re.compile(abnf_regexp.QUERY_RE)

FRAGMENT_MATCHER = QUERY_MATCHER

# Scheme validation, see: http://tools.ietf.org/html/rfc3986#section-3.1
SCHEME_MATCHER = _lazy_re_compile('^{0}$'.format(abnf_regexp.SCHEME_RE))
SCHEME_MATCHER = re.compile('^{0}$'.format(abnf_regexp.SCHEME_RE))

RELATIVE_REF_MATCHER = _lazy_re_compile(r'^%s(\?%s)?(#%s)?$' % (
RELATIVE_REF_MATCHER = re.compile(r'^%s(\?%s)?(#%s)?$' % (
abnf_regexp.RELATIVE_PART_RE,
abnf_regexp.QUERY_RE,
abnf_regexp.FRAGMENT_RE,
))

# See http://tools.ietf.org/html/rfc3986#section-4.3
ABSOLUTE_URI_MATCHER = _lazy_re_compile(r'^%s:%s(\?%s)?$' % (
ABSOLUTE_URI_MATCHER = re.compile(r'^%s:%s(\?%s)?$' % (
abnf_regexp.COMPONENT_PATTERN_DICT['scheme'],
abnf_regexp.HIER_PART_RE,
abnf_regexp.QUERY_RE[1:-1],
Expand All @@ -100,9 +99,9 @@
# IRIs / RFC 3987
# ###############

IRI_MATCHER = _lazy_re_compile(abnf_regexp.URL_PARSING_RE, re.UNICODE)
IRI_MATCHER = re.compile(abnf_regexp.URL_PARSING_RE, re.UNICODE)

ISUBAUTHORITY_MATCHER = _lazy_re_compile((
ISUBAUTHORITY_MATCHER = re.compile((
u'^(?:(?P<userinfo>{0})@)?' # iuserinfo
u'(?P<host>{1})' # ihost
u':?(?P<port>{2})?$' # port
Expand Down
166 changes: 0 additions & 166 deletions opensvc/utilities/lazy.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
import operator

empty = object()

def lazy(fn):
"""
A decorator for on-demand initialization of a property
Expand Down Expand Up @@ -54,166 +50,4 @@ def unset_lazy(self, attr):
delattr(self, attr_name)


def new_method_proxy(func):
def inner(self, *args):
if self._wrapped is empty:
self._setup()
return func(self._wrapped, *args)
return inner


class LazyObject:
"""
A wrapper for another class that can be used to delay instantiation of the
wrapped class.
By subclassing, you have the opportunity to intercept and alter the
instantiation. If you don't need to do that, use SimpleLazyObject.
"""

# Avoid infinite recursion when tracing __init__ (#19456).
_wrapped = None

def __init__(self):
# Note: if a subclass overrides __init__(), it will likely need to
# override __copy__() and __deepcopy__() as well.
self._wrapped = empty

__getattr__ = new_method_proxy(getattr)

def __setattr__(self, name, value):
if name == "_wrapped":
# Assign to __dict__ to avoid infinite __setattr__ loops.
self.__dict__["_wrapped"] = value
else:
if self._wrapped is empty:
self._setup()
setattr(self._wrapped, name, value)

def __delattr__(self, name):
if name == "_wrapped":
raise TypeError("can't delete _wrapped.")
if self._wrapped is empty:
self._setup()
delattr(self._wrapped, name)

def _setup(self):
"""
Must be implemented by subclasses to initialize the wrapped object.
"""
raise NotImplementedError('subclasses of LazyObject must provide a _setup() method')

# Because we have messed with __class__ below, we confuse pickle as to what
# class we are pickling. We're going to have to initialize the wrapped
# object to successfully pickle it, so we might as well just pickle the
# wrapped object since they're supposed to act the same way.
#
# Unfortunately, if we try to simply act like the wrapped object, the ruse
# will break down when pickle gets our id(). Thus we end up with pickle
# thinking, in effect, that we are a distinct object from the wrapped
# object, but with the same __dict__. This can cause problems (see #25389).
#
# So instead, we define our own __reduce__ method and custom unpickler. We
# pickle the wrapped object as the unpickler's argument, so that pickle
# will pickle it normally, and then the unpickler simply returns its
# argument.
def __reduce__(self):
if self._wrapped is empty:
self._setup()
return (unpickle_lazyobject, (self._wrapped,))

def __copy__(self):
if self._wrapped is empty:
# If uninitialized, copy the wrapper. Use type(self), not
# self.__class__, because the latter is proxied.
return type(self)()
else:
# If initialized, return a copy of the wrapped object.
return copy.copy(self._wrapped)

def __deepcopy__(self, memo):
if self._wrapped is empty:
# We have to use type(self), not self.__class__, because the
# latter is proxied.
result = type(self)()
memo[id(self)] = result
return result
return copy.deepcopy(self._wrapped, memo)

__bytes__ = new_method_proxy(bytes)
__str__ = new_method_proxy(str)
__bool__ = new_method_proxy(bool)

# Introspection support
__dir__ = new_method_proxy(dir)

# Need to pretend to be the wrapped class, for the sake of objects that
# care about this (especially in equality tests)
__class__ = property(new_method_proxy(operator.attrgetter("__class__")))
__eq__ = new_method_proxy(operator.eq)
__lt__ = new_method_proxy(operator.lt)
__gt__ = new_method_proxy(operator.gt)
__ne__ = new_method_proxy(operator.ne)
__hash__ = new_method_proxy(hash)

# List/Tuple/Dictionary methods support
__getitem__ = new_method_proxy(operator.getitem)
__setitem__ = new_method_proxy(operator.setitem)
__delitem__ = new_method_proxy(operator.delitem)
__iter__ = new_method_proxy(iter)
__len__ = new_method_proxy(len)
__contains__ = new_method_proxy(operator.contains)


def unpickle_lazyobject(wrapped):
"""
Used to unpickle lazy objects. Just return its argument, which will be the
wrapped object.
"""
return wrapped

class SimpleLazyObject(LazyObject):
"""
A lazy object initialized from any function.
Designed for compound objects of unknown type. For builtins or objects of
known type, use django.utils.functional.lazy.
"""
def __init__(self, func):
"""
Pass in a callable that returns the object to be wrapped.
If copies are made of the resulting SimpleLazyObject, which can happen
in various circumstances within Django, then you must ensure that the
callable can be safely run more than once and will return the same
value.
"""
self.__dict__['_setupfunc'] = func
super().__init__()

def _setup(self):
self._wrapped = self._setupfunc()

# Return a meaningful representation of the lazy object for debugging
# without evaluating the wrapped object.
def __repr__(self):
if self._wrapped is empty:
repr_attr = self._setupfunc
else:
repr_attr = self._wrapped
return '<%s: %r>' % (type(self).__name__, repr_attr)

def __copy__(self):
if self._wrapped is empty:
# If uninitialized, copy the wrapper. Use SimpleLazyObject, not
# self.__class__, because the latter is proxied.
return SimpleLazyObject(self._setupfunc)
else:
# If initialized, return a copy of the wrapped object.
return copy.copy(self._wrapped)

def __deepcopy__(self, memo):
if self._wrapped is empty:
# We have to use SimpleLazyObject, not self.__class__, because the
# latter is proxied.
result = SimpleLazyObject(self._setupfunc)
memo[id(self)] = result
return result
return copy.deepcopy(self._wrapped, memo)
18 changes: 0 additions & 18 deletions opensvc/utilities/string/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,21 +54,3 @@ def is_glob(text):
return True
return False


def _lazy_re_compile(regex, flags=0):
"""
Lazily compile a regex with flags.
"""
import re
from utilities.lazy import SimpleLazyObject
def _compile():
# Compile the regex if it was not passed pre-compiled.
if isinstance(regex, (str, bytes)):
return re.compile(regex, flags)
else:
assert not flags, (
'flags must be empty if regex is passed pre-compiled'
)
return regex
return SimpleLazyObject(_compile)

0 comments on commit 43f2cf0

Please sign in to comment.