Initial version of auto-detection of terminal width.#110
Initial version of auto-detection of terminal width.#110dawngerpony wants to merge 12 commits intogruns:masterfrom
Conversation
|
Update: it seems that the behaviour of |
|
Thanks for contributing! IMO it's not worth spending significant time on perfecting 2.7 since it's well past EOL. I haven't looked carefully but it sounds like you've made a significant improvement for 3.x and not made anything worse for 2.7 and that's great. You can write something like |
You're very welcome! I love your icecream package and am happy to give back.
That's awesome thanks. Unfortunately I had to skip the entire test because there's an assertion inside But the test is committed, I'll mark this PR as ready. |
icecream/icecream.py
Outdated
| # TODO come up with a more elegant solution than subtracting | ||
| # a seemingly random number of characters. |
There was a problem hiding this comment.
Any thoughts about this overflow thingy? I just realised that the extra characters might come from the ic | prefix.
There was a problem hiding this comment.
That's probably what it is, yes. Have this function return the full width, then deal with the length of the prefix inside the class. Remember there's both the ic | prefix (which can be configured) as well as the argPrefix.
There was a problem hiding this comment.
Let me know what you think of my new solution.
icecream/icecream.py
Outdated
| return s | ||
|
|
||
|
|
||
| def columns(): |
There was a problem hiding this comment.
Please give this a more descriptive name.
icecream/icecream.py
Outdated
| width = os.get_terminal_size().columns - COLUMN_OVERFLOW | ||
| except OSError: # Not in TTY | ||
| pass | ||
| except AttributeError: # Python 2.x |
There was a problem hiding this comment.
This looks a bit too broad and prone to hiding real errors. I'd prefer either checking the Python version or checking for the presence of the relevant attribute.
icecream/icecream.py
Outdated
| try: | ||
| # TODO come up with a more elegant solution than subtracting | ||
| # a seemingly random number of characters. | ||
| width = os.get_terminal_size().columns - COLUMN_OVERFLOW |
There was a problem hiding this comment.
The docs https://docs.python.org/3/library/os.html#os.get_terminal_size suggest using shutil (https://docs.python.org/3/library/shutil.html#shutil.get_terminal_size) instead, and looking at that function I think that's a good idea.
alexmojaki
left a comment
There was a problem hiding this comment.
Overall I like the approach and I appreciate the PR. The supports_param idea is clever.
|
@alexmojaki thanks for the review! I've tried to implement your suggestions, which actually led to a different implementation of |
icecream/icecream.py
Outdated
| """ Returns the number of columns that this terminal can handle. """ | ||
| width = default | ||
| try: | ||
| if hasattr(shutil, "get_terminal_size"): |
There was a problem hiding this comment.
I'd prefer to have near the top of the file:
try:
from shutil import get_terminal_size
except ImportError:
try:
from backports.shutil_get_terminal_size import get_terminal_size
except ImportError:
def get_terminal_size():
# get COLUMNS environment variable
icecream should still work if backports.shutil_get_terminal_size isn't installed, e.g. if the user chooses to uninstall it even after installing it automatically.
There was a problem hiding this comment.
(Although in my terminal, env['COLUMNS'] isn't set, so I'm not sure which environments/OSes do set that variable)
There was a problem hiding this comment.
I don't know anything about this either, but I imagine it's a convention so that humans can easily set COLUMNS=50 when running a program and expect that many parts of the program will automatically respect that.
icecream/icecream.py
Outdated
| else: # Python 2.x doesn't support get_terminal_size | ||
| from backports.shutil_get_terminal_size import get_terminal_size | ||
| width = get_terminal_size().columns | ||
| except OSError: # Not in TTY |
There was a problem hiding this comment.
Looks like the shutil version doesn't raise OSError any more. But maybe the whole thing should be wrapped in except Exception just in case something weird happens.
Also you should pass the default width as a fallback to get_terminal_size. Otherwise it's going to use its own default fallback (80 columns) when the other methods fail.
icecream/icecream.py
Outdated
| self.outputFunction = outputFunction | ||
| self.argToStringFunction = argToStringFunction | ||
| self.passWidthParam = supports_param(self.argToStringFunction) | ||
| self.lineWrapWidth = detect_terminal_width(self.prefix, DEFAULT_LINE_WRAP_WIDTH) |
There was a problem hiding this comment.
This still doesn't account for the width of argPrefix, or changing the prefix with configureOutput.
Co-authored-by: Alex Hall <alex.mojaki@gmail.com>
Co-authored-by: Alex Hall <alex.mojaki@gmail.com>
|
Started to make some suggestions then I realised the |
Co-authored-by: Alex Hall <alex.mojaki@gmail.com>
|
Hi @alexmojaki , sorry for the delay, work has been very busy. I have been thinking that it might be best not to enable this feature by default, at least in its first release, otherwise it could introduce breaking changes for a lot of people. So I have added some code to leave it off by default. There's now also at least one test that tests it by using a NB. I'm also a little bemused by the current behaviour of my new ic("banana")should print: ic| 'banana'When I manually run a Python script with the above code, it behaves as expected. But in my test, it actually appears to print the name of the literal along with its value: ic| "banana banana": ('banana '
'banana')Any idea what's going on? |
I think if the experience is generally improved then it should be enabled by default. Most people aren't going to even know they can configure this. As for breaking changes, this is a 'casual' debugging tool, I don't think there are significant expectations or guarantees of backward compatibility. It's hard to picture how this would significantly affect people negatively. If we want to be really careful, we could release a new major version. @gruns what do you think?
This is a bug first noticed in #84 (comment) Basically the source of the literal argument is still printed when the value is multiline, but it shouldn't. |
|
The main problem is that you still need to account for the other parts of the output, and it's quite complicated. There's four pieces:
Each of these pieces needs to be added one at a time to see if they can fit within the terminal width. If not, that starts a new indented line with a new available width. Your code mentions both 'terminal width' and 'line wrap width' in more places than I think it should, and the distinction is confusing. You should only need to store the attribute |
Co-authored-by: Alex Hall <alex.mojaki@gmail.com>
Thank you, this is the context I needed. I think I've catered for the prefix, but definitely not for anything else. I suspect that a lot more digging is needed for me to get familiar with how/when 2, 3 and 4 are added to the output.
OK, will do. Also, based on your thoughts, I'll refactor to remove the "disable by default". It'll be on for everyone. Let's just hope nobody is basing important logic on the output of an informal debugging tool 😉 I'm not sure I picked the simplest task for my first contribution 😂 😬 BTW, thank you so much for sticking with me on this 🙏 |
|
Hi, Thank you for your efforts. Do you think you are still interested in contributing? I'm looking to clear PRs, Issues. |
Might fix #90.
shutil.get_terminal_sizeto detect terminal size in Python 3backports.shutil_get_terminal_sizeto detect terminal size in Python 2, as per this SO answer. This appears to be more effective than the suggested approach of checkingos.env['COLUMNS']but does come at the price of a new dependency. The various answers in the SO link make an interesting read.argToStringFunction, even if a custom function is being used instead of the defaultpprint, but only if the custom function supports awidthparameter.lineWrapWidthis being reset before the start of every test, for idempotency.Notes
pprintin Python 2 doesn't wrap long strings so we test slightly different behaviour between Python 2 and Python 3.OSErrorand abandon the attempt at detecting line widthtoxagainst any other environments or in any other OSes.