Show More
@@ -20,10 +20,15 b' import sys' | |||
|
20 | 20 | import traceback |
|
21 | 21 | |
|
22 | 22 | from typing import ( |
|
23 | Any, | |
|
24 | Callable, | |
|
23 | 25 | Dict, |
|
24 | 26 | List, |
|
27 | NoReturn, | |
|
25 | 28 | Optional, |
|
26 | 29 | Tuple, |
|
30 | Type, | |
|
31 | TypeVar, | |
|
27 | 32 | Union, |
|
28 | 33 | cast, |
|
29 | 34 | ) |
@@ -57,21 +62,23 b' from .utils import (' | |||
|
57 | 62 | urlutil, |
|
58 | 63 | ) |
|
59 | 64 | |
|
65 | _ConfigItems = Dict[Tuple[bytes, bytes], object] # {(section, name) : value} | |
|
60 | 66 | # The **opts args of the various write() methods can be basically anything, but |
|
61 | 67 | # there's no way to express it as "anything but str". So type it to be the |
|
62 | 68 | # handful of known types that are used. |
|
63 | 69 | _MsgOpts = Union[bytes, bool, List["_PromptChoice"]] |
|
64 | 70 | _PromptChoice = Tuple[bytes, bytes] |
|
71 | _Tui = TypeVar('_Tui', bound="ui") | |
|
65 | 72 | |
|
66 | 73 | urlreq = util.urlreq |
|
67 | 74 | |
|
68 | 75 | # for use with str.translate(None, _keepalnum), to keep just alphanumerics |
|
69 | _keepalnum = b''.join( | |
|
76 | _keepalnum: bytes = b''.join( | |
|
70 | 77 | c for c in map(pycompat.bytechr, range(256)) if not c.isalnum() |
|
71 | 78 | ) |
|
72 | 79 | |
|
73 | 80 | # The config knobs that will be altered (if unset) by ui.tweakdefaults. |
|
74 | tweakrc = b""" | |
|
81 | tweakrc: bytes = b""" | |
|
75 | 82 | [ui] |
|
76 | 83 | # The rollback command is dangerous. As a rule, don't use it. |
|
77 | 84 | rollback = False |
@@ -98,7 +105,7 b' showfunc = 1' | |||
|
98 | 105 | word-diff = 1 |
|
99 | 106 | """ |
|
100 | 107 | |
|
101 | samplehgrcs = { | |
|
108 | samplehgrcs: Dict[bytes, bytes] = { | |
|
102 | 109 | b'user': b"""# example user config (see 'hg help config' for more info) |
|
103 | 110 | [ui] |
|
104 | 111 | # name and email, e.g. |
@@ -187,7 +194,7 b' def _maybebytesurl(maybestr):' | |||
|
187 | 194 | class httppasswordmgrdbproxy: |
|
188 | 195 | """Delays loading urllib2 until it's needed.""" |
|
189 | 196 | |
|
190 | def __init__(self): | |
|
197 | def __init__(self) -> None: | |
|
191 | 198 | self._mgr = None |
|
192 | 199 | |
|
193 | 200 | def _get_mgr(self): |
@@ -210,7 +217,7 b' class httppasswordmgrdbproxy:' | |||
|
210 | 217 | ) |
|
211 | 218 | |
|
212 | 219 | |
|
213 | def _catchterm(*args): | |
|
220 | def _catchterm(*args) -> NoReturn: | |
|
214 | 221 | raise error.SignalInterrupt |
|
215 | 222 | |
|
216 | 223 | |
@@ -219,11 +226,11 b' def _catchterm(*args):' | |||
|
219 | 226 | _unset = object() |
|
220 | 227 | |
|
221 | 228 | # _reqexithandlers: callbacks run at the end of a request |
|
222 | _reqexithandlers = [] | |
|
229 | _reqexithandlers: List = [] | |
|
223 | 230 | |
|
224 | 231 | |
|
225 | 232 | class ui: |
|
226 | def __init__(self, src=None): | |
|
233 | def __init__(self, src: Optional["ui"] = None) -> None: | |
|
227 | 234 | """Create a fresh new ui object if no src given |
|
228 | 235 | |
|
229 | 236 | Use uimod.ui.load() to create a ui which knows global and user configs. |
@@ -318,13 +325,13 b' class ui:' | |||
|
318 | 325 | if k in self.environ: |
|
319 | 326 | self._exportableenviron[k] = self.environ[k] |
|
320 | 327 | |
|
321 | def _new_source(self): | |
|
328 | def _new_source(self) -> None: | |
|
322 | 329 | self._ocfg.new_source() |
|
323 | 330 | self._tcfg.new_source() |
|
324 | 331 | self._ucfg.new_source() |
|
325 | 332 | |
|
326 | 333 | @classmethod |
|
327 | def load(cls): | |
|
334 | def load(cls: Type[_Tui]) -> _Tui: | |
|
328 | 335 | """Create a ui and load global and user configs""" |
|
329 | 336 | u = cls() |
|
330 | 337 | # we always trust global config files and environment variables |
@@ -350,7 +357,7 b' class ui:' | |||
|
350 | 357 | u._new_source() # anything after that is a different level |
|
351 | 358 | return u |
|
352 | 359 | |
|
353 | def _maybetweakdefaults(self): | |
|
360 | def _maybetweakdefaults(self) -> None: | |
|
354 | 361 | if not self.configbool(b'ui', b'tweakdefaults'): |
|
355 | 362 | return |
|
356 | 363 | if self._tweaked or self.plain(b'tweakdefaults'): |
@@ -370,17 +377,17 b' class ui:' | |||
|
370 | 377 | if not self.hasconfig(section, name): |
|
371 | 378 | self.setconfig(section, name, value, b"<tweakdefaults>") |
|
372 | 379 | |
|
373 | def copy(self): | |
|
380 | def copy(self: _Tui) -> _Tui: | |
|
374 | 381 | return self.__class__(self) |
|
375 | 382 | |
|
376 | def resetstate(self): | |
|
383 | def resetstate(self) -> None: | |
|
377 | 384 | """Clear internal state that shouldn't persist across commands""" |
|
378 | 385 | if self._progbar: |
|
379 | 386 | self._progbar.resetstate() # reset last-print time of progress bar |
|
380 | 387 | self.httppasswordmgrdb = httppasswordmgrdbproxy() |
|
381 | 388 | |
|
382 | 389 | @contextlib.contextmanager |
|
383 | def timeblockedsection(self, key): | |
|
390 | def timeblockedsection(self, key: bytes): | |
|
384 | 391 | # this is open-coded below - search for timeblockedsection to find them |
|
385 | 392 | starttime = util.timer() |
|
386 | 393 | try: |
@@ -425,10 +432,10 b' class ui:' | |||
|
425 | 432 | finally: |
|
426 | 433 | self._uninterruptible = False |
|
427 | 434 | |
|
428 | def formatter(self, topic, opts): | |
|
435 | def formatter(self, topic: bytes, opts): | |
|
429 | 436 | return formatter.formatter(self, self, topic, opts) |
|
430 | 437 | |
|
431 | def _trusted(self, fp, f): | |
|
438 | def _trusted(self, fp, f: bytes) -> bool: | |
|
432 | 439 | st = util.fstat(fp) |
|
433 | 440 | if util.isowner(st): |
|
434 | 441 | return True |
@@ -454,7 +461,7 b' class ui:' | |||
|
454 | 461 | |
|
455 | 462 | def read_resource_config( |
|
456 | 463 | self, name, root=None, trust=False, sections=None, remap=None |
|
457 | ): | |
|
464 | ) -> None: | |
|
458 | 465 | try: |
|
459 | 466 | fp = resourceutil.open_resource(name[0], name[1]) |
|
460 | 467 | except IOError: |
@@ -468,7 +475,7 b' class ui:' | |||
|
468 | 475 | |
|
469 | 476 | def readconfig( |
|
470 | 477 | self, filename, root=None, trust=False, sections=None, remap=None |
|
471 | ): | |
|
478 | ) -> None: | |
|
472 | 479 | try: |
|
473 | 480 | fp = open(filename, 'rb') |
|
474 | 481 | except IOError: |
@@ -480,7 +487,7 b' class ui:' | |||
|
480 | 487 | |
|
481 | 488 | def _readconfig( |
|
482 | 489 | self, filename, fp, root=None, trust=False, sections=None, remap=None |
|
483 | ): | |
|
490 | ) -> None: | |
|
484 | 491 | with fp: |
|
485 | 492 | cfg = config.config() |
|
486 | 493 | trusted = sections or trust or self._trusted(fp, filename) |
@@ -496,7 +503,9 b' class ui:' | |||
|
496 | 503 | |
|
497 | 504 | self._applyconfig(cfg, trusted, root) |
|
498 | 505 | |
|
499 | def applyconfig(self, configitems, source=b"", root=None): | |
|
506 | def applyconfig( | |
|
507 | self, configitems: _ConfigItems, source=b"", root=None | |
|
508 | ) -> None: | |
|
500 | 509 | """Add configitems from a non-file source. Unlike with ``setconfig()``, |
|
501 | 510 | they can be overridden by subsequent config file reads. The items are |
|
502 | 511 | in the same format as ``configoverride()``, namely a dict of the |
@@ -512,7 +521,7 b' class ui:' | |||
|
512 | 521 | |
|
513 | 522 | self._applyconfig(cfg, True, root) |
|
514 | 523 | |
|
515 | def _applyconfig(self, cfg, trusted, root): | |
|
524 | def _applyconfig(self, cfg, trusted, root) -> None: | |
|
516 | 525 | if self.plain(): |
|
517 | 526 | for k in ( |
|
518 | 527 | b'debug', |
@@ -555,7 +564,7 b' class ui:' | |||
|
555 | 564 | root = os.path.expanduser(b'~') |
|
556 | 565 | self.fixconfig(root=root) |
|
557 | 566 | |
|
558 | def fixconfig(self, root=None, section=None): | |
|
567 | def fixconfig(self, root=None, section=None) -> None: | |
|
559 | 568 | if section in (None, b'paths'): |
|
560 | 569 | # expand vars and ~ |
|
561 | 570 | # translate paths relative to root (or home) into absolute paths |
@@ -618,12 +627,12 b' class ui:' | |||
|
618 | 627 | self._ucfg.backup(section, item), |
|
619 | 628 | ) |
|
620 | 629 | |
|
621 | def restoreconfig(self, data): | |
|
630 | def restoreconfig(self, data) -> None: | |
|
622 | 631 | self._ocfg.restore(data[0]) |
|
623 | 632 | self._tcfg.restore(data[1]) |
|
624 | 633 | self._ucfg.restore(data[2]) |
|
625 | 634 | |
|
626 | def setconfig(self, section, name, value, source=b''): | |
|
635 | def setconfig(self, section, name, value, source=b'') -> None: | |
|
627 | 636 | for cfg in (self._ocfg, self._tcfg, self._ucfg): |
|
628 | 637 | cfg.set(section, name, value, source) |
|
629 | 638 | self.fixconfig(section=section) |
@@ -1009,7 +1018,7 b' class ui:' | |||
|
1009 | 1018 | for name, value in self.configitems(section, untrusted): |
|
1010 | 1019 | yield section, name, value |
|
1011 | 1020 | |
|
1012 | def plain(self, feature=None): | |
|
1021 | def plain(self, feature: Optional[bytes] = None) -> bool: | |
|
1013 | 1022 | """is plain mode active? |
|
1014 | 1023 | |
|
1015 | 1024 | Plain mode means that all configuration variables which affect |
@@ -1083,7 +1092,7 b' class ui:' | |||
|
1083 | 1092 | ) |
|
1084 | 1093 | return user |
|
1085 | 1094 | |
|
1086 | def shortuser(self, user): | |
|
1095 | def shortuser(self, user: bytes) -> bytes: | |
|
1087 | 1096 | """Return a short representation of a user name or email address.""" |
|
1088 | 1097 | if not self.verbose: |
|
1089 | 1098 | user = stringutil.shortuser(user) |
@@ -1161,14 +1170,18 b' class ui:' | |||
|
1161 | 1170 | self._fmsgout, self._fmsgerr = _selectmsgdests(self) |
|
1162 | 1171 | |
|
1163 | 1172 | @contextlib.contextmanager |
|
1164 | def silent(self, error=False, subproc=False, labeled=False): | |
|
1173 | def silent( | |
|
1174 | self, error: bool = False, subproc: bool = False, labeled: bool = False | |
|
1175 | ): | |
|
1165 | 1176 | self.pushbuffer(error=error, subproc=subproc, labeled=labeled) |
|
1166 | 1177 | try: |
|
1167 | 1178 | yield |
|
1168 | 1179 | finally: |
|
1169 | 1180 | self.popbuffer() |
|
1170 | 1181 | |
|
1171 | def pushbuffer(self, error=False, subproc=False, labeled=False): | |
|
1182 | def pushbuffer( | |
|
1183 | self, error: bool = False, subproc: bool = False, labeled: bool = False | |
|
1184 | ) -> None: | |
|
1172 | 1185 | """install a buffer to capture standard output of the ui object |
|
1173 | 1186 | |
|
1174 | 1187 | If error is True, the error output will be captured too. |
@@ -1187,7 +1200,7 b' class ui:' | |||
|
1187 | 1200 | self._bufferstates.append((error, subproc, labeled)) |
|
1188 | 1201 | self._bufferapplylabels = labeled |
|
1189 | 1202 | |
|
1190 | def popbuffer(self): | |
|
1203 | def popbuffer(self) -> bytes: | |
|
1191 | 1204 | '''pop the last buffer and return the buffered output''' |
|
1192 | 1205 | self._bufferstates.pop() |
|
1193 | 1206 | if self._bufferstates: |
@@ -1197,20 +1210,20 b' class ui:' | |||
|
1197 | 1210 | |
|
1198 | 1211 | return b"".join(self._buffers.pop()) |
|
1199 | 1212 | |
|
1200 | def _isbuffered(self, dest): | |
|
1213 | def _isbuffered(self, dest) -> bool: | |
|
1201 | 1214 | if dest is self._fout: |
|
1202 | 1215 | return bool(self._buffers) |
|
1203 | 1216 | if dest is self._ferr: |
|
1204 | 1217 | return bool(self._bufferstates and self._bufferstates[-1][0]) |
|
1205 | 1218 | return False |
|
1206 | 1219 | |
|
1207 | def canwritewithoutlabels(self): | |
|
1220 | def canwritewithoutlabels(self) -> bool: | |
|
1208 | 1221 | '''check if write skips the label''' |
|
1209 | 1222 | if self._buffers and not self._bufferapplylabels: |
|
1210 | 1223 | return True |
|
1211 | 1224 | return self._colormode is None |
|
1212 | 1225 | |
|
1213 | def canbatchlabeledwrites(self): | |
|
1226 | def canbatchlabeledwrites(self) -> bool: | |
|
1214 | 1227 | '''check if write calls with labels are batchable''' |
|
1215 | 1228 | # Windows color printing is special, see ``write``. |
|
1216 | 1229 | return self._colormode != b'win32' |
@@ -1369,7 +1382,7 b' class ui:' | |||
|
1369 | 1382 | util.timer() - starttime |
|
1370 | 1383 | ) * 1000 |
|
1371 | 1384 | |
|
1372 | def _isatty(self, fh): | |
|
1385 | def _isatty(self, fh) -> bool: | |
|
1373 | 1386 | if self.configbool(b'ui', b'nontty'): |
|
1374 | 1387 | return False |
|
1375 | 1388 | return procutil.isatty(fh) |
@@ -1407,10 +1420,10 b' class ui:' | |||
|
1407 | 1420 | finally: |
|
1408 | 1421 | self.restorefinout(fin, fout) |
|
1409 | 1422 | |
|
1410 | def disablepager(self): | |
|
1423 | def disablepager(self) -> None: | |
|
1411 | 1424 | self._disablepager = True |
|
1412 | 1425 | |
|
1413 | def pager(self, command): | |
|
1426 | def pager(self, command: bytes) -> None: | |
|
1414 | 1427 | """Start a pager for subsequent command output. |
|
1415 | 1428 | |
|
1416 | 1429 | Commands which produce a long stream of output should call |
@@ -1491,7 +1504,7 b' class ui:' | |||
|
1491 | 1504 | # warning about a missing pager command. |
|
1492 | 1505 | self.disablepager() |
|
1493 | 1506 | |
|
1494 | def _runpager(self, command, env=None): | |
|
1507 | def _runpager(self, command: bytes, env=None) -> bool: | |
|
1495 | 1508 | """Actually start the pager and set up file descriptors. |
|
1496 | 1509 | |
|
1497 | 1510 | This is separate in part so that extensions (like chg) can |
@@ -1571,7 +1584,7 b' class ui:' | |||
|
1571 | 1584 | self._exithandlers.append((func, args, kwargs)) |
|
1572 | 1585 | return func |
|
1573 | 1586 | |
|
1574 | def interface(self, feature): | |
|
1587 | def interface(self, feature: bytes) -> bytes: | |
|
1575 | 1588 | """what interface to use for interactive console features? |
|
1576 | 1589 | |
|
1577 | 1590 | The interface is controlled by the value of `ui.interface` but also by |
@@ -1626,12 +1639,12 b' class ui:' | |||
|
1626 | 1639 | defaultinterface = b"text" |
|
1627 | 1640 | i = self.config(b"ui", b"interface") |
|
1628 | 1641 | if i in alldefaults: |
|
1629 | defaultinterface = i | |
|
1642 | defaultinterface = cast(bytes, i) # cast to help pytype | |
|
1630 | 1643 | |
|
1631 | choseninterface = defaultinterface | |
|
1644 | choseninterface: bytes = defaultinterface | |
|
1632 | 1645 | f = self.config(b"ui", b"interface.%s" % feature) |
|
1633 | 1646 | if f in availableinterfaces: |
|
1634 | choseninterface = f | |
|
1647 | choseninterface = cast(bytes, f) # cast to help pytype | |
|
1635 | 1648 | |
|
1636 | 1649 | if i is not None and defaultinterface != i: |
|
1637 | 1650 | if f is not None: |
@@ -1671,7 +1684,7 b' class ui:' | |||
|
1671 | 1684 | |
|
1672 | 1685 | return i |
|
1673 | 1686 | |
|
1674 | def termwidth(self): | |
|
1687 | def termwidth(self) -> int: | |
|
1675 | 1688 | """how wide is the terminal in columns?""" |
|
1676 | 1689 | if b'COLUMNS' in encoding.environ: |
|
1677 | 1690 | try: |
@@ -1918,14 +1931,14 b' class ui:' | |||
|
1918 | 1931 | |
|
1919 | 1932 | def edit( |
|
1920 | 1933 | self, |
|
1921 | text, | |
|
1922 | user, | |
|
1923 | extra=None, | |
|
1934 | text: bytes, | |
|
1935 | user: bytes, | |
|
1936 | extra: Optional[Dict[bytes, Any]] = None, # TODO: value type of bytes? | |
|
1924 | 1937 | editform=None, |
|
1925 | 1938 | pending=None, |
|
1926 | repopath=None, | |
|
1927 | action=None, | |
|
1928 | ): | |
|
1939 | repopath: Optional[bytes] = None, | |
|
1940 | action: Optional[bytes] = None, | |
|
1941 | ) -> bytes: | |
|
1929 | 1942 | if action is None: |
|
1930 | 1943 | self.develwarn( |
|
1931 | 1944 | b'action is None but will soon be a required ' |
@@ -1994,13 +2007,13 b' class ui:' | |||
|
1994 | 2007 | |
|
1995 | 2008 | def system( |
|
1996 | 2009 | self, |
|
1997 | cmd, | |
|
2010 | cmd: bytes, | |
|
1998 | 2011 | environ=None, |
|
1999 | cwd=None, | |
|
2000 | onerr=None, | |
|
2001 | errprefix=None, | |
|
2002 | blockedtag=None, | |
|
2003 | ): | |
|
2012 | cwd: Optional[bytes] = None, | |
|
2013 | onerr: Optional[Callable[[bytes], Exception]] = None, | |
|
2014 | errprefix: Optional[bytes] = None, | |
|
2015 | blockedtag: Optional[bytes] = None, | |
|
2016 | ) -> int: | |
|
2004 | 2017 | """execute shell command with appropriate output stream. command |
|
2005 | 2018 | output will be redirected if fout is not stdout. |
|
2006 | 2019 | |
@@ -2027,12 +2040,12 b' class ui:' | |||
|
2027 | 2040 | raise onerr(errmsg) |
|
2028 | 2041 | return rc |
|
2029 | 2042 | |
|
2030 | def _runsystem(self, cmd, environ, cwd, out): | |
|
2043 | def _runsystem(self, cmd: bytes, environ, cwd: Optional[bytes], out) -> int: | |
|
2031 | 2044 | """actually execute the given shell command (can be overridden by |
|
2032 | 2045 | extensions like chg)""" |
|
2033 | 2046 | return procutil.system(cmd, environ=environ, cwd=cwd, out=out) |
|
2034 | 2047 | |
|
2035 | def traceback(self, exc=None, force=False): | |
|
2048 | def traceback(self, exc=None, force: bool = False): | |
|
2036 | 2049 | """print exception traceback if traceback printing enabled or forced. |
|
2037 | 2050 | only to call in exception handler. returns true if traceback |
|
2038 | 2051 | printed.""" |
@@ -2130,7 +2143,7 b' class ui:' | |||
|
2130 | 2143 | """Returns a logger of the given name; or None if not registered""" |
|
2131 | 2144 | return self._loggers.get(name) |
|
2132 | 2145 | |
|
2133 | def setlogger(self, name, logger): | |
|
2146 | def setlogger(self, name, logger) -> None: | |
|
2134 | 2147 | """Install logger which can be identified later by the given name |
|
2135 | 2148 | |
|
2136 | 2149 | More than one loggers can be registered. Use extension or module |
@@ -2138,7 +2151,7 b' class ui:' | |||
|
2138 | 2151 | """ |
|
2139 | 2152 | self._loggers[name] = logger |
|
2140 | 2153 | |
|
2141 | def log(self, event, msgfmt, *msgargs, **opts): | |
|
2154 | def log(self, event, msgfmt, *msgargs, **opts) -> None: | |
|
2142 | 2155 | """hook for logging facility extensions |
|
2143 | 2156 | |
|
2144 | 2157 | event should be a readily-identifiable subsystem, which will |
@@ -2239,7 +2252,7 b' class ui:' | |||
|
2239 | 2252 | return self._exportableenviron |
|
2240 | 2253 | |
|
2241 | 2254 | @contextlib.contextmanager |
|
2242 | def configoverride(self, overrides, source=b""): | |
|
2255 | def configoverride(self, overrides: _ConfigItems, source: bytes = b""): | |
|
2243 | 2256 | """Context manager for temporary config overrides |
|
2244 | 2257 | `overrides` must be a dict of the following structure: |
|
2245 | 2258 | {(section, name) : value}""" |
@@ -2257,7 +2270,7 b' class ui:' | |||
|
2257 | 2270 | if (b'ui', b'quiet') in overrides: |
|
2258 | 2271 | self.fixconfig(section=b'ui') |
|
2259 | 2272 | |
|
2260 | def estimatememory(self): | |
|
2273 | def estimatememory(self) -> Optional[int]: | |
|
2261 | 2274 | """Provide an estimate for the available system memory in Bytes. |
|
2262 | 2275 | |
|
2263 | 2276 | This can be overriden via ui.available-memory. It returns None, if |
@@ -2292,7 +2305,7 b' def haveprogbar() -> bool:' | |||
|
2292 | 2305 | return _progresssingleton is not None |
|
2293 | 2306 | |
|
2294 | 2307 | |
|
2295 | def _selectmsgdests(ui): | |
|
2308 | def _selectmsgdests(ui: ui): | |
|
2296 | 2309 | name = ui.config(b'ui', b'message-output') |
|
2297 | 2310 | if name == b'channel': |
|
2298 | 2311 | if ui.fmsg: |
General Comments 0
You need to be logged in to leave comments.
Login now