Changing Package Representation On Shell
After a question i asked on python-list, Let's say i have a package.
import package package
package
would it be nice to be able to change the repr of the package to package something some message .... ? Thanks! Kind Regards, Abdur-Rahmaan Janhangeer compileralchemy.com https://www.compileralchemy.com | github https://github.com/Abdur-rahmaanJ/ Mauritius
On Thu, Apr 02, 2020 at 10:44:02AM +0400, Abdur-Rahmaan Janhangeer wrote:
Let's say i have a package.
import package package
would it be nice to be able to change the repr of the package to
package package something some message ....
?
I don't know, would it be nice? For what purpose? What will the message be? Where does the message come from? The Python shell just prints the repr() of the object. If you want it to print something different, you can install a custom display hook: py> from types import ModuleType py> def thingy(obj): ... if isinstance(obj, ModuleType): ... print("module %s is amazing!" % obj.__name__) ... print("...and Python is great!") ... else: ... print(repr(obj)) ... py> sys.displayhook = thingy py> 'hello' 'hello' py> math module math is amazing! ...and Python is great! -- Steven
Thanks for the snippet,
Was wondering if given as a package option,
we might display the module's help info.
Out of curiosity how did you learn about sys.displayhook?
Thanks.
Kind Regards,
Abdur-Rahmaan Janhangeer
compileralchemy.com https://www.compileralchemy.com | github
https://github.com/Abdur-rahmaanJ/
Mauritius
On Thu, Apr 2, 2020 at 11:07 AM Steven D'Aprano
On Thu, Apr 02, 2020 at 10:44:02AM +0400, Abdur-Rahmaan Janhangeer wrote:
Let's say i have a package.
import package package
would it be nice to be able to change the repr of the package to
package package something some message ....
?
I don't know, would it be nice? For what purpose? What will the message be? Where does the message come from?
The Python shell just prints the repr() of the object. If you want it to print something different, you can install a custom display hook:
py> from types import ModuleType py> def thingy(obj): ... if isinstance(obj, ModuleType): ... print("module %s is amazing!" % obj.__name__) ... print("...and Python is great!") ... else: ... print(repr(obj)) ... py> sys.displayhook = thingy py> 'hello' 'hello' py> math module math is amazing! ...and Python is great!
-- Steven _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/RBOUOF... Code of Conduct: http://python.org/psf/codeofconduct/
On Thu, Apr 2, 2020 at 8:22 AM Abdur-Rahmaan Janhangeer < arj.python@gmail.com> wrote:
Thanks for the snippet,
Was wondering if given as a package option, we might display the module's help info.
That's what help() is for. The __repr__ is meant to help during development with some succinct representation of the object (hence why they typically have an identifier to help tell equal objects apart). Including docstrings and such is not a goal for the repr and would make it no longer succinct. -Brett
Kind Regards,
Abdur-Rahmaan Janhangeer
compileralchemy.com https://www.compileralchemy.com | github
https://github.com/Abdur-rahmaanJ/
Mauritius
On Thu, Apr 2, 2020 at 9:52 PM Brett Cannon
That's what help() is for. The __repr__ is meant to help during development with some succinct representation of the object (hence why they typically have an identifier to help tell equal objects apart). Including docstrings and such is not a goal for the repr and would make it no longer succinct.
This means we have a __repr__ option in packages (Without Steven's snippet above)?
On Fri, Apr 3, 2020 at 7:30 AM Abdur-Rahmaan Janhangeer
Kind Regards,
Abdur-Rahmaan Janhangeer compileralchemy.com | github Mauritius
On Thu, Apr 2, 2020 at 9:52 PM Brett Cannon
wrote: That's what help() is for. The __repr__ is meant to help during development with some succinct representation of the object (hence why they typically have an identifier to help tell equal objects apart). Including docstrings and such is not a goal for the repr and would make it no longer succinct.
This means we have a __repr__ option in packages (Without Steven's snippet above)?
You can mess with anything on a module if you subclass ModuleType and stick your one into sys.modules. However, I'm not going to give you the code, because I don't believe in helping people to do bad things :) Use help, not repr. ChrisA
Kind Regards,
Abdur-Rahmaan Janhangeer
compileralchemy.com https://www.compileralchemy.com | github
https://github.com/Abdur-rahmaanJ/
Mauritius
On Fri, Apr 3, 2020 at 12:34 AM Chris Angelico
You can mess with anything on a module if you subclass ModuleType and stick your one into sys.modules. However, I'm not going to give you the code, because I don't believe in helping people to do bad things :) Use help, not repr.
Oh you mean subclassing, modifying then assigning your module to the modified one. Well this proposal is about doing it at the time of writing packages. About the help thing, it's more about customisation, help is an idea
This prints modname.__doc__ / help(modname) / inspect.getdoc(modname) with IPython / Jupyter + ipykernel:
modname?
This prints something like inspect.getsource(modname)
modname??
https://ipython.readthedocs.io/en/stable/interactive/python-ipython-diff.htm...
https://docs.python.org/3/library/inspect.html
If an object defines a _repr_pretty_() method, IPython will call that
instead of __repr__()
https://ipython.readthedocs.io/en/stable/config/integrating.html#rich-displa...
On Thu, Apr 2, 2020, 4:30 PM Abdur-Rahmaan Janhangeer
Kind Regards,
Abdur-Rahmaan Janhangeer compileralchemy.com https://www.compileralchemy.com | github https://github.com/Abdur-rahmaanJ/ Mauritius
On Thu, Apr 2, 2020 at 9:52 PM Brett Cannon
wrote: That's what help() is for. The __repr__ is meant to help during development with some succinct representation of the object (hence why they typically have an identifier to help tell equal objects apart). Including docstrings and such is not a goal for the repr and would make it no longer succinct.
This means we have a __repr__ option in packages (Without Steven's snippet above)? _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/EIS67L... Code of Conduct: http://python.org/psf/codeofconduct/
On Fri, Apr 03, 2020 at 12:28:36AM +0400, Abdur-Rahmaan Janhangeer wrote:
This means we have a __repr__ option in packages (Without Steven's snippet above)?
There is no "hook" in the package file structure where you can customize the repr. It is built into the module type. Once loaded, packages are just a module object like any other module. If you want to change the repr() of modules, you will need to change the built-in ModuleType class. But I can tell you that this will 99.999999% be rejected. And if it is accepted, I can tell you that the first time you get hit by a massive wall of text from a package docstring in an exception or some other use of repr(), you will likely regret the change. -- Steven
On Fri, Apr 03, 2020 at 08:00:38AM +1100, Steven D'Aprano wrote:
But I can tell you that this will 99.999999% be rejected. And if it is accepted, I can tell you that the first time you get hit by a massive wall of text from a package docstring in an exception or some other use of repr(), you will likely regret the change.
For what it's worth, I just looked at a few of my private packages, half of them have got docstrings that are > a page long, and one has a three page docstring. Perhaps it's time for me to extract some of that into an external file... Personally, I might make and use a display hood to show the first line of a module docstring. That might be useful, I'm willing to try it for a few weeks and see if I like it. But I definitely don't want the entire docstring displayed, and I even more don't want it in the module repr(). -- Steven
Kind Regards,
Abdur-Rahmaan Janhangeer
compileralchemy.com https://www.compileralchemy.com | github
https://github.com/Abdur-rahmaanJ/
Mauritius
On Fri, Apr 3, 2020 at 4:04 AM Steven D'Aprano
... Personally, I might make and use a display hood to show the first line of a module docstring.
That's another idea to make the default repr show a part of the docstring or a complete customisation ...
I think there's been some confusion with regard to this idea, leading to a
combination of technical details vs the merits of the idea.
So I'm going to summarize a bit what I think the discussion has yielded:
Technical issues:
The __repr__ and __str__ are defined on the class, not instances of a class.
You cannot override them in an instance.
modules are instances of the module class.
Thus the only way to change the __repr__ or __str__ (or other magic
methods) is to create a custom subclass of the module class.
Design issues:
You probably don't want to change the __repr__ of a module anyway -- there
are good reasons to keep the repr of all modules the same and standardized.
(which is one reason __repr__'s are defined on the class, not the instance,
you generally wouldn't want different instances of classes to have
different __repr__s (or any other different magic method behavior).
And while customizing the __repr__ of a module to be non standard is a bad
idea, it's not such a bad idea to customize the __str__ of a module --
traditionally that's where you put a more human-readable version of an
object.
But: modules are kind of special: in the VAST majority of the time, the
instances are created by the import mechanism, which the user has little
control over. And the writer of the module even less. In many cases, one
could write a custom subclass of a standard type, and have your code run
that instead of the usual type, and your users would get that custom class,
but it's difficult to do that with modules.
You can define a custom module class by subclassing types.ModuleType. And
you could put that custom module in a __init__.py of a package, and then be
able to do:
from the_package import the_module
and then the_module will have a custom __str__
Here that is, in action:
in module_str/__init__.py:
import types
class StrModule(types.ModuleType):
def __init__(self, name, custom_str):
super().__init__(name)
self.___str__ = custom_str
def __str__(self):
return f"module {self.__name__}: {self.___str__}"
# create a new module with a custom string representation:
a_module = StrModule("a_module", "a custom str() for a_module" )
# put a few things into it
a_module.x = 5
def a_function():
return "a_function was called"
a_module.a_function = a_function
the use it:
"""
test code for a custom string module
"""
from module_str import a_module
print("the repr of the module:", repr(a_module))
print("the str of the module:", str(a_module))
print("and it works:")
print(a_module.x)
print(a_module.a_function())
Which when run:
$ python try_module_str.py
the repr of the module:
On Sat, Apr 4, 2020 at 7:02 AM Christopher Barker
So if folks think it's a good idea to allow modules to have a custom __str__: it would be nice to add that feature to Python.
I'm not saying I advocate for that -- but it's not completely unreasonable.
It's not unreasonable, I agree. But it's also unnecessary. In theory, PEP 562 could have gone for a broader recommendation eg "any dunder on a module will be looked up in the instance", but in practice, which ones are you actually going to need? PEP 562 chose two (__getattr__ and __dir__), with definite use-cases for each. There's no need to override __new__/__init__, since the module body serves that purpose. Comparisons (__lt__ etc) don't make a lot of sense. Modules are generally singletons, so __hash__ and __eq__ aren't needed (the default of using object identity is fine). There is *one* other dunder that I can imagine getting some good use, and that's __call__. A few others might have occasional uses (maybe __setattr__ for deprecation warnings, same as __getattr__, and maybe __enter__/__exit__ so the module itself can be a context manager), but they would be rather more rare. Changing the repr/str of a module would also be pretty unusual. Fortunately, the unusual case IS possible - just not as easy. You subclass the module type, instantiate your subclass, and shove the instance into sys.modules. So if you really do need to mess with the repr of your module, you can, even if it's a package :) ChrisA
__doc__ https://docs.python.org/3/library/pydoc.html describes the help() function; which you can also call with: $ pydoc modname $ python -m pydoc modname IPython:
help(modname)
?modname modname?
!pydoc modname !python -m pydoc modname
https://ipython.readthedocs.io/en/stable/interactive/python-ipython-diff.htm...
On Fri, Apr 3, 2020, 4:28 PM Chris Angelico
On Sat, Apr 4, 2020 at 7:02 AM Christopher Barker
wrote: So if folks think it's a good idea to allow modules to have a custom __str__: it would be nice to add that feature to Python.
I'm not saying I advocate for that -- but it's not completely unreasonable.
It's not unreasonable, I agree. But it's also unnecessary. In theory, PEP 562 could have gone for a broader recommendation eg "any dunder on a module will be looked up in the instance", but in practice, which ones are you actually going to need? PEP 562 chose two (__getattr__ and __dir__), with definite use-cases for each. There's no need to override __new__/__init__, since the module body serves that purpose. Comparisons (__lt__ etc) don't make a lot of sense. Modules are generally singletons, so __hash__ and __eq__ aren't needed (the default of using object identity is fine).
There is *one* other dunder that I can imagine getting some good use, and that's __call__. A few others might have occasional uses (maybe __setattr__ for deprecation warnings, same as __getattr__, and maybe __enter__/__exit__ so the module itself can be a context manager), but they would be rather more rare. Changing the repr/str of a module would also be pretty unusual.
Fortunately, the unusual case IS possible - just not as easy. You subclass the module type, instantiate your subclass, and shove the instance into sys.modules. So if you really do need to mess with the repr of your module, you can, even if it's a package :)
ChrisA _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/UDPYBE... Code of Conduct: http://python.org/psf/codeofconduct/
On Thu, Apr 02, 2020 at 07:18:47PM +0400, Abdur-Rahmaan Janhangeer wrote:
Out of curiosity how did you learn about sys.displayhook?
20+ years of using Python, experimenting at the interpreter, reading the documentation, blog posts, etc. I have no idea *specifically* where I learned it. I didn't remember the name of the hook, but I knew it existed, so I ran dir(sys) to get a list of objects in the sys module, then tested it to make sure it did what I thought it did. -- Steven
IDK what you'd grep for in these; if it's not there you could send a PR
that adds more greppable keywords or cross-:ref:'s the sys.displayhook docs
like this:
:func:`sys.displayhook`
https://docs.python.org/3/library/sys.html#sys.displayhook
https://github.com/python/cpython/blob/master/Doc/library/sys.rst
```rst
.. function:: displayhook(value)
If *value* is not ``None``, this function prints ``repr(value)`` to
``sys.stdout``, and saves *value* in ``builtins._``. If ``repr(value)``
is
not encodable to ``sys.stdout.encoding`` with ``sys.stdout.errors`` error
handler (which is probably ``'strict'``), encode it to
``sys.stdout.encoding`` with ``'backslashreplace'`` error handler.
``sys.displayhook`` is called on the result of evaluating an
:term:`expression`
entered in an interactive Python session. The display of these values
can be
customized by assigning another one-argument function to
``sys.displayhook``.
Pseudo-code::
def displayhook(value):
if value is None:
return
# Set '_' to None to avoid recursion
builtins._ = None
text = repr(value)
try:
sys.stdout.write(text)
except UnicodeEncodeError:
bytes = text.encode(sys.stdout.encoding, 'backslashreplace')
if hasattr(sys.stdout, 'buffer'):
sys.stdout.buffer.write(bytes)
else:
text = bytes.decode(sys.stdout.encoding, 'strict')
sys.stdout.write(text)
sys.stdout.write("\n")
builtins._ = value
.. versionchanged:: 3.2
Use ``'backslashreplace'`` error handler on :exc:`UnicodeEncodeError`.
```
https://github.com/python/cpython/blob/master/Doc/library/pprint.rst
https://github.com/python/cpython/blob/master/Doc/library/reprlib.rst
On Thu, Apr 2, 2020, 7:57 PM Steven D'Aprano
On Thu, Apr 02, 2020 at 07:18:47PM +0400, Abdur-Rahmaan Janhangeer wrote:
Out of curiosity how did you learn about sys.displayhook?
20+ years of using Python, experimenting at the interpreter, reading the documentation, blog posts, etc. I have no idea *specifically* where I learned it.
I didn't remember the name of the hook, but I knew it existed, so I ran dir(sys) to get a list of objects in the sys module, then tested it to make sure it did what I thought it did.
-- Steven _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/DMKA3C... Code of Conduct: http://python.org/psf/codeofconduct/
Kind Regards,
Abdur-Rahmaan Janhangeer
compileralchemy.com https://www.compileralchemy.com | github
https://github.com/Abdur-rahmaanJ/
Mauritius
On Fri, Apr 3, 2020 at 3:55 AM Steven D'Aprano
On Thu, Apr 02, 2020 at 07:18:47PM +0400, Abdur-Rahmaan Janhangeer wrote:
Out of curiosity how did you learn about sys.displayhook?
20+ years of using Python, experimenting at the interpreter, reading the documentation, blog posts, etc. I have no idea *specifically* where I learned it.
I didn't remember the name of the hook, but I knew it existed, so I ran dir(sys) to get a list of objects in the sys module, then tested it to make sure it did what I thought it did.
Thanks! Learning some internals is always interesting!
On Apr 1, 2020, at 23:47, Abdur-Rahmaan Janhangeer
Let's say i have a package.
import package package
would it be nice to be able to change the repr of the package to
package package something some message ....
I don’t think so. Objects in Python have a str for “human readers” and a repr that’s more useful for debugging. The repr is nearly always either an expression you can copy and paste to create an equivalent object, or something in angle brackets that crams in the type and other useful-for-debugging information. And it nearly always has no newlines (even a string with newlines or a tuple of strings with newlines or a file whose path has newlines, the newlines get escapes), so you can log messages with reprs and know you’ll get one message per line.in the log output. Why should modules break all of that, and be different from strings, tuples, functions, classes, etc.? The str, which you get from print(package), might be a different story. If there’s a representation of a module that’s more useful to end users than the repr, even if it’s not as good for debugging, the str should use that representation. But is there? What would the message be? How would the module specify it? And how it would be useful for the end user to see that message? There’s a third thing that all types have besides repr and str, the docstring, which you get from help(package). Unlike the repr and str, the docstring is generally a constant, so it has no way of including runtime information, but that’s usually not a problem, and I don’t think it is for your use here. And it seems like the docstring might already be what you want. If so, I think it’s perfect for help(package) but would be wrong for print(package). I may be misinterpreting something about the goals of your proposal. If so, I apologize—but it would really help if you give a real example: some known module, what message you think it should include in its repr, where you plan to print out that repr, how you’d like to specify it within the module source, etc.
Kind Regards,
Abdur-Rahmaan Janhangeer
compileralchemy.com https://www.compileralchemy.com | github
https://github.com/Abdur-rahmaanJ/
Mauritius
On Thu, Apr 2, 2020 at 8:15 PM Andrew Barnert
Why should modules break all of that, and be different from strings, tuples, functions, classes, etc.?
python-ideas is for ideas without worrying about implementations unless it's about some glaring breaking changes
The str, which you get from print(package), might be a different story. If there’s a representation of a module that’s more useful to end users than the repr, even if it’s not as good for debugging, the str should use that representation. But is there? What would the message be? How would the module specify it? And how it would be useful for the end user to see that message? ... I may be misinterpreting something about the goals of your proposal. If so, I apologize—but it would really help if you give a real example: some known module, what message you think it should include in its repr, where you plan to print out that repr, how you’d like to specify it within the module source, etc.
Well as for example from known module, the proposal is all about introducing the __repr__ option in modules. If i understood well it does not seem to exist. As for purpose, well a friendlier representation of a package.
On Apr 2, 2020, at 13:35, Abdur-Rahmaan Janhangeer
On Thu, Apr 2, 2020 at 8:15 PM Andrew Barnert
wrote: Why should modules break all of that, and be different from strings, tuples, functions, classes, etc.?
python-ideas is for ideas without worrying about implementations unless it's about some glaring breaking changes
But nobody’s mentioned implementation here. Nobody’s saying you can’t have this because it would be too hard to implement. (It almost surely wouldn’t be hard. For one thing, there are existing cases of special methods like __dir__, which are normally looked up on the type but for modules they’re looked up on the individual instance, and the same thing presumably could be done here just as easily. Even besides that, most types’ reprs, including module, already include information from the instance, so there’s no reason even without overloading module.__repr__ you couldn’t have a slightly different way to extensively customize the repr of each individual module.) People are saying you probably don’t want this because it would be inconsistent with other reprs, and with what repr is for and how it’s used—e.g., the concise and standard form of reprs is crucial to things like tracebacks and logs being useful for debugging. That’s not about implementation; that’s about the key idea in your proposal.
The str, which you get from print(package), might be a different story. If there’s a representation of a module that’s more useful to end users than the repr, even if it’s not as good for debugging, the str should use that representation. But is there? What would the message be? How would the module specify it? And how it would be useful for the end user to see that message? ... I may be misinterpreting something about the goals of your proposal. If so, I apologize—but it would really help if you give a real example: some known module, what message you think it should include in its repr, where you plan to print out that repr, how you’d like to specify it within the module source, etc.
Well as for example from known module, the proposal is all about introducing the __repr__ option in modules. If i understood well it does not seem to exist. As for purpose, well a friendlier representation of a package.
That’s not an example. Show us a module that you’d like to have a custom repr, and show us what you’d like that custom repr to be, and show us that it looks good in other contexts (a traceback, printing out sys.modules, etc.), or why it’s so good in the REPL that it overcomes the cost of being less good in those contexts. You may well have examples that are good enough. But if you don’t show us your examples, we can only use our own imagination, and obviously none of us are imagining anything nearly good enough to be worth it. Which is our failure, not yours—but you want this implemented, and if nobody backs your proposal because nobody imagines how useful it would be, you’re not going to get it.
Kind Regards,
Abdur-Rahmaan Janhangeer
compileralchemy.com https://www.compileralchemy.com | github
https://github.com/Abdur-rahmaanJ/
Mauritius
On Fri, Apr 3, 2020 at 2:21 AM Andrew Barnert
On Apr 2, 2020, at 13:35, Abdur-Rahmaan Janhangeer
wrote: But nobody’s mentioned implementation here. Nobody’s saying you can’t have this because it would be too hard to implement.
...
That’s not about implementation; that’s about the key idea in your proposal.
Ah ok i misunderstood.
That’s not an example.
Well i meant that there was no known module example if the feature did not exist yet.
Show us a module that you’d like to have a custom repr, and show us what you’d like that custom repr to be, and show us that it looks good in other contexts (a traceback, printing out sys.modules, etc.), or why it’s so good in the REPL that it overcomes the cost of being less good in those contexts. You may well have examples that are good enough. But if you don’t show us your examples, we can only use our own imagination, and obviously none of us are imagining anything nearly good enough to be worth it. Which is our failure, not yours—but you want this implemented, and if nobody backs your proposal because nobody imagines how useful it would be, you’re not going to get it.
Well it's about having the ability to change the default <'long line where module is found'>. I find it ugly as the default representation of a package. If it's the default, maybe it can be changed/customised. Same spirit like the repr of an object is <__main__.A object at 0x0048E4D8>, but it can be customised.
participants (7)
-
Abdur-Rahmaan Janhangeer
-
Andrew Barnert
-
Brett Cannon
-
Chris Angelico
-
Christopher Barker
-
Steven D'Aprano
-
Wes Turner