Skip to content

Commit 86549ca

Browse files
committed
[GR-14857] [GH-61] Improve compliance of class SRE_Pattern.
PullRequest: graalpython/467
2 parents 9d4b9ce + 10d4d6f commit 86549ca

File tree

4 files changed

+83
-4
lines changed

4 files changed

+83
-4
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_re.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,14 @@ def test_symbolic_groups(self):
254254
self.checkPatternError(r'(?(-1))', "bad character in group name '-1'", 3)
255255
self.assertEqual(re.match(pat, 'xc8yz').span(), (0, 5))
256256

257+
def test_re_subn(self):
258+
self.assertEqual(re.subn("(?i)b+", "x", "bbbb BBBB"), ('x x', 2))
259+
self.assertEqual(re.subn("b+", "x", "bbbb BBBB"), ('x BBBB', 1))
260+
self.assertEqual(re.subn("b+", "x", "xyz"), ('xyz', 0))
261+
self.assertEqual(re.subn("b*", "x", "xyz"), ('xxxyxzx', 4))
262+
self.assertEqual(re.subn("b*", "x", "xyz", 2), ('xxxyz', 2))
263+
self.assertEqual(re.subn("b*", "x", "xyz", count=2), ('xxxyz', 2))
264+
257265
def test_re_split(self):
258266
for string in ":a:b::c", S(":a:b::c"):
259267
self.assertTypedEqual(re.split(":", string),
@@ -358,6 +366,36 @@ def test_ignore_case_set(self):
358366
# self.assertTrue(re.match(r'[19\ufb05]', '\ufb06', re.I))
359367
# self.assertTrue(re.match(r'[19\ufb06]', '\ufb05', re.I))
360368

369+
def test_getattr(self):
370+
self.assertEqual(re.compile("(?i)(a)(b)").pattern, "(?i)(a)(b)")
371+
# TODO at the moment, we use slightly different default flags
372+
#self.assertEqual(re.compile("(?i)(a)(b)").flags, re.I | re.U)
373+
374+
# TODO re-enable this test once TRegex provides this property
375+
#self.assertEqual(re.compile("(?i)(a)(b)").groups, 2)
376+
self.assertEqual(re.compile("(?i)(a)(b)").groupindex, {})
377+
self.assertEqual(re.compile("(?i)(?P<first>a)(?P<other>b)").groupindex,
378+
{'first': 1, 'other': 2})
379+
380+
self.assertEqual(re.match("(a)", "a").pos, 0)
381+
self.assertEqual(re.match("(a)", "a").endpos, 1)
382+
self.assertEqual(re.match("(a)", "a").string, "a")
383+
384+
# TODO not yet supported
385+
#self.assertEqual(re.match("(a)", "a").regs, ((0, 1), (0, 1)))
386+
387+
self.assertTrue(re.match("(a)", "a").re)
388+
389+
# Issue 14260. groupindex should be non-modifiable mapping.
390+
p = re.compile(r'(?i)(?P<first>a)(?P<other>b)')
391+
self.assertEqual(sorted(p.groupindex), ['first', 'other'])
392+
self.assertEqual(p.groupindex['other'], 2)
393+
394+
if sys.version_info.minor >= 6:
395+
with self.assertRaises(TypeError):
396+
p.groupindex['other'] = 0
397+
self.assertEqual(p.groupindex['other'], 2)
398+
361399
def test_backreference(self):
362400
compiled = re.compile(r"(.)\1")
363401
self.assertTrue(compiled.match("11"))

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/dict/DictBuiltins.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes;
5959
import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.ContainsKeyNode;
6060
import com.oracle.graal.python.builtins.objects.function.PKeyword;
61+
import com.oracle.graal.python.builtins.objects.mappingproxy.PMappingproxy;
6162
import com.oracle.graal.python.builtins.objects.str.PString;
6263
import com.oracle.graal.python.nodes.PGuards;
6364
import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
@@ -341,6 +342,12 @@ Object doDictDict(PDict self, PDict other,
341342
return equalsNode.execute(self.getDictStorage(), other.getDictStorage());
342343
}
343344

345+
@Specialization
346+
Object doDictProxy(PDict self, PMappingproxy other,
347+
@Cached("create()") HashingStorageNodes.EqualsNode equalsNode) {
348+
return equalsNode.execute(self.getDictStorage(), other.getDictStorage());
349+
}
350+
344351
@Fallback
345352
@SuppressWarnings("unused")
346353
PNotImplemented doGeneric(Object self, Object other) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mappingproxy/MappingproxyBuiltins.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import static com.oracle.graal.python.nodes.SpecialMethodNames.ITEMS;
2929
import static com.oracle.graal.python.nodes.SpecialMethodNames.KEYS;
3030
import static com.oracle.graal.python.nodes.SpecialMethodNames.__CONTAINS__;
31+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__EQ__;
3132
import static com.oracle.graal.python.nodes.SpecialMethodNames.__GETITEM__;
3233
import static com.oracle.graal.python.nodes.SpecialMethodNames.__INIT__;
3334
import static com.oracle.graal.python.nodes.SpecialMethodNames.__ITER__;
@@ -43,6 +44,7 @@
4344
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
4445
import com.oracle.graal.python.builtins.PythonBuiltins;
4546
import com.oracle.graal.python.builtins.objects.PNone;
47+
import com.oracle.graal.python.builtins.objects.PNotImplemented;
4648
import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes;
4749
import com.oracle.graal.python.builtins.objects.dict.PDict;
4850
import com.oracle.graal.python.builtins.objects.dict.PDictView;
@@ -53,6 +55,7 @@
5355
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
5456
import com.oracle.truffle.api.CompilerDirectives;
5557
import com.oracle.truffle.api.dsl.Cached;
58+
import com.oracle.truffle.api.dsl.Fallback;
5659
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
5760
import com.oracle.truffle.api.dsl.Specialization;
5861

@@ -198,4 +201,27 @@ public PDict copy(PMappingproxy proxy) {
198201
return factory().createDict(proxy.getDictStorage());
199202
}
200203
}
204+
205+
@Builtin(name = __EQ__, minNumOfPositionalArgs = 2)
206+
@GenerateNodeFactory
207+
public abstract static class EqNode extends PythonBinaryBuiltinNode {
208+
@Specialization
209+
Object doProxyProxy(PMappingproxy self, PMappingproxy other,
210+
@Cached("create()") HashingStorageNodes.EqualsNode equalsNode) {
211+
return equalsNode.execute(self.getDictStorage(), other.getDictStorage());
212+
}
213+
214+
@Specialization
215+
Object doProxDict(PMappingproxy self, PDict other,
216+
@Cached("create()") HashingStorageNodes.EqualsNode equalsNode) {
217+
return equalsNode.execute(self.getDictStorage(), other.getDictStorage());
218+
}
219+
220+
@Fallback
221+
@SuppressWarnings("unused")
222+
PNotImplemented doGeneric(Object self, Object other) {
223+
return PNotImplemented.NOT_IMPLEMENTED;
224+
}
225+
}
226+
201227
}

graalpython/lib-graalpython/_sre.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141

4242
from mmap import mmap
4343

44+
_mappingpoxy = type(type.__dict__)
45+
4446
def default(value, default):
4547
return default if not value else value
4648

@@ -235,6 +237,7 @@ def _is_bytes_like(object):
235237
class SRE_Pattern():
236238
def __init__(self, pattern, flags):
237239
self.__binary = isinstance(pattern, bytes)
240+
self.groups = 0
238241
self.pattern = pattern
239242
self.flags = flags
240243
flags_str = []
@@ -243,12 +246,13 @@ def __init__(self, pattern, flags):
243246
flags_str.append(char)
244247
self.flags_str = "".join(flags_str)
245248
self.__compiled_regexes = dict()
246-
self.groupindex = dict()
249+
groupindex = dict()
247250
if self.__tregex_compile(self.pattern).groups is not None:
248251
for group_name in dir(self.__tregex_compile(self.pattern).groups):
249252
groups = self.__tregex_compile(self.pattern).groups
250253
self.groups = _interop.__get_size__(_interop.__keys__(groups))
251-
self.groupindex[group_name] = groups[group_name]
254+
groupindex[group_name] = groups[group_name]
255+
self.groupindex = _mappingpoxy(groupindex)
252256

253257
def __check_input_type(self, input):
254258
if not isinstance(input, str) and not _is_bytes_like(input):
@@ -299,6 +303,7 @@ def _search(self, pattern, string, pos, endpos, sticky=False):
299303
pattern = self.__tregex_compile(pattern, self.flags_str + ("y" if sticky else ""))
300304
input_str = string
301305
if endpos == -1 or endpos >= len(string):
306+
endpos = len(string)
302307
result = tregex_call_exec(pattern.exec, input_str, min(pos, len(string) + 1))
303308
else:
304309
input_str = string[:endpos]
@@ -425,6 +430,9 @@ def __extract_groupname(self, repl, pos):
425430

426431

427432
def sub(self, repl, string, count=0):
433+
return self.subn(repl, string, count)[0]
434+
435+
def subn(self, repl, string, count=0):
428436
self.__check_input_type(string)
429437
n = 0
430438
pattern = self.__tregex_compile(self.pattern)
@@ -458,9 +466,9 @@ def sub(self, repl, string, count=0):
458466
pos = pos + 1
459467
result.append(string[pos:])
460468
if self.__binary:
461-
return b"".join(result)
469+
return (b"".join(result), n)
462470
else:
463-
return "".join(result)
471+
return ("".join(result), n)
464472

465473
def split(self, string, maxsplit=0):
466474
n = 0

0 commit comments

Comments
 (0)