Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d6192cd
merged from other brach
TheAnyKey May 7, 2020
a447b88
merges testutils
TheAnyKey May 8, 2020
84a6e8e
merged from TheAnyKey/p39_string_rem_pre_suffix
TheAnyKey May 8, 2020
da09370
Revert "merged from TheAnyKey/p39_string_rem_pre_suffix"
TheAnyKey May 8, 2020
f448654
Make PyArrayIter ThreadSafe
palaviv May 9, 2020
94e93f7
Make PyDeque, PyDequeIterator ThreadSafe
palaviv May 9, 2020
1b585bd
Make Reader ThreadSafe
palaviv May 9, 2020
75af7f6
Make PyBytesIO, PyStringIO ThreadSafe
palaviv May 9, 2020
4cf5178
Make PyItertools* ThreadSafe
palaviv May 9, 2020
ebf6b51
Merge pull request #1911 from TheAnyKey/TheAnyKey/p39_dict_union_pr
palaviv May 9, 2020
8466f45
Fix clippy error
palaviv May 9, 2020
25913a6
Remove expected failure from test_exhausted_iterator
palaviv May 9, 2020
73d35bc
add support for getresuid
mrmiywj May 10, 2020
7a3df36
Merge pull request #1920 from mrmiywj/add_support_for_getresuid
coolreader18 May 10, 2020
9352695
add_getresgid_support
mrmiywj May 10, 2020
9b03e9a
Merge pull request #1919 from palaviv/threading-stdlib
windelbouwman May 12, 2020
a48cd71
Merge pull request #1921 from mrmiywj/add_getresgid_support
windelbouwman May 12, 2020
86dd0d6
suppress new version of flake8 lint error for test
youknowone May 12, 2020
7c51a91
Merge pull request #1924 from youknowone/pylint
coolreader18 May 13, 2020
174a21c
implement and test Py39 string operations removeprefix and removesuff…
TheAnyKey May 14, 2020
5b1fb7f
fixed len issue and updated test accordingly
TheAnyKey May 9, 2020
785454d
removeprefix, suffix: implementation for bytes and bytes array
TheAnyKey May 10, 2020
46bc077
unified implementation of removeprefix and removesuffix, added pydocs
TheAnyKey May 13, 2020
7c66acf
fixed findings: removed unnecessary returns and double implementation
TheAnyKey May 16, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions Lib/test/string_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,45 @@ def test_replace_overflow(self):
self.checkraises(OverflowError, A2_16, "replace", "A", A2_16)
self.checkraises(OverflowError, A2_16, "replace", "AA", A2_16+A2_16)


# Python 3.9
def test_removeprefix(self):
self.checkequal('am', 'spam', 'removeprefix', 'sp')
self.checkequal('spamspam', 'spamspamspam', 'removeprefix', 'spam')
self.checkequal('spam', 'spam', 'removeprefix', 'python')
self.checkequal('spam', 'spam', 'removeprefix', 'spider')
self.checkequal('spam', 'spam', 'removeprefix', 'spam and eggs')

self.checkequal('', '', 'removeprefix', '')
self.checkequal('', '', 'removeprefix', 'abcde')
self.checkequal('abcde', 'abcde', 'removeprefix', '')
self.checkequal('', 'abcde', 'removeprefix', 'abcde')

self.checkraises(TypeError, 'hello', 'removeprefix')
self.checkraises(TypeError, 'hello', 'removeprefix', 42)
self.checkraises(TypeError, 'hello', 'removeprefix', 42, 'h')
self.checkraises(TypeError, 'hello', 'removeprefix', 'h', 42)
self.checkraises(TypeError, 'hello', 'removeprefix', ("he", "l"))

# Python 3.9
def test_removesuffix(self):
self.checkequal('sp', 'spam', 'removesuffix', 'am')
self.checkequal('spamspam', 'spamspamspam', 'removesuffix', 'spam')
self.checkequal('spam', 'spam', 'removesuffix', 'python')
self.checkequal('spam', 'spam', 'removesuffix', 'blam')
self.checkequal('spam', 'spam', 'removesuffix', 'eggs and spam')

self.checkequal('', '', 'removesuffix', '')
self.checkequal('', '', 'removesuffix', 'abcde')
self.checkequal('abcde', 'abcde', 'removesuffix', '')
self.checkequal('', 'abcde', 'removesuffix', 'abcde')

self.checkraises(TypeError, 'hello', 'removesuffix')
self.checkraises(TypeError, 'hello', 'removesuffix', 42)
self.checkraises(TypeError, 'hello', 'removesuffix', 42, 'h')
self.checkraises(TypeError, 'hello', 'removesuffix', 'h', 42)
self.checkraises(TypeError, 'hello', 'removesuffix', ("lo", "l"))

def test_capitalize(self):
self.checkequal(' hello ', ' hello ', 'capitalize')
self.checkequal('Hello ', 'Hello ','capitalize')
Expand Down
2 changes: 0 additions & 2 deletions Lib/test/test_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,8 +341,6 @@ def test_iterator_pickle(self):
a.fromlist(data2)
self.assertEqual(list(it), [])

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_exhausted_iterator(self):
a = array.array(self.typecode, self.example)
self.assertEqual(list(a), list(self.example))
Expand Down
83 changes: 83 additions & 0 deletions tests/snippets/dict_union.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@

import testutils

def test_dunion_ior0():
a={1:2,2:3}
b={3:4,5:6}
a|=b

assert a == {1:2,2:3,3:4,5:6}, f"wrong value assigned {a=}"
assert b == {3:4,5:6}, f"right hand side modified, {b=}"

def test_dunion_or0():
a={1:2,2:3}
b={3:4,5:6}
c=a|b

assert a == {1:2,2:3}, f"left hand side of non-assignment operator modified {a=}"
assert b == {3:4,5:6}, f"right hand side of non-assignment operator modified, {b=}"
assert c == {1:2,2:3, 3:4, 5:6}, f"unexpected result of dict union {c=}"


def test_dunion_or1():
a={1:2,2:3}
b={3:4,5:6}
c=a.__or__(b)

assert a == {1:2,2:3}, f"left hand side of non-assignment operator modified {a=}"
assert b == {3:4,5:6}, f"right hand side of non-assignment operator modified, {b=}"
assert c == {1:2,2:3, 3:4, 5:6}, f"unexpected result of dict union {c=}"


def test_dunion_ror0():
a={1:2,2:3}
b={3:4,5:6}
c=b.__ror__(a)

assert a == {1:2,2:3}, f"left hand side of non-assignment operator modified {a=}"
assert b == {3:4,5:6}, f"right hand side of non-assignment operator modified, {b=}"
assert c == {1:2,2:3, 3:4, 5:6}, f"unexpected result of dict union {c=}"


def test_dunion_other_types():
def perf_test_or(other_obj):
d={1:2}
try:
d.__or__(other_obj)
except:
return True
return False

def perf_test_ior(other_obj):
d={1:2}
try:
d.__ior__(other_obj)
except:
return True
return False

def perf_test_ror(other_obj):
d={1:2}
try:
d.__ror__(other_obj)
except:
return True
return False

test_fct={'__or__':perf_test_or, '__ror__':perf_test_ror, '__ior__':perf_test_ior}
others=['FooBar', 42, [36], set([19]), ['aa'], None]
for tfn,tf in test_fct.items():
for other in others:
assert tf(other), f"Failed: dict {tfn}, accepted {other}"




testutils.skip_if_unsupported(3,9,test_dunion_ior0)
testutils.skip_if_unsupported(3,9,test_dunion_or0)
testutils.skip_if_unsupported(3,9,test_dunion_or1)
testutils.skip_if_unsupported(3,9,test_dunion_ror0)
testutils.skip_if_unsupported(3,9,test_dunion_other_types)



97 changes: 96 additions & 1 deletion tests/snippets/strings.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from testutils import assert_raises, AssertRaises
from testutils import assert_raises, AssertRaises, skip_if_unsupported

assert "".__eq__(1) == NotImplemented
assert "a" == 'a'
Expand Down Expand Up @@ -471,3 +471,98 @@ def try_mutate_str():
assert '{:e}'.format(float('inf')) == 'inf'
assert '{:e}'.format(float('-inf')) == '-inf'
assert '{:E}'.format(float('inf')) == 'INF'


# remove*fix test
def test_removeprefix():
s = 'foobarfoo'
s_ref='foobarfoo'
assert s.removeprefix('f') == s_ref[1:]
assert s.removeprefix('fo') == s_ref[2:]
assert s.removeprefix('foo') == s_ref[3:]

assert s.removeprefix('') == s_ref
assert s.removeprefix('bar') == s_ref
assert s.removeprefix('lol') == s_ref
assert s.removeprefix('_foo') == s_ref
assert s.removeprefix('-foo') == s_ref
assert s.removeprefix('afoo') == s_ref
assert s.removeprefix('*foo') == s_ref

assert s==s_ref, 'undefined test fail'

s_uc = '😱foobarfoo🖖'
s_ref_uc = '😱foobarfoo🖖'
assert s_uc.removeprefix('😱') == s_ref_uc[1:]
assert s_uc.removeprefix('😱fo') == s_ref_uc[3:]
assert s_uc.removeprefix('😱foo') == s_ref_uc[4:]

assert s_uc.removeprefix('🖖') == s_ref_uc
assert s_uc.removeprefix('foo') == s_ref_uc
assert s_uc.removeprefix(' ') == s_ref_uc
assert s_uc.removeprefix('_😱') == s_ref_uc
assert s_uc.removeprefix(' 😱') == s_ref_uc
assert s_uc.removeprefix('-😱') == s_ref_uc
assert s_uc.removeprefix('#😱') == s_ref_uc

def test_removeprefix_types():
s='0123456'
s_ref='0123456'
others=[0,['012']]
found=False
for o in others:
try:
s.removeprefix(o)
except:
found=True

assert found, f'Removeprefix accepts other type: {type(o)}: {o=}'

def test_removesuffix():
s='foobarfoo'
s_ref='foobarfoo'
assert s.removesuffix('o') == s_ref[:-1]
assert s.removesuffix('oo') == s_ref[:-2]
assert s.removesuffix('foo') == s_ref[:-3]

assert s.removesuffix('') == s_ref
assert s.removesuffix('bar') == s_ref
assert s.removesuffix('lol') == s_ref
assert s.removesuffix('foo_') == s_ref
assert s.removesuffix('foo-') == s_ref
assert s.removesuffix('foo*') == s_ref
assert s.removesuffix('fooa') == s_ref

assert s==s_ref, 'undefined test fail'

s_uc = '😱foobarfoo🖖'
s_ref_uc = '😱foobarfoo🖖'
assert s_uc.removesuffix('🖖') == s_ref_uc[:-1]
assert s_uc.removesuffix('oo🖖') == s_ref_uc[:-3]
assert s_uc.removesuffix('foo🖖') == s_ref_uc[:-4]

assert s_uc.removesuffix('😱') == s_ref_uc
assert s_uc.removesuffix('foo') == s_ref_uc
assert s_uc.removesuffix(' ') == s_ref_uc
assert s_uc.removesuffix('🖖_') == s_ref_uc
assert s_uc.removesuffix('🖖 ') == s_ref_uc
assert s_uc.removesuffix('🖖-') == s_ref_uc
assert s_uc.removesuffix('🖖#') == s_ref_uc

def test_removesuffix_types():
s='0123456'
s_ref='0123456'
others=[0,6,['6']]
found=False
for o in others:
try:
s.removesuffix(o)
except:
found=True

assert found, f'Removesuffix accepts other type: {type(o)}: {o=}'

skip_if_unsupported(3,9,test_removeprefix)
skip_if_unsupported(3,9,test_removeprefix_types)
skip_if_unsupported(3,9,test_removesuffix)
skip_if_unsupported(3,9,test_removesuffix_types)
25 changes: 25 additions & 0 deletions tests/snippets/testutils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import platform
import sys

def assert_raises(expected, *args, _msg=None, **kw):
if args:
f, f_args = args[0], args[1:]
Expand Down Expand Up @@ -67,3 +70,25 @@ def assert_isinstance(obj, klass):

def assert_in(a, b):
_assert_print(lambda: a in b, [a, 'in', b])

def skip_if_unsupported(req_maj_vers, req_min_vers, test_fct):
def exec():
test_fct()

if platform.python_implementation() == 'RustPython':
exec()
elif sys.version_info.major>=req_maj_vers and sys.version_info.minor>=req_min_vers:
exec()
else:
print(f'Skipping test as a higher python version is required. Using {platform.python_implementation()} {platform.python_version()}')

def fail_if_unsupported(req_maj_vers, req_min_vers, test_fct):
def exec():
test_fct()

if platform.python_implementation() == 'RustPython':
exec()
elif sys.version_info.major>=req_maj_vers and sys.version_info.minor>=req_min_vers:
exec()
else:
assert False, f'Test cannot performed on this python version. {platform.python_implementation()} {platform.python_version()}'
2 changes: 1 addition & 1 deletion tests/snippets/tuple.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def __eq__(self, x):
b = (55, *a)
assert b == (55, 1, 2, 3, 1)

assert () is ()
assert () is () # noqa

a = ()
b = ()
Expand Down
24 changes: 24 additions & 0 deletions vm/src/obj/objbytearray.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,30 @@ impl PyByteArray {
self.borrow_value().rstrip(chars).into()
}

/// removeprefix($self, prefix, /)
///
///
/// Return a bytearray object with the given prefix string removed if present.
///
/// If the bytearray starts with the prefix string, return string[len(prefix):]
/// Otherwise, return a copy of the original bytearray.
#[pymethod(name = "removeprefix")]
fn removeprefix(&self, prefix: PyByteInner) -> PyByteArray {
self.borrow_value().removeprefix(prefix).into()
}

/// removesuffix(self, prefix, /)
///
///
/// Return a bytearray object with the given suffix string removed if present.
///
/// If the bytearray ends with the suffix string, return string[:len(suffix)]
/// Otherwise, return a copy of the original bytearray.
#[pymethod(name = "removesuffix")]
fn removesuffix(&self, suffix: PyByteInner) -> PyByteArray {
self.borrow_value().removesuffix(suffix).to_vec().into()
}

#[pymethod(name = "split")]
fn split(&self, options: ByteInnerSplitOptions, vm: &VirtualMachine) -> PyResult {
self.borrow_value()
Expand Down
18 changes: 18 additions & 0 deletions vm/src/obj/objbyteinner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,24 @@ impl PyByteInner {
.to_vec()
}

// new in Python 3.9
pub fn removeprefix(&self, prefix: PyByteInner) -> Vec<u8> {
self.elements
.py_removeprefix(&prefix.elements, prefix.elements.len(), |s, p| {
s.starts_with(p)
})
.to_vec()
}

// new in Python 3.9
pub fn removesuffix(&self, suffix: PyByteInner) -> Vec<u8> {
self.elements
.py_removesuffix(&suffix.elements, suffix.elements.len(), |s, p| {
s.ends_with(p)
})
.to_vec()
}

pub fn split<F>(
&self,
options: ByteInnerSplitOptions,
Expand Down
24 changes: 24 additions & 0 deletions vm/src/obj/objbytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,30 @@ impl PyBytes {
self.inner.rstrip(chars).into()
}

/// removeprefix($self, prefix, /)
///
///
/// Return a bytes object with the given prefix string removed if present.
///
/// If the bytes starts with the prefix string, return string[len(prefix):]
/// Otherwise, return a copy of the original bytes.
#[pymethod(name = "removeprefix")]
fn removeprefix(&self, prefix: PyByteInner) -> PyBytes {
self.inner.removeprefix(prefix).into()
}

/// removesuffix(self, prefix, /)
///
///
/// Return a bytes object with the given suffix string removed if present.
///
/// If the bytes ends with the suffix string, return string[:len(suffix)]
/// Otherwise, return a copy of the original bytes.
#[pymethod(name = "removesuffix")]
fn removesuffix(&self, suffix: PyByteInner) -> PyBytes {
self.inner.removesuffix(suffix).into()
}

#[pymethod(name = "split")]
fn split(&self, options: ByteInnerSplitOptions, vm: &VirtualMachine) -> PyResult {
self.inner
Expand Down
Loading