Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rjust and center operations implementation #4044

Merged
merged 2 commits into from
May 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/source/reference/pysupported.rst
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,9 @@ The following functions, attributes and methods are currently supported:
* ``.startswith()``
* ``.endswith()``
* ``.find()``
* ``.center()``
* ``.ljust()``
* ``.rjust()``
* ``.split()``
* ``.join()``
* ``.zfill()``
Expand Down
94 changes: 57 additions & 37 deletions numba/tests/test_unicode.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,14 @@ def join_empty_usecase(x):
return x.join(l)


def center_usecase(x, y):
return x.center(y)


def center_usecase_fillchar(x, y, fillchar):
return x.center(y, fillchar)


def ljust_usecase(x, y):
return x.ljust(y)

Expand All @@ -123,6 +131,14 @@ def ljust_usecase_fillchar(x, y, fillchar):
return x.ljust(y, fillchar)


def rjust_usecase(x, y):
return x.rjust(y)


def rjust_usecase_fillchar(x, y, fillchar):
return x.rjust(y, fillchar)


def iter_usecase(x):
l = []
for i in x:
Expand Down Expand Up @@ -585,53 +601,57 @@ def test_join_interleave_str(self):
cfunc(sep, parts),
"'%s'.join('%s')?" % (sep, parts))

def test_ljust(self):
pyfunc = ljust_usecase
cfunc = njit(pyfunc)

with self.assertRaises(TypingError) as raises:
cfunc(UNICODE_EXAMPLES[0], 1.1)
self.assertIn('The width must be an Integer', str(raises.exception))

for s in UNICODE_EXAMPLES:
for width in range(-3, 20):
self.assertEqual(pyfunc(s, width),
cfunc(s, width),
"'%s'.ljust(%d)?" % (s, width))

def test_ljust_fillchar(self):
pyfunc = ljust_usecase_fillchar
cfunc = njit(pyfunc)
def test_justification(self):
for pyfunc, case_name in [(center_usecase, 'center'),
(ljust_usecase, 'ljust'),
(rjust_usecase, 'rjust')]:
cfunc = njit(pyfunc)

# allowed fillchar cases
for fillchar in [' ', '+', 'ú', '处']:
with self.assertRaises(TypingError) as raises:
cfunc(UNICODE_EXAMPLES[0], 1.1, fillchar)
cfunc(UNICODE_EXAMPLES[0], 1.1)
self.assertIn('The width must be an Integer', str(raises.exception))

for s in UNICODE_EXAMPLES:
for width in range(-3, 20):
self.assertEqual(pyfunc(s, width, fillchar),
cfunc(s, width, fillchar),
"'%s'.ljust(%d, '%s')?" % (s, width, fillchar))
self.assertEqual(pyfunc(s, width),
cfunc(s, width),
"'%s'.%s(%d)?" % (s, case_name, width))

def test_justification_fillchar(self):
for pyfunc, case_name in [(center_usecase_fillchar, 'center'),
(ljust_usecase_fillchar, 'ljust'),
(rjust_usecase_fillchar, 'rjust')]:
cfunc = njit(pyfunc)

def test_ljust_fillchar_exception(self):
self.disable_leak_check()
# allowed fillchar cases
for fillchar in [' ', '+', 'ú', '处']:
with self.assertRaises(TypingError) as raises:
cfunc(UNICODE_EXAMPLES[0], 1.1, fillchar)
self.assertIn('The width must be an Integer', str(raises.exception))

pyfunc = ljust_usecase_fillchar
cfunc = njit(pyfunc)
for s in UNICODE_EXAMPLES:
for width in range(-3, 20):
self.assertEqual(pyfunc(s, width, fillchar),
cfunc(s, width, fillchar),
"'%s'.%s(%d, '%s')?" % (s, case_name, width, fillchar))

# disallowed fillchar cases
for fillchar in ['', '+0', 'quién', '处着']:
with self.assertRaises(ValueError) as raises:
cfunc(UNICODE_EXAMPLES[0], 20, fillchar)
self.assertIn('The fill character must be exactly one', str(raises.exception))
def test_justification_fillchar_exception(self):
self.disable_leak_check()

# forbid fillchar cases with different types
for fillchar in [1, 1.1]:
with self.assertRaises(TypingError) as raises:
cfunc(UNICODE_EXAMPLES[0], 20, fillchar)
self.assertIn('The fillchar must be a UnicodeType', str(raises.exception))
for pyfunc in [center_usecase_fillchar, ljust_usecase_fillchar, rjust_usecase_fillchar]:
cfunc = njit(pyfunc)

# disallowed fillchar cases
for fillchar in ['', '+0', 'quién', '处着']:
with self.assertRaises(ValueError) as raises:
cfunc(UNICODE_EXAMPLES[0], 20, fillchar)
self.assertIn('The fill character must be exactly one', str(raises.exception))

# forbid fillchar cases with different types
for fillchar in [1, 1.1]:
with self.assertRaises(TypingError) as raises:
cfunc(UNICODE_EXAMPLES[0], 20, fillchar)
self.assertIn('The fillchar must be a UnicodeType', str(raises.exception))

def test_inplace_concat(self, flags=no_pyobj_flags):
pyfunc = inplace_concat_usecase
Expand Down
53 changes: 53 additions & 0 deletions numba/unicode.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,36 @@ def split_whitespace_impl(a, sep=None, maxsplit=-1):
return split_whitespace_impl


@overload_method(types.UnicodeType, 'center')
def unicode_center(string, width, fillchar=' '):
if not isinstance(width, types.Integer):
raise TypingError('The width must be an Integer')
if not (fillchar == ' ' or isinstance(fillchar, (types.Omitted, types.UnicodeType))):
raise TypingError('The fillchar must be a UnicodeType')

def center_impl(string, width, fillchar=' '):
str_len = len(string)
fillchar_len = len(fillchar)

if fillchar_len != 1:
raise ValueError('The fill character must be exactly one character long')

if width <= str_len:
return string

allmargin = width - str_len
lmargin = (allmargin // 2) + (allmargin & width & 1)
rmargin = allmargin - lmargin

l_string = fillchar * lmargin
if lmargin == rmargin:
return l_string + string + l_string
else:
return l_string + string + (fillchar * rmargin)

return center_impl


@overload_method(types.UnicodeType, 'ljust')
def unicode_ljust(string, width, fillchar=' '):
if not isinstance(width, types.Integer):
Expand All @@ -617,6 +647,29 @@ def ljust_impl(string, width, fillchar=' '):
return ljust_impl


@overload_method(types.UnicodeType, 'rjust')
def unicode_rjust(string, width, fillchar=' '):
if not isinstance(width, types.Integer):
raise TypingError('The width must be an Integer')
if not (fillchar == ' ' or isinstance(fillchar, (types.Omitted, types.UnicodeType))):
raise TypingError('The fillchar must be a UnicodeType')

def rjust_impl(string, width, fillchar=' '):
str_len = len(string)
fillchar_len = len(fillchar)

if fillchar_len != 1:
raise ValueError('The fill character must be exactly one character long')

if width <= str_len:
return string

newstr = (fillchar * (width - str_len)) + string

return newstr
return rjust_impl


@njit
def join_list(sep, parts):
parts_len = len(parts)
Expand Down