1

I'm basically attempting py2/3 compatibility by trying to add a a fullmatch method to Python2 re compiled patterns.

I've seen https://stackoverflow.com/a/2982/2694385 on how to add an attribute to an existing instance. I'm creating the method as given in https://stackoverflow.com/a/30212799/2694385.

Example code

import re
import six


regex = re.compile('some pattern')  # Better if we keep this same

if six.PY2:
    def fullmatch(self_regex, string, flags=0):
        return self_regex.match(string, flags=flags)

    regex = re.compile(r'(?:' + regex.pattern + r')\Z', flags=regex.flags)

    import types

    bound = types.MethodType(fullmatch, regex)
    # AttributeError here. None of the following three lines work
    regex.fullmatch = bound
    regex.__setattr__('fullmatch', bound)
    setattr(regex, 'fullmatch', bound)
user80551
  • 1,134
  • 2
  • 15
  • 26
  • @zwer Can you make it an answer. I have ended up doing `re.fullmatch = fullmatch` for now, and using `re.fullmatch(regex, string)` instead of `regex.fullmatch(string)` for now. – user80551 Jun 27 '17 at 07:20

2 Answers2

0

That ain't gonna work - regex objects are created on the C side and they don't represent your regular instances so you cannot modify their signature from within Python. For example, if you try to extend _sre.SRE_Pattern:

import _sre

class CustomPattern(_sre.SRE_Pattern): pass

You'll get an AttributeError complaining that such object doesn't exist in the _sre module. If you try to cheat it with:

import re

tmp_pattern = re.compile("")
sre_pat = type(tmp_pattern)

class CustomPattern(sre_pat): pass

it will give you a TypeError complaining that _sre.SRE_Pattern (which now 'temporarily' exists as it's being created ad-hoc) is not an acceptable base type.

What you can do instead is to create a full wrapper around the re module (or at least add the missing structures to it) and handle the Python version differences on the Python's side, although I think it's just not worth it.

P.S. If you're not using six anywhere else, there no reason for the overhead just to check your Python version - you can use sys.version_info.major < 3 instead.

zwer
  • 24,943
  • 3
  • 48
  • 66
0

See nlpia.regexes.Pattern for something similar to what you want -- a Frankenstein mashup of _sre.Pattern with a fullmatch() method. This monkey-patching "inheritance" approach works in Python 2 and 3.

import re
import regex

class Pattern:
    """ "Inherits" _sre.SRE_Pattern and adds .fullmatch() method

    >>> pattern = Pattern('Aaron[ ]Swartz')
    >>> pattern.match('Aaron Swartz')
    <_sre.SRE_Match object; span=(0, 12), match='Aaron Swartz'>
    >>> pattern.fullmatch('Aaron Swartz!!')
    >>> pattern.match('Aaron Swartz!!')
    <_sre.SRE_Match object; span=(0, 12), match='Aaron Swartz'>
    """
    def __init__(self, pattern):
        self._compiled_pattern = re.compile(pattern)
        for name in dir(self._compiled_pattern):
            if not name in set(('__class__', '__init__', 'fullmatch')):
                attr = getattr(self._compiled_pattern, name)
                setattr(self, name, attr)

def fullmatch(self, *args, **kwargs):
    return regex.fullmatch(self._compiled_pattern.pattern, *args, **kwargs)
hobs
  • 18,473
  • 10
  • 83
  • 106