Show More
@@ -14,6 +14,11 b' import re as remod' | |||||
14 | import textwrap |
|
14 | import textwrap | |
15 | import types |
|
15 | import types | |
16 |
|
16 | |||
|
17 | from typing import ( | |||
|
18 | Optional, | |||
|
19 | overload, | |||
|
20 | ) | |||
|
21 | ||||
17 | from ..i18n import _ |
|
22 | from ..i18n import _ | |
18 | from ..thirdparty import attr |
|
23 | from ..thirdparty import attr | |
19 |
|
24 | |||
@@ -30,6 +35,16 b' from .. import (' | |||||
30 | regexbytesescapemap = {i: (b'\\' + i) for i in _respecial} |
|
35 | regexbytesescapemap = {i: (b'\\' + i) for i in _respecial} | |
31 |
|
36 | |||
32 |
|
37 | |||
|
38 | @overload | |||
|
39 | def reescape(pat: bytes) -> bytes: | |||
|
40 | ... | |||
|
41 | ||||
|
42 | ||||
|
43 | @overload | |||
|
44 | def reescape(pat: str) -> str: | |||
|
45 | ... | |||
|
46 | ||||
|
47 | ||||
33 | def reescape(pat): |
|
48 | def reescape(pat): | |
34 | """Drop-in replacement for re.escape.""" |
|
49 | """Drop-in replacement for re.escape.""" | |
35 | # NOTE: it is intentional that this works on unicodes and not |
|
50 | # NOTE: it is intentional that this works on unicodes and not | |
@@ -45,12 +60,12 b' def reescape(pat):' | |||||
45 | return pat.encode('latin1') |
|
60 | return pat.encode('latin1') | |
46 |
|
61 | |||
47 |
|
62 | |||
48 | def pprint(o, bprefix=False, indent=0, level=0): |
|
63 | def pprint(o, bprefix: bool = False, indent: int = 0, level: int = 0) -> bytes: | |
49 | """Pretty print an object.""" |
|
64 | """Pretty print an object.""" | |
50 | return b''.join(pprintgen(o, bprefix=bprefix, indent=indent, level=level)) |
|
65 | return b''.join(pprintgen(o, bprefix=bprefix, indent=indent, level=level)) | |
51 |
|
66 | |||
52 |
|
67 | |||
53 | def pprintgen(o, bprefix=False, indent=0, level=0): |
|
68 | def pprintgen(o, bprefix: bool = False, indent: int = 0, level: int = 0): | |
54 | """Pretty print an object to a generator of atoms. |
|
69 | """Pretty print an object to a generator of atoms. | |
55 |
|
70 | |||
56 | ``bprefix`` is a flag influencing whether bytestrings are preferred with |
|
71 | ``bprefix`` is a flag influencing whether bytestrings are preferred with | |
@@ -250,7 +265,7 b' def pprintgen(o, bprefix=False, indent=0' | |||||
250 | yield pycompat.byterepr(o) |
|
265 | yield pycompat.byterepr(o) | |
251 |
|
266 | |||
252 |
|
267 | |||
253 | def prettyrepr(o): |
|
268 | def prettyrepr(o) -> bytes: | |
254 | """Pretty print a representation of a possibly-nested object""" |
|
269 | """Pretty print a representation of a possibly-nested object""" | |
255 | lines = [] |
|
270 | lines = [] | |
256 | rs = pycompat.byterepr(o) |
|
271 | rs = pycompat.byterepr(o) | |
@@ -281,7 +296,7 b' def prettyrepr(o):' | |||||
281 | return b'\n'.join(b' ' * l + s for l, s in lines) |
|
296 | return b'\n'.join(b' ' * l + s for l, s in lines) | |
282 |
|
297 | |||
283 |
|
298 | |||
284 | def buildrepr(r): |
|
299 | def buildrepr(r) -> bytes: | |
285 | """Format an optional printable representation from unexpanded bits |
|
300 | """Format an optional printable representation from unexpanded bits | |
286 |
|
301 | |||
287 | ======== ================================= |
|
302 | ======== ================================= | |
@@ -305,12 +320,12 b' def buildrepr(r):' | |||||
305 | return pprint(r) |
|
320 | return pprint(r) | |
306 |
|
321 | |||
307 |
|
322 | |||
308 | def binary(s): |
|
323 | def binary(s: bytes) -> bool: | |
309 | """return true if a string is binary data""" |
|
324 | """return true if a string is binary data""" | |
310 | return bool(s and b'\0' in s) |
|
325 | return bool(s and b'\0' in s) | |
311 |
|
326 | |||
312 |
|
327 | |||
313 | def _splitpattern(pattern): |
|
328 | def _splitpattern(pattern: bytes): | |
314 | if pattern.startswith(b're:'): |
|
329 | if pattern.startswith(b're:'): | |
315 | return b're', pattern[3:] |
|
330 | return b're', pattern[3:] | |
316 | elif pattern.startswith(b'literal:'): |
|
331 | elif pattern.startswith(b'literal:'): | |
@@ -318,7 +333,7 b' def _splitpattern(pattern):' | |||||
318 | return b'literal', pattern |
|
333 | return b'literal', pattern | |
319 |
|
334 | |||
320 |
|
335 | |||
321 | def stringmatcher(pattern, casesensitive=True): |
|
336 | def stringmatcher(pattern: bytes, casesensitive: bool = True): | |
322 | """ |
|
337 | """ | |
323 | accepts a string, possibly starting with 're:' or 'literal:' prefix. |
|
338 | accepts a string, possibly starting with 're:' or 'literal:' prefix. | |
324 | returns the matcher name, pattern, and matcher function. |
|
339 | returns the matcher name, pattern, and matcher function. | |
@@ -379,7 +394,7 b' def stringmatcher(pattern, casesensitive' | |||||
379 | raise error.ProgrammingError(b'unhandled pattern kind: %s' % kind) |
|
394 | raise error.ProgrammingError(b'unhandled pattern kind: %s' % kind) | |
380 |
|
395 | |||
381 |
|
396 | |||
382 | def substringregexp(pattern, flags=0): |
|
397 | def substringregexp(pattern: bytes, flags: int = 0): | |
383 | """Build a regexp object from a string pattern possibly starting with |
|
398 | """Build a regexp object from a string pattern possibly starting with | |
384 | 're:' or 'literal:' prefix. |
|
399 | 're:' or 'literal:' prefix. | |
385 |
|
400 | |||
@@ -431,7 +446,7 b' def substringregexp(pattern, flags=0):' | |||||
431 | raise error.ProgrammingError(b'unhandled pattern kind: %s' % kind) |
|
446 | raise error.ProgrammingError(b'unhandled pattern kind: %s' % kind) | |
432 |
|
447 | |||
433 |
|
448 | |||
434 | def shortuser(user): |
|
449 | def shortuser(user: bytes) -> bytes: | |
435 | """Return a short representation of a user name or email address.""" |
|
450 | """Return a short representation of a user name or email address.""" | |
436 | f = user.find(b'@') |
|
451 | f = user.find(b'@') | |
437 | if f >= 0: |
|
452 | if f >= 0: | |
@@ -448,7 +463,7 b' def shortuser(user):' | |||||
448 | return user |
|
463 | return user | |
449 |
|
464 | |||
450 |
|
465 | |||
451 | def emailuser(user): |
|
466 | def emailuser(user: bytes) -> bytes: | |
452 | """Return the user portion of an email address.""" |
|
467 | """Return the user portion of an email address.""" | |
453 | f = user.find(b'@') |
|
468 | f = user.find(b'@') | |
454 | if f >= 0: |
|
469 | if f >= 0: | |
@@ -459,7 +474,7 b' def emailuser(user):' | |||||
459 | return user |
|
474 | return user | |
460 |
|
475 | |||
461 |
|
476 | |||
462 | def email(author): |
|
477 | def email(author: bytes) -> bytes: | |
463 | '''get email of author.''' |
|
478 | '''get email of author.''' | |
464 | r = author.find(b'>') |
|
479 | r = author.find(b'>') | |
465 | if r == -1: |
|
480 | if r == -1: | |
@@ -467,7 +482,7 b' def email(author):' | |||||
467 | return author[author.find(b'<') + 1 : r] |
|
482 | return author[author.find(b'<') + 1 : r] | |
468 |
|
483 | |||
469 |
|
484 | |||
470 | def person(author): |
|
485 | def person(author: bytes) -> bytes: | |
471 | """Returns the name before an email address, |
|
486 | """Returns the name before an email address, | |
472 | interpreting it as per RFC 5322 |
|
487 | interpreting it as per RFC 5322 | |
473 |
|
488 | |||
@@ -612,7 +627,7 b' def parsemailmap(mailmapcontent):' | |||||
612 | return mailmap |
|
627 | return mailmap | |
613 |
|
628 | |||
614 |
|
629 | |||
615 | def mapname(mailmap, author): |
|
630 | def mapname(mailmap, author: bytes) -> bytes: | |
616 | """Returns the author field according to the mailmap cache, or |
|
631 | """Returns the author field according to the mailmap cache, or | |
617 | the original author field. |
|
632 | the original author field. | |
618 |
|
633 | |||
@@ -663,7 +678,7 b' def mapname(mailmap, author):' | |||||
663 | _correctauthorformat = remod.compile(br'^[^<]+\s<[^<>]+@[^<>]+>$') |
|
678 | _correctauthorformat = remod.compile(br'^[^<]+\s<[^<>]+@[^<>]+>$') | |
664 |
|
679 | |||
665 |
|
680 | |||
666 | def isauthorwellformed(author): |
|
681 | def isauthorwellformed(author: bytes) -> bool: | |
667 | """Return True if the author field is well formed |
|
682 | """Return True if the author field is well formed | |
668 | (ie "Contributor Name <contrib@email.dom>") |
|
683 | (ie "Contributor Name <contrib@email.dom>") | |
669 |
|
684 | |||
@@ -685,7 +700,7 b' def isauthorwellformed(author):' | |||||
685 | return _correctauthorformat.match(author) is not None |
|
700 | return _correctauthorformat.match(author) is not None | |
686 |
|
701 | |||
687 |
|
702 | |||
688 | def firstline(text): |
|
703 | def firstline(text: bytes) -> bytes: | |
689 | """Return the first line of the input""" |
|
704 | """Return the first line of the input""" | |
690 | # Try to avoid running splitlines() on the whole string |
|
705 | # Try to avoid running splitlines() on the whole string | |
691 | i = text.find(b'\n') |
|
706 | i = text.find(b'\n') | |
@@ -697,12 +712,13 b' def firstline(text):' | |||||
697 | return b'' |
|
712 | return b'' | |
698 |
|
713 | |||
699 |
|
714 | |||
700 | def ellipsis(text, maxlength=400): |
|
715 | def ellipsis(text: bytes, maxlength: int = 400) -> bytes: | |
701 | """Trim string to at most maxlength (default: 400) columns in display.""" |
|
716 | """Trim string to at most maxlength (default: 400) columns in display.""" | |
702 | return encoding.trim(text, maxlength, ellipsis=b'...') |
|
717 | return encoding.trim(text, maxlength, ellipsis=b'...') | |
703 |
|
718 | |||
704 |
|
719 | |||
705 | def escapestr(s): |
|
720 | def escapestr(s: bytes) -> bytes: | |
|
721 | # "bytes" is also a typing shortcut for bytes, bytearray, and memoryview | |||
706 | if isinstance(s, memoryview): |
|
722 | if isinstance(s, memoryview): | |
707 | s = bytes(s) |
|
723 | s = bytes(s) | |
708 | # call underlying function of s.encode('string_escape') directly for |
|
724 | # call underlying function of s.encode('string_escape') directly for | |
@@ -710,7 +726,7 b' def escapestr(s):' | |||||
710 | return codecs.escape_encode(s)[0] # pytype: disable=module-attr |
|
726 | return codecs.escape_encode(s)[0] # pytype: disable=module-attr | |
711 |
|
727 | |||
712 |
|
728 | |||
713 | def unescapestr(s): |
|
729 | def unescapestr(s: bytes) -> bytes: | |
714 | return codecs.escape_decode(s)[0] # pytype: disable=module-attr |
|
730 | return codecs.escape_decode(s)[0] # pytype: disable=module-attr | |
715 |
|
731 | |||
716 |
|
732 | |||
@@ -724,7 +740,7 b' def forcebytestr(obj):' | |||||
724 | return pycompat.bytestr(encoding.strtolocal(str(obj))) |
|
740 | return pycompat.bytestr(encoding.strtolocal(str(obj))) | |
725 |
|
741 | |||
726 |
|
742 | |||
727 | def uirepr(s): |
|
743 | def uirepr(s: bytes) -> bytes: | |
728 | # Avoid double backslash in Windows path repr() |
|
744 | # Avoid double backslash in Windows path repr() | |
729 | return pycompat.byterepr(pycompat.bytestr(s)).replace(b'\\\\', b'\\') |
|
745 | return pycompat.byterepr(pycompat.bytestr(s)).replace(b'\\\\', b'\\') | |
730 |
|
746 | |||
@@ -838,7 +854,9 b' def _MBTextWrapper(**kwargs):' | |||||
838 | return tw(**kwargs) |
|
854 | return tw(**kwargs) | |
839 |
|
855 | |||
840 |
|
856 | |||
841 | def wrap(line, width, initindent=b'', hangindent=b''): |
|
857 | def wrap( | |
|
858 | line: bytes, width: int, initindent: bytes = b'', hangindent: bytes = b'' | |||
|
859 | ) -> bytes: | |||
842 | maxindent = max(len(hangindent), len(initindent)) |
|
860 | maxindent = max(len(hangindent), len(initindent)) | |
843 | if width <= maxindent: |
|
861 | if width <= maxindent: | |
844 | # adjust for weird terminal size |
|
862 | # adjust for weird terminal size | |
@@ -875,7 +893,7 b" def wrap(line, width, initindent=b'', ha" | |||||
875 | } |
|
893 | } | |
876 |
|
894 | |||
877 |
|
895 | |||
878 | def parsebool(s): |
|
896 | def parsebool(s: bytes) -> Optional[bool]: | |
879 | """Parse s into a boolean. |
|
897 | """Parse s into a boolean. | |
880 |
|
898 | |||
881 | If s is not a valid boolean, returns None. |
|
899 | If s is not a valid boolean, returns None. | |
@@ -883,7 +901,8 b' def parsebool(s):' | |||||
883 | return _booleans.get(s.lower(), None) |
|
901 | return _booleans.get(s.lower(), None) | |
884 |
|
902 | |||
885 |
|
903 | |||
886 | def parselist(value): |
|
904 | # TODO: make arg mandatory (and fix code below?) | |
|
905 | def parselist(value: Optional[bytes]): | |||
887 | """parse a configuration value as a list of comma/space separated strings |
|
906 | """parse a configuration value as a list of comma/space separated strings | |
888 |
|
907 | |||
889 | >>> parselist(b'this,is "a small" ,test') |
|
908 | >>> parselist(b'this,is "a small" ,test') | |
@@ -973,7 +992,7 b' def parselist(value):' | |||||
973 | return result or [] |
|
992 | return result or [] | |
974 |
|
993 | |||
975 |
|
994 | |||
976 | def evalpythonliteral(s): |
|
995 | def evalpythonliteral(s: bytes): | |
977 | """Evaluate a string containing a Python literal expression""" |
|
996 | """Evaluate a string containing a Python literal expression""" | |
978 | # We could backport our tokenizer hack to rewrite '' to u'' if we want |
|
997 | # We could backport our tokenizer hack to rewrite '' to u'' if we want | |
979 | return ast.literal_eval(s.decode('latin1')) |
|
998 | return ast.literal_eval(s.decode('latin1')) |
General Comments 0
You need to be logged in to leave comments.
Login now