1# -*- coding: utf-8 -*-
2
3cimport cython
4
5import sys
6
7PY_VERSION = sys.version_info
8
9text = u'ab jd  sdflk as sa  sadas asdas fsdf '
10sep = u'  '
11format1 = u'abc%sdef'
12format2 = u'abc%sdef%sghi'
13unicode_sa = u'sa'
14
15multiline_text = u'''\
16ab jd
17sdflk as sa
18sadas asdas fsdf '''
19
20def print_all(l):
21    for s in l:
22        print(s)
23
24
25# unicode.split(s, [sep, [maxsplit]])
26
27@cython.test_assert_path_exists(
28    "//PythonCapiCallNode")
29def split(unicode s):
30    """
31    >>> print_all( text.split() )
32    ab
33    jd
34    sdflk
35    as
36    sa
37    sadas
38    asdas
39    fsdf
40    >>> print_all( split(text) )
41    ab
42    jd
43    sdflk
44    as
45    sa
46    sadas
47    asdas
48    fsdf
49    """
50    return s.split()
51
52@cython.test_assert_path_exists(
53    "//PythonCapiCallNode")
54def split_sep(unicode s, sep):
55    """
56    >>> print_all( text.split(sep) )
57    ab jd
58    sdflk as sa
59    sadas asdas fsdf
60    >>> print_all( split_sep(text, sep) )
61    ab jd
62    sdflk as sa
63    sadas asdas fsdf
64    """
65    return s.split(sep)
66
67@cython.test_fail_if_path_exists(
68    "//CoerceToPyTypeNode",
69    "//CastNode", "//TypecastNode")
70@cython.test_assert_path_exists(
71    "//CoerceFromPyTypeNode",
72    "//PythonCapiCallNode")
73def split_sep_max(unicode s, sep, max):
74    """
75    >>> print_all( text.split(sep, 1) )
76    ab jd
77    sdflk as sa  sadas asdas fsdf
78    >>> print_all( split_sep_max(text, sep, 1) )
79    ab jd
80    sdflk as sa  sadas asdas fsdf
81    """
82    return s.split(sep, max)
83
84@cython.test_fail_if_path_exists(
85    "//CoerceToPyTypeNode", "//CoerceFromPyTypeNode",
86    "//CastNode", "//TypecastNode")
87@cython.test_assert_path_exists(
88    "//PythonCapiCallNode")
89def split_sep_max_int(unicode s, sep):
90    """
91    >>> print_all( text.split(sep, 1) )
92    ab jd
93    sdflk as sa  sadas asdas fsdf
94    >>> print_all( split_sep_max_int(text, sep) )
95    ab jd
96    sdflk as sa  sadas asdas fsdf
97    """
98    return s.split(sep, 1)
99
100
101# unicode.splitlines(s, [keepends])
102
103@cython.test_assert_path_exists(
104    "//PythonCapiCallNode")
105def splitlines(unicode s):
106    """
107    >>> len(multiline_text.splitlines())
108    3
109    >>> print_all( multiline_text.splitlines() )
110    ab jd
111    sdflk as sa
112    sadas asdas fsdf
113    >>> len(splitlines(multiline_text))
114    3
115    >>> print_all( splitlines(multiline_text) )
116    ab jd
117    sdflk as sa
118    sadas asdas fsdf
119    """
120    return s.splitlines()
121
122@cython.test_assert_path_exists(
123    "//PythonCapiCallNode")
124def splitlines_keep(unicode s, keep):
125    """
126    >>> len(multiline_text.splitlines(True))
127    3
128    >>> print_all( multiline_text.splitlines(True) )
129    ab jd
130    <BLANKLINE>
131    sdflk as sa
132    <BLANKLINE>
133    sadas asdas fsdf
134    >>> len(splitlines_keep(multiline_text, True))
135    3
136    >>> print_all( splitlines_keep(multiline_text, True) )
137    ab jd
138    <BLANKLINE>
139    sdflk as sa
140    <BLANKLINE>
141    sadas asdas fsdf
142    """
143    return s.splitlines(keep)
144
145@cython.test_fail_if_path_exists(
146    "//CoerceToPyTypeNode", "//CoerceFromPyTypeNode",
147    "//CastNode", "//TypecastNode")
148@cython.test_assert_path_exists(
149    "//PythonCapiCallNode")
150def splitlines_keep_bint(unicode s):
151    """
152    >>> len(multiline_text.splitlines(True))
153    3
154    >>> print_all( multiline_text.splitlines(True) )
155    ab jd
156    <BLANKLINE>
157    sdflk as sa
158    <BLANKLINE>
159    sadas asdas fsdf
160    >>> print_all( multiline_text.splitlines(False) )
161    ab jd
162    sdflk as sa
163    sadas asdas fsdf
164    >>> len(splitlines_keep_bint(multiline_text))
165    7
166    >>> print_all( splitlines_keep_bint(multiline_text) )
167    ab jd
168    <BLANKLINE>
169    sdflk as sa
170    <BLANKLINE>
171    sadas asdas fsdf
172    --
173    ab jd
174    sdflk as sa
175    sadas asdas fsdf
176    """
177    return s.splitlines(True) + ['--'] + s.splitlines(False)
178
179
180# unicode.join(s, iterable)
181
182pipe_sep = u'|'
183
184@cython.test_fail_if_path_exists(
185    "//CoerceToPyTypeNode", "//CoerceFromPyTypeNode",
186    "//CastNode", "//TypecastNode",
187    "//SimpleCallNode//AttributeNode[@is_py_attr = true]")
188@cython.test_assert_path_exists(
189    "//PythonCapiCallNode",
190)
191def join(unicode sep, l):
192    """
193    >>> l = text.split()
194    >>> len(l)
195    8
196    >>> print( pipe_sep.join(l) )
197    ab|jd|sdflk|as|sa|sadas|asdas|fsdf
198    >>> print( join(pipe_sep, l) )
199    ab|jd|sdflk|as|sa|sadas|asdas|fsdf
200    """
201    return sep.join(l)
202
203
204@cython.test_fail_if_path_exists(
205    "//CoerceToPyTypeNode", "//CoerceFromPyTypeNode",
206    "//CastNode", "//TypecastNode", "//NoneCheckNode",
207    "//SimpleCallNode//AttributeNode[@is_py_attr = true]")
208@cython.test_assert_path_exists(
209    "//PythonCapiCallNode",
210)
211def join_sep(l):
212    """
213    >>> l = text.split()
214    >>> len(l)
215    8
216    >>> print( '|'.join(l) )
217    ab|jd|sdflk|as|sa|sadas|asdas|fsdf
218    >>> print( join_sep(l) )
219    ab|jd|sdflk|as|sa|sadas|asdas|fsdf
220    """
221    result = u'|'.join(l)
222    assert cython.typeof(result) == 'unicode object', cython.typeof(result)
223    return result
224
225
226@cython.test_fail_if_path_exists(
227    "//CoerceToPyTypeNode", "//CoerceFromPyTypeNode",
228    "//CastNode", "//TypecastNode", "//NoneCheckNode",
229    "//SimpleCallNode//AttributeNode[@is_py_attr = true]"
230)
231@cython.test_assert_path_exists(
232    "//PythonCapiCallNode",
233    "//InlinedGeneratorExpressionNode"
234)
235def join_sep_genexpr(l):
236    """
237    >>> l = text.split()
238    >>> len(l)
239    8
240    >>> print( '<<%s>>' % '|'.join(s + ' ' for s in l) )
241    <<ab |jd |sdflk |as |sa |sadas |asdas |fsdf >>
242    >>> print( '<<%s>>' % join_sep_genexpr(l) )
243    <<ab |jd |sdflk |as |sa |sadas |asdas |fsdf >>
244    """
245    result = u'|'.join(s + u' ' for s in l)
246    assert cython.typeof(result) == 'unicode object', cython.typeof(result)
247    return result
248
249
250@cython.test_fail_if_path_exists(
251    "//CoerceToPyTypeNode", "//CoerceFromPyTypeNode",
252    "//CastNode", "//TypecastNode",
253)
254@cython.test_assert_path_exists(
255    "//PythonCapiCallNode",
256    "//InlinedGeneratorExpressionNode"
257)
258def join_sep_genexpr_dictiter(dict d):
259    """
260    >>> l = text.split()
261    >>> d = dict(zip(range(len(l)), l))
262    >>> print('|'.join( sorted(' '.join('%s:%s' % (k, v) for k, v in d.items()).split()) ))
263    0:ab|1:jd|2:sdflk|3:as|4:sa|5:sadas|6:asdas|7:fsdf
264    >>> print('|'.join( sorted(join_sep_genexpr_dictiter(d).split())) )
265    0:ab|1:jd|2:sdflk|3:as|4:sa|5:sadas|6:asdas|7:fsdf
266    """
267    result = u' '.join('%s:%s' % (k, v) for k, v in d.iteritems())
268    assert cython.typeof(result) == 'unicode object', cython.typeof(result)
269    return result
270
271
272@cython.test_assert_path_exists(
273    "//PythonCapiCallNode",
274)
275def join_unbound(unicode sep, l):
276    """
277    >>> l = text.split()
278    >>> len(l)
279    8
280    >>> print( pipe_sep.join(l) )
281    ab|jd|sdflk|as|sa|sadas|asdas|fsdf
282    >>> print( join_unbound(pipe_sep, l) )
283    ab|jd|sdflk|as|sa|sadas|asdas|fsdf
284    """
285    join = unicode.join
286    return join(sep, l)
287
288
289# unicode.startswith(s, prefix, [start, [end]])
290
291@cython.test_fail_if_path_exists(
292    "//CoerceToPyTypeNode",
293    "//CoerceFromPyTypeNode",
294    "//CastNode", "//TypecastNode")
295@cython.test_assert_path_exists(
296    "//PythonCapiCallNode")
297def startswith(unicode s, sub):
298    """
299    >>> text.startswith('ab ')
300    True
301    >>> startswith(text, 'ab ')
302    'MATCH'
303    >>> text.startswith('ab X')
304    False
305    >>> startswith(text, 'ab X')
306    'NO MATCH'
307
308    >>> PY_VERSION < (2,5) or text.startswith(('ab', 'ab '))
309    True
310    >>> startswith(text, ('ab', 'ab '))
311    'MATCH'
312    >>> PY_VERSION < (2,5) or not text.startswith((' ab', 'ab X'))
313    True
314    >>> startswith(text, (' ab', 'ab X'))
315    'NO MATCH'
316    """
317    if s.startswith(sub):
318        return 'MATCH'
319    else:
320        return 'NO MATCH'
321
322@cython.test_fail_if_path_exists(
323    "//CoerceToPyTypeNode",
324    "//CastNode", "//TypecastNode")
325@cython.test_assert_path_exists(
326    "//CoerceFromPyTypeNode",
327    "//PythonCapiCallNode")
328def startswith_start_end(unicode s, sub, start, end):
329    """
330    >>> text.startswith('b ', 1, 5)
331    True
332    >>> startswith_start_end(text, 'b ', 1, 5)
333    'MATCH'
334    >>> text.startswith('ab ', -1000, 5000)
335    True
336    >>> startswith_start_end(text, 'ab ', -1000, 5000)
337    'MATCH'
338    >>> text.startswith('b X', 1, 5)
339    False
340    >>> startswith_start_end(text, 'b X', 1, 5)
341    'NO MATCH'
342    """
343    if s.startswith(sub, start, end):
344        return 'MATCH'
345    else:
346        return 'NO MATCH'
347
348
349# unicode.endswith(s, prefix, [start, [end]])
350
351@cython.test_fail_if_path_exists(
352    "//CoerceToPyTypeNode",
353    "//CoerceFromPyTypeNode",
354    "//CastNode", "//TypecastNode")
355@cython.test_assert_path_exists(
356    "//PythonCapiCallNode")
357def endswith(unicode s, sub):
358    """
359    >>> text.endswith('fsdf ')
360    True
361    >>> endswith(text, 'fsdf ')
362    'MATCH'
363    >>> text.endswith('fsdf X')
364    False
365    >>> endswith(text, 'fsdf X')
366    'NO MATCH'
367
368    >>> PY_VERSION < (2,5) or text.endswith(('fsdf', 'fsdf '))
369    True
370    >>> endswith(text, ('fsdf', 'fsdf '))
371    'MATCH'
372    >>> PY_VERSION < (2,5) or not text.endswith(('fsdf', 'fsdf X'))
373    True
374    >>> endswith(text, ('fsdf', 'fsdf X'))
375    'NO MATCH'
376    """
377    if s.endswith(sub):
378        return 'MATCH'
379    else:
380        return 'NO MATCH'
381
382@cython.test_fail_if_path_exists(
383    "//CoerceToPyTypeNode",
384    "//CastNode", "//TypecastNode")
385@cython.test_assert_path_exists(
386    "//CoerceFromPyTypeNode",
387    "//PythonCapiCallNode")
388def endswith_start_end(unicode s, sub, start, end):
389    """
390    >>> text.endswith('fsdf', 10, len(text)-1)
391    True
392    >>> endswith_start_end(text, 'fsdf', 10, len(text)-1)
393    'MATCH'
394    >>> text.endswith('fsdf ', 10, len(text)-1)
395    False
396    >>> endswith_start_end(text, 'fsdf ', 10, len(text)-1)
397    'NO MATCH'
398
399    >>> text.endswith('fsdf ', -1000, 5000)
400    True
401    >>> endswith_start_end(text, 'fsdf ', -1000, 5000)
402    'MATCH'
403
404    >>> PY_VERSION < (2,5) or text.endswith(('fsd', 'fsdf'), 10, len(text)-1)
405    True
406    >>> endswith_start_end(text, ('fsd', 'fsdf'), 10, len(text)-1)
407    'MATCH'
408    >>> PY_VERSION < (2,5) or not text.endswith(('fsdf ', 'fsdf X'), 10, len(text)-1)
409    True
410    >>> endswith_start_end(text, ('fsdf ', 'fsdf X'), 10, len(text)-1)
411    'NO MATCH'
412    """
413    if s.endswith(sub, start, end):
414        return 'MATCH'
415    else:
416        return 'NO MATCH'
417
418
419# unicode.__contains__(s, sub)
420
421@cython.test_fail_if_path_exists(
422    "//CoerceFromPyTypeNode", "//AttributeNode")
423@cython.test_assert_path_exists(
424    "//CoerceToPyTypeNode", "//PrimaryCmpNode")
425def in_test(unicode s, substring):
426    """
427    >>> in_test(text, 'sa')
428    True
429    >>> in_test(text, 'XYZ')
430    False
431    >>> in_test(None, 'sa')
432    Traceback (most recent call last):
433    TypeError: 'NoneType' object is not iterable
434    """
435    return substring in s
436
437
438# unicode.__concat__(s, suffix)
439
440def concat_any(unicode s, suffix):
441    """
442    >>> concat(text, 'sa') == text + 'sa'  or  concat(text, 'sa')
443    True
444    >>> concat(None, 'sa')   # doctest: +ELLIPSIS
445    Traceback (most recent call last):
446    TypeError: ...
447    >>> concat(text, None)   # doctest: +ELLIPSIS
448    Traceback (most recent call last):
449    TypeError: ...
450    >>> class RAdd(object):
451    ...     def __radd__(self, other):
452    ...         return 123
453    >>> concat(None, 'sa')   # doctest: +ELLIPSIS
454    Traceback (most recent call last):
455    TypeError: ...
456    """
457    assert cython.typeof(s + suffix) == 'Python object', cython.typeof(s + suffix)
458    return s + suffix
459
460
461def concat(unicode s, str suffix):
462    """
463    >>> concat(text, 'sa') == text + 'sa'  or  concat(text, 'sa')
464    True
465    >>> concat(None, 'sa')   # doctest: +ELLIPSIS
466    Traceback (most recent call last):
467    TypeError: ...
468    >>> concat(text, None)   # doctest: +ELLIPSIS
469    Traceback (most recent call last):
470    TypeError: ...
471    >>> class RAdd(object):
472    ...     def __radd__(self, other):
473    ...         return 123
474    >>> concat(None, 'sa')   # doctest: +ELLIPSIS
475    Traceback (most recent call last):
476    TypeError: ...
477    """
478    assert cython.typeof(s + object()) == 'Python object', cython.typeof(s + object())
479    assert cython.typeof(s + suffix) == 'unicode object', cython.typeof(s + suffix)
480    return s + suffix
481
482
483def concat_literal_str(str suffix):
484    """
485    >>> concat_literal_str('sa') == 'abcsa'  or  concat_literal_str('sa')
486    True
487    >>> concat_literal_str(None)  # doctest: +ELLIPSIS
488    Traceback (most recent call last):
489    TypeError: ...NoneType...
490    """
491    assert cython.typeof(u'abc' + object()) == 'Python object', cython.typeof(u'abc' + object())
492    assert cython.typeof(u'abc' + suffix) == 'unicode object', cython.typeof(u'abc' + suffix)
493    return u'abc' + suffix
494
495
496def concat_literal_unicode(unicode suffix):
497    """
498    >>> concat_literal_unicode(unicode_sa) == 'abcsa'  or  concat_literal_unicode(unicode_sa)
499    True
500    >>> concat_literal_unicode(None)  # doctest: +ELLIPSIS
501    Traceback (most recent call last):
502    TypeError: ...NoneType...
503    """
504    assert cython.typeof(u'abc' + suffix) == 'unicode object', cython.typeof(u'abc' + suffix)
505    return u'abc' + suffix
506
507
508# unicode.__mod__(format, values)
509
510def mod_format(unicode s, values):
511    """
512    >>> mod_format(format1, 'sa') == 'abcsadef'  or  mod_format(format1, 'sa')
513    True
514    >>> mod_format(format2, ('XYZ', 'ABC')) == 'abcXYZdefABCghi'  or  mod_format(format2, ('XYZ', 'ABC'))
515    True
516    >>> mod_format(None, 'sa')   # doctest: +ELLIPSIS
517    Traceback (most recent call last):
518    TypeError: unsupported operand type(s) for %: 'NoneType' and 'str'
519    >>> class RMod(object):
520    ...     def __rmod__(self, other):
521    ...         return 123
522    >>> mod_format(None, RMod())
523    123
524    """
525    assert cython.typeof(s % values) == 'Python object', cython.typeof(s % values)
526    return s % values
527
528
529def mod_format_literal(values):
530    """
531    >>> mod_format_literal('sa') == 'abcsadef'  or  mod_format(format1, 'sa')
532    True
533    >>> mod_format_literal(('sa',)) == 'abcsadef'  or  mod_format(format1, ('sa',))
534    True
535    >>> mod_format_literal(['sa']) == "abc['sa']def"  or  mod_format(format1, ['sa'])
536    True
537    """
538    assert cython.typeof(u'abc%sdef' % values) == 'unicode object', cython.typeof(u'abc%sdef' % values)
539    return u'abc%sdef' % values
540
541
542def mod_format_tuple(*values):
543    """
544    >>> mod_format_tuple('sa') == 'abcsadef'  or  mod_format(format1, 'sa')
545    True
546    >>> mod_format_tuple()
547    Traceback (most recent call last):
548    TypeError: not enough arguments for format string
549    """
550    assert cython.typeof(u'abc%sdef' % values) == 'unicode object', cython.typeof(u'abc%sdef' % values)
551    return u'abc%sdef' % values
552
553
554# unicode.find(s, sub, [start, [end]])
555
556@cython.test_fail_if_path_exists(
557    "//CoerceFromPyTypeNode",
558    "//CastNode", "//TypecastNode")
559@cython.test_assert_path_exists(
560    "//CoerceToPyTypeNode",
561    "//PythonCapiCallNode")
562def find(unicode s, substring):
563    """
564    >>> text.find('sa')
565    16
566    >>> find(text, 'sa')
567    16
568    """
569    cdef Py_ssize_t pos = s.find(substring)
570    return pos
571
572@cython.test_fail_if_path_exists(
573    "//CastNode", "//TypecastNode")
574@cython.test_assert_path_exists(
575    "//CoerceToPyTypeNode",
576    "//PythonCapiCallNode")
577def find_start_end(unicode s, substring, start, end):
578    """
579    >>> text.find('sa', 17, 25)
580    20
581    >>> find_start_end(text, 'sa', 17, 25)
582    20
583    """
584    cdef Py_ssize_t pos = s.find(substring, start, end)
585    return pos
586
587
588# unicode.rfind(s, sub, [start, [end]])
589
590@cython.test_fail_if_path_exists(
591    "//CoerceFromPyTypeNode",
592    "//CastNode", "//TypecastNode")
593@cython.test_assert_path_exists(
594    "//CoerceToPyTypeNode",
595    "//PythonCapiCallNode")
596def rfind(unicode s, substring):
597    """
598    >>> text.rfind('sa')
599    20
600    >>> rfind(text, 'sa')
601    20
602    """
603    cdef Py_ssize_t pos = s.rfind(substring)
604    return pos
605
606@cython.test_fail_if_path_exists(
607    "//CastNode", "//TypecastNode")
608@cython.test_assert_path_exists(
609    "//CoerceToPyTypeNode",
610    "//PythonCapiCallNode")
611def rfind_start_end(unicode s, substring, start, end):
612    """
613    >>> text.rfind('sa', 14, 19)
614    16
615    >>> rfind_start_end(text, 'sa', 14, 19)
616    16
617    """
618    cdef Py_ssize_t pos = s.rfind(substring, start, end)
619    return pos
620
621
622# unicode.count(s, sub, [start, [end]])
623
624@cython.test_fail_if_path_exists(
625    "//CoerceFromPyTypeNode",
626    "//CastNode", "//TypecastNode")
627@cython.test_assert_path_exists(
628    "//CoerceToPyTypeNode",
629    "//PythonCapiCallNode")
630def count(unicode s, substring):
631    """
632    >>> text.count('sa')
633    2
634    >>> count(text, 'sa')
635    2
636    """
637    cdef Py_ssize_t pos = s.count(substring)
638    return pos
639
640@cython.test_fail_if_path_exists(
641    "//CastNode", "//TypecastNode")
642@cython.test_assert_path_exists(
643    "//CoerceToPyTypeNode",
644    "//PythonCapiCallNode")
645def count_start_end(unicode s, substring, start, end):
646    """
647    >>> text.count('sa', 14, 21)
648    1
649    >>> text.count('sa', 14, 22)
650    2
651    >>> count_start_end(text, 'sa', 14, 21)
652    1
653    >>> count_start_end(text, 'sa', 14, 22)
654    2
655    """
656    cdef Py_ssize_t pos = s.count(substring, start, end)
657    return pos
658
659
660# unicode.replace(s, sub, repl, [maxcount])
661
662@cython.test_fail_if_path_exists(
663    "//CoerceFromPyTypeNode",
664    "//CastNode", "//TypecastNode")
665@cython.test_assert_path_exists(
666    "//PythonCapiCallNode")
667def replace(unicode s, substring, repl):
668    """
669    >>> print( text.replace('sa', 'SA') )
670    ab jd  sdflk as SA  SAdas asdas fsdf
671    >>> print( replace(text, 'sa', 'SA') )
672    ab jd  sdflk as SA  SAdas asdas fsdf
673    """
674    return s.replace(substring, repl)
675
676@cython.test_fail_if_path_exists(
677    "//CastNode", "//TypecastNode")
678@cython.test_assert_path_exists(
679    "//CoerceFromPyTypeNode",
680    "//PythonCapiCallNode")
681def replace_maxcount(unicode s, substring, repl, maxcount):
682    """
683    >>> print( text.replace('sa', 'SA', 1) )
684    ab jd  sdflk as SA  sadas asdas fsdf
685    >>> print( replace_maxcount(text, 'sa', 'SA', 1) )
686    ab jd  sdflk as SA  sadas asdas fsdf
687    """
688    return s.replace(substring, repl, maxcount)
689