Skip to content

Commit c4253f8

Browse files
committed
REPL: update doc() function from imacropy 0.3.0
1 parent a208e78 commit c4253f8

1 file changed

Lines changed: 35 additions & 11 deletions

File tree

unpythonic/net/server.py

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,16 @@
124124
import time
125125
import socketserver
126126
import atexit
127-
from textwrap import dedent
127+
import inspect
128128
from itertools import count
129129

130130
try:
131-
# macro-enabled console with imacropy semantics
131+
from macropy.core.macros import WrappedFunction
132+
except ModuleNotFoundError: # probably no MacroPy installed
133+
WrappedFunction = None
134+
135+
try:
136+
# macro-enabled console with imacropy semantics and ?, ?? docstring/source viewing syntax
132137
from imacropy.console import MacroConsole as Console
133138
except ModuleNotFoundError:
134139
try:
@@ -170,19 +175,38 @@
170175
# --------------------------------------------------------------------------------
171176
# Exports for REPL sessions
172177

178+
# This is a copy of `imacropy.doc` (from v0.3.0) with a slightly modified docstring.
179+
# We strictly need a local copy of this only if `imacropy` is not installed,
180+
# to allow viewing docstrings in the MacroPy or stdlib consoles.
173181
def doc(obj):
174-
"""Print an object's docstring, non-interactively, but emulate help's dedenting."""
182+
"""Print an object's docstring, non-interactively.
183+
184+
Additionally, if the information is available, print the filename
185+
and the starting line number of the definition of `obj` in that file.
186+
This is printed before the actual docstring.
187+
188+
This works around the problem that in a REPL session, the stdin/stdout
189+
of the builtin `help()` are not properly redirected.
190+
191+
And that looking directly at `some_macro.__doc__` prints the string
192+
value as-is, without formatting it.
193+
194+
NOTE: if you have the `imacropy` package installed, you can use
195+
the IPython-like `obj?` and `obj??` syntax instead (provided by
196+
`imacropy.console.MacroConsole`).
197+
"""
175198
if not hasattr(obj, "__doc__") or not obj.__doc__:
176199
print("<no docstring>")
177200
return
178-
# Emulate help()'s dedenting. Typically, the first line in a docstring
179-
# has no leading whitespace, while the rest follow the indentation of
180-
# the function body.
181-
firstline, *rest = obj.__doc__.split("\n")
182-
rest = dedent("\n".join(rest))
183-
doc = [firstline, *rest.split("\n")]
184-
for line in doc:
185-
print(line)
201+
try:
202+
if isinstance(obj, WrappedFunction):
203+
obj = obj.__wrapped__ # this is needed to make inspect.getsourcefile work with macros
204+
filename = inspect.getsourcefile(obj)
205+
source, firstlineno = inspect.getsourcelines(obj)
206+
print(f"{filename}:{firstlineno}")
207+
except (TypeError, OSError):
208+
pass
209+
print(inspect.cleandoc(obj.__doc__))
186210

187211
# TODO: detect stdout, stderr and redirect to the appropriate stream.
188212
def server_print(*values, **kwargs):

0 commit comments

Comments
 (0)