##// END OF EJS Templates
typing: add type hints to mercurial/help.py...
Matt Harbison -
r50541:2a70d1fc default
parent child Browse files
Show More
@@ -10,6 +10,18 b' import itertools'
10 import re
10 import re
11 import textwrap
11 import textwrap
12
12
13 from typing import (
14 Callable,
15 Dict,
16 Iterable,
17 List,
18 Optional,
19 Set,
20 Tuple,
21 Union,
22 cast,
23 )
24
13 from .i18n import (
25 from .i18n import (
14 _,
26 _,
15 gettext,
27 gettext,
@@ -40,7 +52,16 b' from .utils import ('
40 stringutil,
52 stringutil,
41 )
53 )
42
54
43 _exclkeywords = {
55 _DocLoader = Callable[[uimod.ui], bytes]
56 # Old extensions may not register with a category
57 _HelpEntry = Union["_HelpEntryNoCategory", "_HelpEntryWithCategory"]
58 _HelpEntryNoCategory = Tuple[List[bytes], bytes, _DocLoader]
59 _HelpEntryWithCategory = Tuple[List[bytes], bytes, _DocLoader, bytes]
60 _SelectFn = Callable[[object], bool]
61 _SynonymTable = Dict[bytes, List[bytes]]
62 _TopicHook = Callable[[uimod.ui, bytes, bytes], bytes]
63
64 _exclkeywords: Set[bytes] = {
44 b"(ADVANCED)",
65 b"(ADVANCED)",
45 b"(DEPRECATED)",
66 b"(DEPRECATED)",
46 b"(EXPERIMENTAL)",
67 b"(EXPERIMENTAL)",
@@ -56,7 +77,7 b' from .utils import ('
56 # Extensions with custom categories should insert them into this list
77 # Extensions with custom categories should insert them into this list
57 # after/before the appropriate item, rather than replacing the list or
78 # after/before the appropriate item, rather than replacing the list or
58 # assuming absolute positions.
79 # assuming absolute positions.
59 CATEGORY_ORDER = [
80 CATEGORY_ORDER: List[bytes] = [
60 registrar.command.CATEGORY_REPO_CREATION,
81 registrar.command.CATEGORY_REPO_CREATION,
61 registrar.command.CATEGORY_REMOTE_REPO_MANAGEMENT,
82 registrar.command.CATEGORY_REMOTE_REPO_MANAGEMENT,
62 registrar.command.CATEGORY_COMMITTING,
83 registrar.command.CATEGORY_COMMITTING,
@@ -74,7 +95,7 b' CATEGORY_ORDER = ['
74
95
75 # Human-readable category names. These are translated.
96 # Human-readable category names. These are translated.
76 # Extensions with custom categories should add their names here.
97 # Extensions with custom categories should add their names here.
77 CATEGORY_NAMES = {
98 CATEGORY_NAMES: Dict[bytes, bytes] = {
78 registrar.command.CATEGORY_REPO_CREATION: b'Repository creation',
99 registrar.command.CATEGORY_REPO_CREATION: b'Repository creation',
79 registrar.command.CATEGORY_REMOTE_REPO_MANAGEMENT: b'Remote repository management',
100 registrar.command.CATEGORY_REMOTE_REPO_MANAGEMENT: b'Remote repository management',
80 registrar.command.CATEGORY_COMMITTING: b'Change creation',
101 registrar.command.CATEGORY_COMMITTING: b'Change creation',
@@ -102,7 +123,7 b" TOPIC_CATEGORY_NONE = b'none'"
102 # Extensions with custom categories should insert them into this list
123 # Extensions with custom categories should insert them into this list
103 # after/before the appropriate item, rather than replacing the list or
124 # after/before the appropriate item, rather than replacing the list or
104 # assuming absolute positions.
125 # assuming absolute positions.
105 TOPIC_CATEGORY_ORDER = [
126 TOPIC_CATEGORY_ORDER: List[bytes] = [
106 TOPIC_CATEGORY_IDS,
127 TOPIC_CATEGORY_IDS,
107 TOPIC_CATEGORY_OUTPUT,
128 TOPIC_CATEGORY_OUTPUT,
108 TOPIC_CATEGORY_CONFIG,
129 TOPIC_CATEGORY_CONFIG,
@@ -112,7 +133,7 b' TOPIC_CATEGORY_ORDER = ['
112 ]
133 ]
113
134
114 # Human-readable topic category names. These are translated.
135 # Human-readable topic category names. These are translated.
115 TOPIC_CATEGORY_NAMES = {
136 TOPIC_CATEGORY_NAMES: Dict[bytes, bytes] = {
116 TOPIC_CATEGORY_IDS: b'Mercurial identifiers',
137 TOPIC_CATEGORY_IDS: b'Mercurial identifiers',
117 TOPIC_CATEGORY_OUTPUT: b'Mercurial output',
138 TOPIC_CATEGORY_OUTPUT: b'Mercurial output',
118 TOPIC_CATEGORY_CONFIG: b'Mercurial configuration',
139 TOPIC_CATEGORY_CONFIG: b'Mercurial configuration',
@@ -122,7 +143,12 b' TOPIC_CATEGORY_NAMES = {'
122 }
143 }
123
144
124
145
125 def listexts(header, exts, indent=1, showdeprecated=False):
146 def listexts(
147 header: bytes,
148 exts: Dict[bytes, bytes],
149 indent: int = 1,
150 showdeprecated: bool = False,
151 ) -> List[bytes]:
126 '''return a text listing of the given extensions'''
152 '''return a text listing of the given extensions'''
127 rst = []
153 rst = []
128 if exts:
154 if exts:
@@ -135,7 +161,7 b' def listexts(header, exts, indent=1, sho'
135 return rst
161 return rst
136
162
137
163
138 def extshelp(ui):
164 def extshelp(ui: uimod.ui) -> bytes:
139 rst = loaddoc(b'extensions')(ui).splitlines(True)
165 rst = loaddoc(b'extensions')(ui).splitlines(True)
140 rst.extend(
166 rst.extend(
141 listexts(
167 listexts(
@@ -153,7 +179,7 b' def extshelp(ui):'
153 return doc
179 return doc
154
180
155
181
156 def parsedefaultmarker(text):
182 def parsedefaultmarker(text: bytes) -> Optional[Tuple[bytes, List[bytes]]]:
157 """given a text 'abc (DEFAULT: def.ghi)',
183 """given a text 'abc (DEFAULT: def.ghi)',
158 returns (b'abc', (b'def', b'ghi')). Otherwise return None"""
184 returns (b'abc', (b'def', b'ghi')). Otherwise return None"""
159 if text[-1:] == b')':
185 if text[-1:] == b')':
@@ -164,7 +190,7 b' def parsedefaultmarker(text):'
164 return text[:pos], item.split(b'.', 2)
190 return text[:pos], item.split(b'.', 2)
165
191
166
192
167 def optrst(header, options, verbose, ui):
193 def optrst(header: bytes, options, verbose: bool, ui: uimod.ui) -> bytes:
168 data = []
194 data = []
169 multioccur = False
195 multioccur = False
170 for option in options:
196 for option in options:
@@ -220,13 +246,15 b' def optrst(header, options, verbose, ui)'
220 return b''.join(rst)
246 return b''.join(rst)
221
247
222
248
223 def indicateomitted(rst, omitted, notomitted=None):
249 def indicateomitted(
250 rst: List[bytes], omitted: bytes, notomitted: Optional[bytes] = None
251 ) -> None:
224 rst.append(b'\n\n.. container:: omitted\n\n %s\n\n' % omitted)
252 rst.append(b'\n\n.. container:: omitted\n\n %s\n\n' % omitted)
225 if notomitted:
253 if notomitted:
226 rst.append(b'\n\n.. container:: notomitted\n\n %s\n\n' % notomitted)
254 rst.append(b'\n\n.. container:: notomitted\n\n %s\n\n' % notomitted)
227
255
228
256
229 def filtercmd(ui, cmd, func, kw, doc):
257 def filtercmd(ui: uimod.ui, cmd: bytes, func, kw: bytes, doc: bytes) -> bool:
230 if not ui.debugflag and cmd.startswith(b"debug") and kw != b"debug":
258 if not ui.debugflag and cmd.startswith(b"debug") and kw != b"debug":
231 # Debug command, and user is not looking for those.
259 # Debug command, and user is not looking for those.
232 return True
260 return True
@@ -249,11 +277,13 b' def filtercmd(ui, cmd, func, kw, doc):'
249 return False
277 return False
250
278
251
279
252 def filtertopic(ui, topic):
280 def filtertopic(ui: uimod.ui, topic: bytes) -> bool:
253 return ui.configbool(b'help', b'hidden-topic.%s' % topic, False)
281 return ui.configbool(b'help', b'hidden-topic.%s' % topic, False)
254
282
255
283
256 def topicmatch(ui, commands, kw):
284 def topicmatch(
285 ui: uimod.ui, commands, kw: bytes
286 ) -> Dict[bytes, List[Tuple[bytes, bytes]]]:
257 """Return help topics matching kw.
287 """Return help topics matching kw.
258
288
259 Returns {'section': [(name, summary), ...], ...} where section is
289 Returns {'section': [(name, summary), ...], ...} where section is
@@ -326,10 +356,10 b' def topicmatch(ui, commands, kw):'
326 return results
356 return results
327
357
328
358
329 def loaddoc(topic, subdir=None):
359 def loaddoc(topic: bytes, subdir: Optional[bytes] = None) -> _DocLoader:
330 """Return a delayed loader for help/topic.txt."""
360 """Return a delayed loader for help/topic.txt."""
331
361
332 def loader(ui):
362 def loader(ui: uimod.ui) -> bytes:
333 package = b'mercurial.helptext'
363 package = b'mercurial.helptext'
334 if subdir:
364 if subdir:
335 package += b'.' + subdir
365 package += b'.' + subdir
@@ -342,7 +372,7 b' def loaddoc(topic, subdir=None):'
342 return loader
372 return loader
343
373
344
374
345 internalstable = sorted(
375 internalstable: List[_HelpEntryNoCategory] = sorted(
346 [
376 [
347 (
377 (
348 [b'bid-merge'],
378 [b'bid-merge'],
@@ -407,7 +437,7 b' internalstable = sorted('
407 )
437 )
408
438
409
439
410 def internalshelp(ui):
440 def internalshelp(ui: uimod.ui) -> bytes:
411 """Generate the index for the "internals" topic."""
441 """Generate the index for the "internals" topic."""
412 lines = [
442 lines = [
413 b'To access a subtopic, use "hg help internals.{subtopic-name}"\n',
443 b'To access a subtopic, use "hg help internals.{subtopic-name}"\n',
@@ -419,7 +449,7 b' def internalshelp(ui):'
419 return b''.join(lines)
449 return b''.join(lines)
420
450
421
451
422 helptable = sorted(
452 helptable: List[_HelpEntryWithCategory] = sorted(
423 [
453 [
424 (
454 (
425 [b'bundlespec'],
455 [b'bundlespec'],
@@ -581,20 +611,27 b' helptable = sorted('
581 )
611 )
582
612
583 # Maps topics with sub-topics to a list of their sub-topics.
613 # Maps topics with sub-topics to a list of their sub-topics.
584 subtopics = {
614 subtopics: Dict[bytes, List[_HelpEntryNoCategory]] = {
585 b'internals': internalstable,
615 b'internals': internalstable,
586 }
616 }
587
617
588 # Map topics to lists of callable taking the current topic help and
618 # Map topics to lists of callable taking the current topic help and
589 # returning the updated version
619 # returning the updated version
590 helphooks = {}
620 helphooks: Dict[bytes, List[_TopicHook]] = {}
591
621
592
622
593 def addtopichook(topic, rewriter):
623 def addtopichook(topic: bytes, rewriter: _TopicHook) -> None:
594 helphooks.setdefault(topic, []).append(rewriter)
624 helphooks.setdefault(topic, []).append(rewriter)
595
625
596
626
597 def makeitemsdoc(ui, topic, doc, marker, items, dedent=False):
627 def makeitemsdoc(
628 ui: uimod.ui,
629 topic: bytes,
630 doc: bytes,
631 marker: bytes,
632 items: Dict[bytes, bytes],
633 dedent: bool = False,
634 ) -> bytes:
598 """Extract docstring from the items key to function mapping, build a
635 """Extract docstring from the items key to function mapping, build a
599 single documentation block and use it to overwrite the marker in doc.
636 single documentation block and use it to overwrite the marker in doc.
600 """
637 """
@@ -622,8 +659,10 b' def makeitemsdoc(ui, topic, doc, marker,'
622 return doc.replace(marker, entries)
659 return doc.replace(marker, entries)
623
660
624
661
625 def addtopicsymbols(topic, marker, symbols, dedent=False):
662 def addtopicsymbols(
626 def add(ui, topic, doc):
663 topic: bytes, marker: bytes, symbols, dedent: bool = False
664 ) -> None:
665 def add(ui: uimod.ui, topic: bytes, doc: bytes):
627 return makeitemsdoc(ui, topic, doc, marker, symbols, dedent=dedent)
666 return makeitemsdoc(ui, topic, doc, marker, symbols, dedent=dedent)
628
667
629 addtopichook(topic, add)
668 addtopichook(topic, add)
@@ -647,7 +686,7 b' addtopicsymbols('
647 )
686 )
648
687
649
688
650 def inserttweakrc(ui, topic, doc):
689 def inserttweakrc(ui: uimod.ui, topic: bytes, doc: bytes) -> bytes:
651 marker = b'.. tweakdefaultsmarker'
690 marker = b'.. tweakdefaultsmarker'
652 repl = uimod.tweakrc
691 repl = uimod.tweakrc
653
692
@@ -658,7 +697,9 b' def inserttweakrc(ui, topic, doc):'
658 return re.sub(br'( *)%s' % re.escape(marker), sub, doc)
697 return re.sub(br'( *)%s' % re.escape(marker), sub, doc)
659
698
660
699
661 def _getcategorizedhelpcmds(ui, cmdtable, name, select=None):
700 def _getcategorizedhelpcmds(
701 ui: uimod.ui, cmdtable, name: bytes, select: Optional[_SelectFn] = None
702 ) -> Tuple[Dict[bytes, List[bytes]], Dict[bytes, bytes], _SynonymTable]:
662 # Category -> list of commands
703 # Category -> list of commands
663 cats = {}
704 cats = {}
664 # Command -> short description
705 # Command -> short description
@@ -687,16 +728,18 b' def _getcategorizedhelpcmds(ui, cmdtable'
687 return cats, h, syns
728 return cats, h, syns
688
729
689
730
690 def _getcategorizedhelptopics(ui, topictable):
731 def _getcategorizedhelptopics(
732 ui: uimod.ui, topictable: List[_HelpEntry]
733 ) -> Tuple[Dict[bytes, List[Tuple[bytes, bytes]]], Dict[bytes, List[bytes]]]:
691 # Group commands by category.
734 # Group commands by category.
692 topiccats = {}
735 topiccats = {}
693 syns = {}
736 syns = {}
694 for topic in topictable:
737 for topic in topictable:
695 names, header, doc = topic[0:3]
738 names, header, doc = topic[0:3]
696 if len(topic) > 3 and topic[3]:
739 if len(topic) > 3 and topic[3]:
697 category = topic[3]
740 category: bytes = cast(bytes, topic[3]) # help pytype
698 else:
741 else:
699 category = TOPIC_CATEGORY_NONE
742 category: bytes = TOPIC_CATEGORY_NONE
700
743
701 topicname = names[0]
744 topicname = names[0]
702 syns[topicname] = list(names)
745 syns[topicname] = list(names)
@@ -709,15 +752,15 b" addtopichook(b'config', inserttweakrc)"
709
752
710
753
711 def help_(
754 def help_(
712 ui,
755 ui: uimod.ui,
713 commands,
756 commands,
714 name,
757 name: bytes,
715 unknowncmd=False,
758 unknowncmd: bool = False,
716 full=True,
759 full: bool = True,
717 subtopic=None,
760 subtopic: Optional[bytes] = None,
718 fullname=None,
761 fullname: Optional[bytes] = None,
719 **opts
762 **opts
720 ):
763 ) -> bytes:
721 """
764 """
722 Generate the help for 'name' as unformatted restructured text. If
765 Generate the help for 'name' as unformatted restructured text. If
723 'name' is None, describe the commands available.
766 'name' is None, describe the commands available.
@@ -725,7 +768,7 b' def help_('
725
768
726 opts = pycompat.byteskwargs(opts)
769 opts = pycompat.byteskwargs(opts)
727
770
728 def helpcmd(name, subtopic=None):
771 def helpcmd(name: bytes, subtopic: Optional[bytes]) -> List[bytes]:
729 try:
772 try:
730 aliases, entry = cmdutil.findcmd(
773 aliases, entry = cmdutil.findcmd(
731 name, commands.table, strict=unknowncmd
774 name, commands.table, strict=unknowncmd
@@ -826,7 +869,7 b' def help_('
826
869
827 return rst
870 return rst
828
871
829 def helplist(select=None, **opts):
872 def helplist(select: Optional[_SelectFn] = None, **opts) -> List[bytes]:
830 cats, h, syns = _getcategorizedhelpcmds(
873 cats, h, syns = _getcategorizedhelpcmds(
831 ui, commands.table, name, select
874 ui, commands.table, name, select
832 )
875 )
@@ -846,7 +889,7 b' def help_('
846 else:
889 else:
847 rst.append(_(b'list of commands:\n'))
890 rst.append(_(b'list of commands:\n'))
848
891
849 def appendcmds(cmds):
892 def appendcmds(cmds: Iterable[bytes]) -> None:
850 cmds = sorted(cmds)
893 cmds = sorted(cmds)
851 for c in cmds:
894 for c in cmds:
852 display_cmd = c
895 display_cmd = c
@@ -955,7 +998,7 b' def help_('
955 )
998 )
956 return rst
999 return rst
957
1000
958 def helptopic(name, subtopic=None):
1001 def helptopic(name: bytes, subtopic: Optional[bytes] = None) -> List[bytes]:
959 # Look for sub-topic entry first.
1002 # Look for sub-topic entry first.
960 header, doc = None, None
1003 header, doc = None, None
961 if subtopic and name in subtopics:
1004 if subtopic and name in subtopics:
@@ -998,7 +1041,7 b' def help_('
998 pass
1041 pass
999 return rst
1042 return rst
1000
1043
1001 def helpext(name, subtopic=None):
1044 def helpext(name: bytes, subtopic: Optional[bytes] = None) -> List[bytes]:
1002 try:
1045 try:
1003 mod = extensions.find(name)
1046 mod = extensions.find(name)
1004 doc = gettext(pycompat.getdoc(mod)) or _(b'no help text available')
1047 doc = gettext(pycompat.getdoc(mod)) or _(b'no help text available')
@@ -1040,7 +1083,9 b' def help_('
1040 )
1083 )
1041 return rst
1084 return rst
1042
1085
1043 def helpextcmd(name, subtopic=None):
1086 def helpextcmd(
1087 name: bytes, subtopic: Optional[bytes] = None
1088 ) -> List[bytes]:
1044 cmd, ext, doc = extensions.disabledcmd(
1089 cmd, ext, doc = extensions.disabledcmd(
1045 ui, name, ui.configbool(b'ui', b'strict')
1090 ui, name, ui.configbool(b'ui', b'strict')
1046 )
1091 )
@@ -1127,8 +1172,14 b' def help_('
1127
1172
1128
1173
1129 def formattedhelp(
1174 def formattedhelp(
1130 ui, commands, fullname, keep=None, unknowncmd=False, full=True, **opts
1175 ui: uimod.ui,
1131 ):
1176 commands,
1177 fullname: Optional[bytes],
1178 keep: Optional[Iterable[bytes]] = None,
1179 unknowncmd: bool = False,
1180 full: bool = True,
1181 **opts
1182 ) -> bytes:
1132 """get help for a given topic (as a dotted name) as rendered rst
1183 """get help for a given topic (as a dotted name) as rendered rst
1133
1184
1134 Either returns the rendered help text or raises an exception.
1185 Either returns the rendered help text or raises an exception.
General Comments 0
You need to be logged in to leave comments. Login now