Duplicated stdout and input call leads to 'Logger' object has no attribute 'errors'

Hello

Hard to summarize my issue in title…
I recovered an old project, written with python2, upgraded it to python 3.4 (blocked by my OS: SLES12SP5), all was good… until I tried to “enhance” a display.
In application, stdout is duplicated for taking all traces in console and a file, it’s still from old code in python2 I think:

import log
sys.stdout = log.Logger(sys.stdout, "install.log") 

The point to enhance is an user input, asked with a “nice_input” function:

def nice_input(question, validate=None):
    """
    Ask for text input
    :param question: Question text
    :param validate: Validation method
    :return: the user input
    """

    if validate is not None:
        questions = [
            inquirer.Text('response', message=question, validate=validate),
        ]
    else:
        questions = [
            inquirer.Text('response', message=question),
        ]
    answers = inquirer.prompt(questions)
    return answers['response']

At this point, the display disappointed me : if user enters a wrong entry, the question is displayed again with the entry. If user uses the backspace, display is not erased and only cursor moves. With a “shift + backspace”, characters are well erased.
So I tried a more logic method I think (and with better display) :

while True:
    backup_file_name = input("Backup file name: ")
    if is_a_valid_filename(backup_file_name):
        break

but… an error occurs on the ‘input’ (I tried a simple ‘input’ call and error occurs) :
AttributeError: ‘Logger’ object has no attribute ‘errors’

I’m trying to change the way that stdout is duplicated to a file (with logging module or this method :

class Logger(object):
    def __init__(self):
        self.terminal = sys.stdout
        self.log = open("logfile.log", "a")
   
    def write(self, message):
        self.terminal.write(message)
        self.log.write(message)  

    def flush(self):
        # this flush method is needed for python 3 compatibility.
        # this handles the flush command by doing nothing.
        # you might want to specify some extra behavior here.
        pass    

sys.stdout = Logger()

) but without success. The following error occurs:
File “install.py”, line 180, in
firewall2.reload()
File “/tmp/app/data/firewall2.py”, line 93, in reload
subprocess.check_call(["/sbin/SuSEfirewall2"], stdout=sys.stdout, stderr=sys.stdout)
File “/usr/lib64/python3.4/subprocess.py”, line 553, in check_call
retcode = call(*popenargs, **kwargs)
File “/usr/lib64/python3.4/subprocess.py”, line 534, in call
with Popen(*popenargs, **kwargs) as p:
File “/usr/lib64/python3.4/subprocess.py”, line 820, in init
errread, errwrite) = self._get_handles(stdin, stdout, stderr)
File “/usr/lib64/python3.4/subprocess.py”, line 1305, in _get_handles
c2pwrite = stdout.fileno()
AttributeError: ‘Logger’ object has no attribute ‘fileno’

As I said, it’s an old project with some thousands lines code… hope I could avoid changing a lot of interactions with I/O streams.

Any advice on the way to solve this kind of problem ? maybe an issue on stdin as the ‘input’ function leads to the error ?

Just FYI, Python 3.4 was released over seven and a half years ago, and has been end of life upstream for well over two and a half years. Few modern packages support it anymore, and many never did in the first place.

In any case, if you want a logger that logs both to a file and to stdout, there is no need for aweful hacks. Instead, simply add two handlers, one for logging to stdout, and one for logging to a file. See the first few lines of the official logging cookbook. Here’s an abridged version with just the parts most relevant to your issue:

import logging
import sys

# Create logger for 'spam_application'
logger = logging.getLogger('spam_application')
# Create file handler
fh = logging.FileHandler('install.log')
# Create console handler
ch = logging.StreamHandler(sys.stdout)
# Add the handlers to the logger
logger.addHandler(fh)
logger.addHandler(ch)

Cheers!

Thanks for the tips, I already tried something like that but I’ll try again.

In fact, it’s an old project, I have to maintain it before making any global change (as changing for a newer version for python…) and, as I’m a new python user, I have to go step by step.
The main advantage I see in proceeding this way on an old project, is to understand the mechanisms related to python.