0

I am using Spyder for Pyhton and for some problems the output in the IPython console is quite large (more than 10000 lines) and it is quite inefficient to analyse the output directly in the IPython console. This is why I would like to know if there is a way how I can just print the output to a .txt file? I tried what was suggested here How to write console output on text file. So I use at the beginning of my code:

import sys
sys.stdout = open('C:/Users/Python_Code/log.txt', 'w')

and at the end sys.stdout.close(). However, I get an error message stating "Value Error: I/O operation on closed file" and the log.txt file is not created. If I create the log.txt file manually in the corresponding folder, the file remains empty. Not only remains the file empty but also Spyder does not react at all after executing this code so I have to shut it down and restart.

Do you have any idea, how I can redirect the console output to a txt-file? I'd appreciate every comment and would be thankful for your help.

PeterBe
  • 700
  • 1
  • 17
  • 37
  • See [here](https://stackoverflow.com/q/50549933/13145954) – Seon Jun 09 '21 at 13:05
  • How about `python your_script.py > your_file.txt`? – Klaus D. Jun 09 '21 at 13:06
  • 1
    See if putting `sys.stdout = sys.__stdout__` after you close the file makes any difference. It sounds like something is still trying to write to console after you close it, and if it is noncritical or you can't control it then it can be redirected to the normal console to avoid errors. – thshea Jun 09 '21 at 13:06

4 Answers4

1

Put sys.stdout = sys.__stdout__ after you close the file.

Something is still trying to write to console, so you have to change it to the system stdout to prevent errors after closing. If you absolutely must capture these logs, you must use the python file.py > output.txt on the command line.

thshea
  • 1,048
  • 6
  • 18
  • Thanks thshea for your answer. Basically it works. However now nothing on the console is printed. Is there a way to also print special output (not all) also to the console in addition to the file? – PeterBe Jun 10 '21 at 13:12
  • Any comment on my last comment? I'd highly appreciate every further comment from you. – PeterBe Jun 11 '21 at 06:27
  • Check out [logging](https://docs.python.org/3/library/logging.html) as per the answer below. It has multiple layers of logging that you can filter (debug, errors, etc) that you can manually filter. And it has functionality to write both to console and a file. – thshea Jun 11 '21 at 12:12
  • Note that you can do it with a lot less code than the other comment if you want minimal customization: `logging.basicConfig(filename='example.log', encoding='utf-8', level=logging.DEBUG)`. – thshea Jun 11 '21 at 12:14
  • Thanks for your answer thshea. I upvoted and accepted your answer. I really appreciate your help. – PeterBe Jun 11 '21 at 14:30
  • Hi thshea. I experienced some problem with your answers. Your inital answers lead to supressing the console output for the file as mentioned before. Strangely also for files that DON'T have you suggested code, nothing is printed on the console. Why is this the case because normally this should not affect other files – PeterBe Jun 17 '21 at 10:35
  • Your suggeted code `logging.basicConfig(filename='example.log', encoding='utf-8', level=logging.DEBUG). ` leads to an error message "ValueError: Unrecognised argument(s): encoding". So I tried to do what is recommended here https://stackoverflow.com/questions/10706547/add-encoding-parameter-to-logging-basicconfig. A log file is created however, there is still no console output. It is just in the file. Then there is a further problem with the file. The size of the file increases with every run so I think it is somehow not closing. altough I use you suggested code `sys.stdout = sys.__stdout__` – PeterBe Jun 17 '21 at 10:37
  • Any comments on my last comments. I'd highly appreciate every further comment from you – PeterBe Jun 18 '21 at 06:51
  • Any comments on my last comment? – PeterBe Jun 21 '21 at 07:08
  • Hi thshea. Your suggested approach leads to some problems (see my previous comments). Do you have any idea how I can tackle them? I'd highly apprciate every further comment from you. – PeterBe Jun 22 '21 at 08:10
  • Any comments on my last comments and the problem that occurs when using your suggested code? – PeterBe Jun 30 '21 at 10:28
1

I do not see that deep into python to have a definite answer, but I suppose there is some safeguard to prevent you from closing the underlying stream associated with any of the stdout, stderr, stdin. So the solution would be to save sys.stdout temporarily to some variable and the reassign it before closing. Here is an example:

In [1]: import sys

In [2]: f = open('log.txt', 'w')

In [3]: temp = sys.stdout

In [4]: sys.stdout = f
In [5]: print("Hi")
In [6]: sys.stdout = temp

In [7]: f.close()

In [8]: !cat log.txt

Hi

Or in a more elegant way (I'd say this is the pythonic way of doing it):

In [9]: from contextlib import redirect_stdout

In [10]: with open('log.txt', 'w') as f:
    ...:     with redirect_stdout(f):
    ...:         print("Hi again!")
    ...:

In [11]: !cat log.txt
Hi again!
Majo
  • 344
  • 2
  • 6
0

If your code uses logging module, you can configure the handler to write to the file.

Example:

import logging.config

logging.config.dictConfig({ 
    'version': 1,
    'disable_existing_loggers': True,
    'formatters': { 
        'standard': { 
            'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
        },
    },
    'handlers': { 
        'default': { 
            'level': 'INFO',
            'formatter': 'standard',
            'class': 'logging.FileHandler',
            'filename': 'error.log',
            'mode': 'a',
        },
    },
    'loggers': { 
        '': {  # root logger
            'handlers': ['default'],
            'level': 'WARNING',
            'propagate': False
        },
        'some.package': { 
            'handlers': ['default'],
            'level': 'INFO',
            'propagate': False
        }
    } 
})
Alexander Volkovsky
  • 2,588
  • 7
  • 13
0

The best way is to use something like print("your output", file=...).

The full code is like this:

with open("output_text.txt", "w") as f:
    print("your output text ...", file=f)
Alipqb
  • 101
  • 4
  • 7