simplere / simplere /

A simpler way to access and use regular expressions. As a bonus,
also simpler access to globs.

from mementos import MementoMetaclass, with_metaclass    
import sys, re, fnmatch

_PY3 = sys.version_info[0] > 2
if _PY3:
    basestring = str

class ReMatch(object):
    An easier-to-use proxy for regular expression match objects. Ideally this
    would be a subclass of the re module's match object, but their type
    ``_sre.SRE_Match`` appears to be unsubclassable
    Thus, ReMatch is a proxy exposes the match object's numeric (positional) and
    named groups through indices and attributes. If a named group has the same
    name as a match object method or property, it takes precedence. Either
    change the name of the match group or access the underlying property thus:
    def __init__(self, match):
        self._match = match
        self._groupdict = match.groupdict()
    def __getattr__(self, name):
        if name in self.__dict__:
            return self.__dict__[name]
        if name in self._groupdict:
            return self._groupdict[name]
            return getattr(self._match, name)
        except AttributeError:
            return AttributeError("no such attribute '{}'".format(name))

    def __getitem__(self, index):

function_type = type(lambda: True)   # define our own because not def'd in py26

def is_function(obj):
    Determines: Is obj a function?
    return isinstance(obj, function_type)

def regrouped(f):
    Takes a function f that is supposed to get _sre.SRE_Match objects and
    wraps each of those with a ReMatch proxy. If not a function (ie, probably
    a string, then just return it.)
    if not is_function(f):
        return f
    def regrouped_fn(match):
        re_match = ReMatch(match)
        return f(re_match)
    return regrouped_fn

class Re(with_metaclass(MementoMetaclass, object)):

    # convenience copy of re flag constants
    DEBUG      = re.DEBUG
    I          = re.I
    L          = re.L
    LOCALE     = re.LOCALE
    M          = re.M
    S          = re.S
    DOTALL     = re.DOTALL
    U          = re.U
    X          = re.X
    _ = None

    def __init__(self, pattern, flags=0):
        self.pattern    = pattern
        self.flags      = flags = pattern if type(pattern).__name__ == 'SRE_Pattern' else re.compile(pattern, flags)
        self.groups     =
        self.groupindex =
        # can't use isinstance() test on pattern because _sre objects are damn hard to
        # import or wrangle. Name test is best I know how to do.
    def _regroup(self, m):
        Given an _sre.SRE_Match object, create and return a corresponding
        ReMatch object.
        result = ReMatch(m) if m else m
        Re._ = result
        return result

    def __contains__(self, item):
        if not isinstance(item, basestring):
             item = str(item)
        return self._regroup(
    ### methods that return ReMatch objects
    def search(self, *args, **kwargs):
        return self._regroup(*args, **kwargs))

    def match(self, *args, **kwargs):
        return self._regroup(*args, **kwargs))
    def finditer(self, *args, **kwargs):
        for m in*args, **kwargs):
            yield self._regroup(m)
    ### methods that don't need ReMatch objects
    def findall(self, *args, **kwargs):
        return*args, **kwargs)
    def split(self, *args, **kwargs):
        return*args, **kwargs)
    def sub(self, repl, *args, **kwargs):
        return, *args, **kwargs)
    def subn(self, repl, *args, **kwargs):
        return, *args, **kwargs)
    def escape(self, *args, **kwargs):
        return*args, **kwargs)

class Glob(with_metaclass(MementoMetaclass, object)):
    An item matches a Glob via Unix filesystem glob semantics.
    E.g. 'alpha' matches 'a*' and 'a????' but not 'b*'

    def __init__(self, pattern):
        self.pattern = pattern
    def __contains__(self, item):
        return fnmatch.fnmatch(str(item), self.pattern)