Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using termcolor in PyScript doesn't affect console output #1288

Closed
3 tasks done
PyBoy314 opened this issue Mar 16, 2023 · 11 comments
Closed
3 tasks done

Using termcolor in PyScript doesn't affect console output #1288

PyBoy314 opened this issue Mar 16, 2023 · 11 comments
Labels
type: bug Something isn't working

Comments

@PyBoy314
Copy link

Checklist

  • I added a descriptive title
  • I searched for other issues and couldn't find a solution or duplication
  • I already searched in Google and didn't find any good information or help

What happened?

When I run a simple PyScript program such as the one below, the console output on the webpage doesn't seem to be affected by the package 'termcolor'.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" href="https://pyscript.net/releases/2023.03.1/pyscript.css" />
    <script defer src="https://pyscript.net/releases/2023.03.1/pyscript.js"></script>
  </head>
  <body>
    <py-config>
        packages = ['termcolor']
    </py-config>
    <py-script>
from termcolor import colored
text = colored("Red text?", "red")
print(text)
    </py-script>
  </body>
</html>

The output is the standard white instead of an expected red.

What browsers are you seeing the problem on? (if applicable)

Chrome

Console info

There are no errors given.

Additional Context

No response

@PyBoy314 PyBoy314 added needs-triage Issue needs triage type: bug Something isn't working labels Mar 16, 2023
@marimeireles
Copy link
Member

I'm not super deep in the code for the terminal that shows up when you print in pyscript but it seems to me that it's just a pre tag with a bit of styling. So that's probably the reason why it's not working for you. @antocuni can give you more info on that one.
If you want a functional terminal with colorful output you can give a try on Jeff's pet project: https://jeff.glass/project/richdemo/

@JeffersGlass
Copy link
Member

JeffersGlass commented Mar 27, 2023

For what it's worth, I'm working on a PR that allows users to use an xtermjs terminal in place of the <pre> tag, if they want to eat the extra 400KB of page load. Not quite ready to open that PR yet, but it's mostly functional.

Edit: It'll be PR #1317 .

image

@WebReflection
Copy link
Contributor

I think termcolor doesn't produce strings with terminal special chars but oddly enough the devtools console understands these escape chars ...

print("\x1b[1mHello\x1b[0m \x1b[31mWorld\x1b[0m")

Screenshot from 2023-03-28 09-05-42

That makes me think that if termcolor cannot be sure about which kind of terminal is executing it just doesn't do anything (doesn't transform the text) but in case we'd receive special chars, I believe the terminal won't be able to handle these, while the devtools console would work just as fine.

Maybe waiting for @JeffersGlass PR is indeed a good idea (imho).

@PyBoy314
Copy link
Author

Very interesting. I'm just happy to hear some thoughts on this. I think I'll go with WebReflection's comment there about waiting for rich implementation. Thanks again, everyone.

@marimeireles
Copy link
Member

No problem! Closing this one then. Thanks! :)

@marimeireles marimeireles removed the needs-triage Issue needs triage label Mar 28, 2023
@JeffersGlass
Copy link
Member

Another option might be using a JS or Python library that converts ANSI escape sequences of text to HTML. The most popular Python one seems to be ansi2html, but it's API is a bit odd - for a given sequence, you can convert it either to an entire HTML page (with head/body tags) or a snippet that wraps the styled text in <span> tags with specific classes, but it doesn't emit those classes...

The JavaScript options for ansi-to-HTML conversion seem more promising - here's a short demo using the ansi_up library:

<!--index.html-->
<head>
    <script src="https://cdn.jsdelivr.net/npm/ansi_up@5.1.0/ansi_up.js"></script>
    <script defer src="https://pyscript.net/releases/2023.03.1/pyscript.js"></script>
    <link rel="stylesheet" href="https://pyscript.net/releases/2023.03.1/pyscript.css">
</head>
<body>
    <py-config>
        packages = ['termcolor']
    </py-config>
    <py-script src="termdemo.py"></py-script>
</body>
</html>
#termdemo.py
import os
import termcolor

import js

ansi_up = js.AnsiUp.new() #Create new coverter object

os.environ['FORCE_COLOR'] = "True" #Force termcolor to output ANSI sequences

raw = termcolor.colored("Hello", "green", "on_blue") #Create text with ansi sequences embedded
converted = ansi_up.ansi_to_html(raw) #HTML-styled text
display(HTML(converted)) #Send HTML to DOM without escaping
print(converted) #Show escaped HTML in terminal, for interest

That makes me think that if termcolor cannot be sure about which kind of terminal is executing it just doesn't do anything (doesn't transform the text)...

Indeed, termcolor uses some environment variables to determine whether it should be output escape codes or not. You can ensure it does in PyScript/Pyodide by using import os; os.environ['FORCE_COLOR'] = "True"

https://github.com/termcolor/termcolor/blob/59be43ac08e4cacb1bdd54823044d7eef163ea88/src/termcolor/termcolor.py#L99-L111

Rich has a much more involved method of detecting what terminal it thinks it's in, but it seems ANSI escape codes can generally be forced in the browser with rich._console = RichConsole(color_system="..."), where "..." is 256 or truecolor.

@WebReflection
Copy link
Contributor

WebReflection commented Mar 28, 2023

termcolor uses some environment variables to determine whether it should be output escape codes or not. You can ensure it does in PyScript/Pyodide by using import os; os.environ['FORCE_COLOR'] = "True"

makes sense, thanks for explaining! I am totally up for ansi_up library as it looks like it does exactly what I would do if I had to create that from scratch 👍

that being said, the print apparently would work just fine with escape sequences in Chrome/ium devtools, but I don't think we handle escapes in our py-term output

@antocuni
Copy link
Contributor

yes, the current py-terminal is deliberately designed to be dumb and not support any escape sequence. I think that the "proper" solution is to use xterm.js, as Jeff is doing.

That said, we could decide to support ANSI escape sequence for colors also in the dumb terminal: in theory it feels wrong (because people should respect the TERM env variable and avoid printing ANSI escape sequences if the TERM is not compatible), but I think that in practice there are tons of libraries around which just assumes that the terminal supports them, so it might be a good idea

@WebReflection
Copy link
Contributor

@antocuni we can always make it optional via an attribute or accessor so that pyTerm.env = 'ansi' (just made up field) could enable such escaping when/if needed ... although I am OK with current behavior as it never receives anything from termcolor but like you said other libraries might use a different module to print colors or developers might wonder how comes colors don't show up in the terminal.

@JeffersGlass
Copy link
Member

I think for the moment I'd agree that the current behavior (escape sequences don't do anything) is probably fine as a default. The expanded optional behavior of supporting colors feels like a great thing to add to a community (external) plugin at some point.

@antocuni
Copy link
Contributor

I'm not opposed to have a terminal which supports ANSI colors (either builtin or via a plugin), but then we need to think carefully.
Ideally, I'd like to find an existing terminal which supports those and only those escape sequences that we want to support, so that we can just declare that we are emulating it and set the TERM variable accordingly. This way, all the other libraries which do "the right thing" would just work automatically.

I doubt that such a terminal exists, because AFAIK most of them supports at least basic cursor movement (which I guess we don't want to emulate). So we could probably invent a new one -- let's call it pyterminal -- and set TERM accordingly.
This would be a bit annoying because libraries which does "the right thing" would detect a terminal which they don't support and don't emit colors even if they could.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants