##// END OF EJS Templates
typing: add trivial type hints to mercurial/ui.py...
Matt Harbison -
r50692:0449fb77 default
parent child Browse files
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