pytest:使用re.escape()断言转义字符失败

我有一个使用re.escape()方法返回字符的函数。 在经验测试中,它似乎有效,我想用pytest对其进行测试。 但是我无法使测试正常工作,因此在尝试了几次之后,我尝试了类似的方法:

    def test_escape():
>       assert re.escape('!') == "\\!"
E       AssertionError: assert '!' == '\\!'
E         - !
E         + \!

test/test_e.py:6: AssertionError

我还与口译员进行了测试,该口译员的工作没有任何问题:

>>> re.escape('!') == '\\!'
True

使用“ -s”禁用pytest的输出,并尝试打印re.escape('!')的输出,我得到的是"!"而不是"\!",这在解释器上不会发生

我通过强制"\!"作为输出来尝试重新修补re.escape,它神奇地起作用。这显然不能解决我的问题,但可以用re.escape突出我不知道的某种问题

@pytest.fixture
def mock_escape(monkeypatch):
    monkeypatch.setattr(re,"escape",lambda x: "\\!")

def test_escape(mock_escape):
    assert re.escape('!') == "\\!"

...

test/test_e.py .

======================================== 1 passed in 0.07s =========================================
all test passed

出于好奇,我对原始功能执行了相同的操作(不进行monkeypatching,但编辑其返回值),即使在这种情况下,它也可以正常工作。 因此这并不是由于导入而发生的问题。

#编辑:# tmt发现,这是python或pytest版本的问题。 python 3.7.2和pytest 5.2.1出现问题。 python 3.6.3和pytest 4.5.0不会发生此问题 因此,几乎可以肯定是一个错误(我认为pytest更容易) 就像家伙回答的那样,这仅仅是re.escape()的行为更改

wenboylqx 回答:pytest:使用re.escape()断言转义字符失败

如果您查看re.py,将会看到escape()正在使用定义的特殊字符列表

_special_chars_map = {i: '\\' + chr(i) for i in b'()[]{}?*+-|^$\\.&~# \t\n\r\v\f'}

def escape(pattern):
    """
    Escape special characters in a string.
    """
    if isinstance(pattern,str):
        return pattern.translate(_special_chars_map)
    else:
        pattern = str(pattern,'latin1')
        return pattern.translate(_special_chars_map).encode('latin1')

并且!不包括在其中,因此re.escape('!')返回!,而不是\!

assert re.escape('[') == '\\['

例如可以使用。

更新

此答案适用于Python 3.7,适用于Python 3.6。 Pull request #1007更改了escape() pull source code

  

re.escape()现在仅转义特殊字符。

先前版本:

_alphanum_str = frozenset("_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890")
_alphanum_bytes = frozenset(b"_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890")

def escape(pattern):
    if isinstance(pattern,str):
        alphanum = _alphanum_str
        s = list(pattern)
        for i,c in enumerate(pattern):
            if c not in alphanum:
                if c == "\000":
                    s[i] = "\\000"
                else:
                    s[i] = "\\" + c
        return "".join(s)
    else:
        alphanum = _alphanum_bytes
        s = []
        esc = ord(b"\\")
        for c in pattern:
            if c in alphanum:
                s.append(c)
            else:
                if c == 0:
                    s.extend(b"\\000")
                else:
                    s.append(esc)
                    s.append(c)
        return bytes(s)

它于2017年4月13日进行了修改,因此在versions history re.escape('!') == '\\!'上运行应该可以在Python 3.6和更低版本上使用。

本文链接:https://www.f2er.com/3126178.html

大家都在问