#๐Ÿ”’ redirecting io doesn't print properly

133 messages ยท Page 1 of 1 (latest)

fierce ravine
#
output = io.StringIO()
sys.stdout = output
results = parse_trick_and_run(trick_data, request.args)
sys.stdout = sys.__stdout__
output.seek(0)
print_content = output.read()
return Response(print_content)
torn girderBOT
#

@fierce ravine

Python help channel opened

Remember to:

  • Ask your Python question, not if you can ask or if there's an expert who can help.
  • Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
  • Explain what you expect to happen and what actually happens.

:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.

fierce ravine
#
b'Filesystem at / is mounted as read-only.\nFilesystem at / is confirmed as read-only.\n'

#

output ^

#

I want it to print \n as a newline, not actually print the new line ascii symbol

lavish light
#

format is usually utf8 or ascii

fierce ravine
#

when i do type(print_content), it shows it as str though

#

so I can't decode

lavish light
fierce ravine
lavish light
#

wait... you have a bytes object stringified?
so you actually have "b'...'"?

fierce ravine
lavish light
#

you can double verify this is indeed what you have by doing:
print(repr(your_stuff))

this will print a stringified bytes as
"b'stuff'"
note surrounding quotes around the b'stuff', indicating str type

keen berry
#

Also you have to be careful when using it, looking at the code you're returning a Response object, is this flask? Mutating sys won't work correctly if you have multiple threads

fierce ravine
#

i am using flask

#

only one thread

#

it doesn't matter if i use flask or not

#

i'm still getting 'Filesystem at / is mounted as read-only.\nFilesystem at / is confirmed as read-only.\n'

#

before i return the response

#
    output = io.StringIO()

    with contextlib.redirect_stdout(output):
        results = parse_trick_and_run(trick_data, request.args)

    print_content = output.getvalue()
    return Response(print_content)
#

this is my new code

keen berry
#

It just appears like \n when you inspect the string. In fact it is an actual newline

fierce ravine
#

i want it to actually put it on a newline

#

instead of showing the \n character

keen berry
fierce ravine
#

thanks, but that won't fix my problem

#

the problem is in the code above

#

before the return

keen berry
#

It just looks like \n

fierce ravine
#

but in my terminal, it doesn't actually show a new line

#

and i don't get why there is a b'

#

if it's not a byte string

keen berry
#

Show your whole file?

fierce ravine
#

it's a big project

keen berry
#

Use !paste

fierce ravine
#

!paste

keen berry
#

And what did you print to show the b'...?

fierce ravine
#

print_content

keen berry
#

You commented it out, so it will only print <class 'str'> right now

#

Show the output from your program and what you ran?

fierce ravine
#

yeah i was testing

#
huzi@huzi:~/Documents/houdini/api$ python3 run_trick.py 
Container read_only_filesystem already exists. Removing it.
Image 'read_only_filesystem' built successfully. โœ“
Container 'read_only_filesystem' started successfully.
b'Filesystem at / is mounted as read-only.\nFilesystem at / is confirmed as read-only.\n'

huzi@huzi:~/Documents/houdini/api$ 

keen berry
#

That's impossible you didn't print anything out

fierce ravine
#

i just changed my code lol

keen berry
#

Is your paste out of date?

keen berry
fierce ravine
#

here

keen berry
#

show the new output?

fierce ravine
#

it's there

#

i just sent it

fierce ravine
#

only look at the last line

#

the other output comes from another file

#

this project is pretty big

#

hundreds of files

keen berry
#

Show the output of cat run_trick.py

#

Are you sure you saved your file?

fierce ravine
#

you're looking at the wrong code

fierce ravine
#

new url

keen berry
#

Yeah I'm looking at both

fierce ravine
#

i don't have encode in the new file

#

and it's still doing that

keen berry
#

Run the cat command and the python3 command in the same terminal and paste everything

fierce ravine
#
huzi@huzi:~/Documents/houdini/api$ cat run_trick.py 
def run_trick(trick):
    import requests
    import json
    from houdini_config import VM_URL, get_value
    params = {
        'container_name': trick,
        'file': "85c8de88d28866bf0868090b3961162bf82392f690d9e4730910f4af7c6ab3ee.txt",
    }

    response = requests.get(f'{VM_URL}/run-trick/{trick}', params=params)
    data = response.text

    print(data)

def for_host_debug():
    import requests
    import json
    PORT = 49153
    VM_URL = f'http://127.0.0.1:{PORT}'
    trick = "read_only_filesystem" # this will be the container name too

    params = {
        'container_name': trick,
        'file': "85c8de88d28866bf0868090b3961162bf82392f690d9e4730910f4af7c6ab3ee.txt",
    }

    response = requests.get(f'{VM_URL}/run-trick/{trick}', params=params)
    data = str(response.text)
    
    for line in data.split('\n'):
        print(line)


for_host_debug()
#

this file is irrelevant

#
import os
import subprocess

def is_read_only(mount_point):
    """
    Check if the filesystem at the given mount point is read-only.

    Args:
        mount_point (str): The path to the mount point.

    Returns:
        bool: True if the filesystem is read-only, False otherwise.
    """
    try:
        # Use the `mount` command to check filesystem options
        output = subprocess.check_output(['mount'], text=True)
        for line in output.splitlines():
            if mount_point in line and 'ro,' in line:
                return True
        return False
    except subprocess.CalledProcessError as e:
        print(f"Error checking filesystem mount options: {e}")
        return False

def test_write_permission(test_file_path):
    """
    Attempt to write to a test file to check write permissions.

    Args:
        test_file_path (str): Path to the test file.

    Returns:
        bool: True if write operation is successful, False otherwise.
    """
    try:
        with open(test_file_path, 'w') as test_file:
            test_file.write("Testing write permissions.")
        # Cleanup
        os.remove(test_file_path)
        return True
    except IOError:
        return False

def main():
    mount_point = '/'  # Change this to the actual mount point
    test_file_path = os.path.join(mount_point, 'test_write_permission.tmp')

    # Check if the filesystem is read-only
    if is_read_only(mount_point):
        print(f"Filesystem at {mount_point} is mounted as read-only.")
    else:
        print(f"Filesystem at {mount_point} is not read-only.")

    # Test write permissions
    if test_write_permission(test_file_path):
        print(f"Write permissions are available on {mount_point}.")
    else:
        print(f"Filesystem at {mount_point} is confirmed as read-only.")

if __name__ == "__main__":
    main()

#

this is where I get the output from

#

second paste is read_only_filesystem.py

#

this file runs in a docker container

#

and i use the io shit to get it to the host

#

this is very confusing stuff to be sharing my files

keen berry
#

I need you to show me the cat output and the python3 output in one paste

fierce ravine
#

idk what the problem is with my approach

keen berry
#

The output you're getting doesn't match the program you're running at all

#

Oh I see what's happening. There's a bug in parse_trick_and_run somewhere

#

It's calling print with a bytes object

#

@fierce ravine ^

fierce ravine
#

do you want to see parse_trick_and_run

keen berry
#

Yes

fierce ravine
#

i mean it doesn't print anything

#
def parse_trick_and_run(trick_data, args):
    container_name = args.get('container_name')
    # delete_docker_image(container_name)

    # next three function calls are generic. They will never be different
    check_if_container_is_running(container_name)

    original_directory = os.getcwd()
    os.chdir(trick_data['trick'][0]['path'])
    build_docker_image(trick_data['dockerfile'][0]['path'], container_name)
    os.chdir(original_directory)


    if bool(trick_data['dependencies'][0]['server']):
        # print("true")
        if not dependency_check.check_server():
            print(f"HTTP not turned on host. {x_button} \nQuitting Trick")
            return 1


    # third param to run_docker_container will always be for network. Waiting to find out what fourth, ..., nth is.
    run_docker_container(
                            container_name, 
                            container_name, 
                            str(trick_data['docker_config'][0]['network_mode']), 
                            trick_data['docker_config'][1]['read_only'],
                            trick_data['docker_config'][2]['security_opt'],
                            trick_data['docker_config'][3]['pid_mode'],
                            trick_data['docker_config'][4]['cpu_shares'],
                            trick_data['docker_config'][5]['volumes'],
                            trick_data['docker_config'][6]['mem_limit']
                        )
keen berry
#

Well why do you bother with redirect_stdout if it doesn't print anything?

fierce ravine
#

the run_docker_container is running a file in a container, and I want it's output

#

so i do that

keen berry
#

redirect_stdout only captures stuff that gets printed to sys.stdout eg python calls

#

Subprocess output is not captured

#

You need to use a pipe for that

#

Show that whole file

fierce ravine
#

but then how am i able to get the output

#

from the docker container to the host

#

with my method

keen berry
#

Show where the b'Filesystem at / ... gets printed

fierce ravine
#
import os
import subprocess

def is_read_only(mount_point):
    """
    Check if the filesystem at the given mount point is read-only.

    Args:
        mount_point (str): The path to the mount point.

    Returns:
        bool: True if the filesystem is read-only, False otherwise.
    """
    try:
        # Use the `mount` command to check filesystem options
        output = subprocess.check_output(['mount'], text=True)
        for line in output.splitlines():
            if mount_point in line and 'ro,' in line:
                return True
        return False
    except subprocess.CalledProcessError as e:
        print(f"Error checking filesystem mount options: {e}")
        return False

def test_write_permission(test_file_path):
    """
    Attempt to write to a test file to check write permissions.

    Args:
        test_file_path (str): Path to the test file.

    Returns:
        bool: True if write operation is successful, False otherwise.
    """
    try:
        with open(test_file_path, 'w') as test_file:
            test_file.write("Testing write permissions.")
        # Cleanup
        os.remove(test_file_path)
        return True
    except IOError:
        return False

def main():
    mount_point = '/'  # Change this to the actual mount point
    test_file_path = os.path.join(mount_point, 'test_write_permission.tmp')

    # Check if the filesystem is read-only
    if is_read_only(mount_point):
        print(f"Filesystem at {mount_point} is mounted as read-only.\r")
    else:
        print(f"Filesystem at {mount_point} is not read-only.")

    # Test write permissions
    if test_write_permission(test_file_path):
        print(f"Write permissions are available on {mount_point}.")
    else:
        print(f"Filesystem at {mount_point} is confirmed as read-only.")

if __name__ == "__main__":
    main()

#

this is running in the container

keen berry
#

Ah right ok. Show how you're capturing output from the container

#

Probably the whole file that contains run_docker_container

fierce ravine
#
def run_docker_container(image_name, container_name, network_mode, read_only, security_opt, pid_mode, cpu_shares, volumes, mem_limit):
    try:

        container = client.containers.run(
            image_name, 
            name=container_name, 
            detach=True, 
            network_mode=network_mode, 
            read_only=read_only, 
            security_opt=security_opt, 
            pid_mode=pid_mode, 
            cpu_shares=cpu_shares,
            volumes=volumes,
            mem_limit=mem_limit
        )

        print(f"Container '{container_name}' started successfully.")

        output = container.attach(stdout=True, stream=True, logs=True)
    except docker.errors.APIError as e:
        print(f"Error running Docker container: {e}")
#
container.attach(stdout=True, stream=True, logs=True)
#

this is how I get the output

keen berry
#

Show the whole file

fierce ravine
#

ok sorry

#

here

keen berry
fierce ravine
#

ah you're right

#

i got it to work

#
        # Attach to the container's logs
        for line in container.attach(stdout=True, stderr=True, stream=True, logs=True):
            print(line.decode('utf-8'), end='')
#

with this

#

so i don't think i need the other io lines in that other file

#

hmm looks like i still need it

#

but anyways it works now

#
huzi@huzi:~/Documents/houdini/api$ python3 run_trick.py 
Container read_only_filesystem already exists. Removing it.
Image 'read_only_filesystem' built successfully. โœ“
Container 'read_only_filesystem' started successfully.
Filesystem at / is mounted as read-only.
Filesystem at / is confirmed as read-only.

#

thanks man

keen berry
#

You shouldn't decode the lines like that

fierce ravine
#

then what should i do ?

keen berry
#

You need to use codecs.getincrementaldecoder("utf8")

#

Eg

for chunk in  codecs.iterdecode(container.attach(...), "utf8"):
    sys.stdout.write(chunk)
#

Otherwise you can get a utf8 character split across chunks

#

Or if you only want to return the output use stream=False and return it. Then you don't need that redirect_stdout hack

fierce ravine
#

thanks

#

ok i got it

torn girderBOT
#
Python help channel closed

This help channel has been closed and it's no longer possible to send messages here. If your question wasn't answered, feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.