0

I am making infrastructure for methods dbg (stands for debug_message), info (stands from info_message) as well as log (logging functionality).

The dbg, info, and log methods will be called whatever the user input, however, they will function differently based on the user input, such as whether the user wants the process to print DEBUG or be fully QUIET as well as whether the user wants to LOG.

I could achieve such functionality as long as I am not using an object to wrap the functionality (for multiplicity reasons). When I wrap it into an object and call it from an object I get AttributeError, that the object has no method.

class Feedbacker(object):
    def __init__(self, task):
        self.LOG = task.LOG
        self.LOG_DIR = task.LOG_DIR
        self.DEBUG = task.DEBUG
        self.QUIET = task.QUIET

        self.timestamp = datetime.now().strftime("%Y-%m-%d_%H%M%S")

        # Logging
        # Based on parameter input. Creates a log file and logs all info output.
        if self.LOG: # If logging parameter was provided -> Initiate logging
            Path(self.LOG_DIR).mkdir(parents=True, exist_ok=True) # Creates directory

            import logging
            logging.basicConfig(format='%(asctime)s %(message)s',\
                handlers=[logging.FileHandler(\
                f"{self.LOG_DIR}/ytr_log_{self.timestamp}.log", 'w', 'utf-8')]) # UTC-8
            logging.logThreads = 0
            logging.logProcesses = 0
            logger=logging.getLogger()
            logger.setLevel(logging.ERROR)
            def log(*args,**kwargs):
                msg = " ".join(args) # Joins all args into one string. " " seperator.
                logger.log(60, msg) # First agr is the log level.

        else: # If logging is not provided, log will still be run, but will do nothing.
            def log(*args,**kwargs):
                pass
        # Debug message handling
        if self.DEBUG:
            def dbg(*args, head = "DEBUG", **kwargs):
                info(*args, head = head, **kwargs)
        else:
            def dbg(self, *args, head = "DEBUG", **kwargs):
                log(f"[{head}]: ", *args, **kwargs)
                pass
        # Quiet execution
        if self.QUIET:
            def info(*args, head = "INFO", **kwargs):
                log(f"[{head}]: ", *args,**kwargs)
        else:
            def info(*args, head = "INFO", **kwargs):
                print(f"[{head}]: ", *args,**kwargs)
                log(f"[{head}]: ", *args,**kwargs)

# Example call, which does not work.
fb = Feedbacker(task)
fb.dbg("Test message")

How can I define dbg method based on instance variables?

1
  • @Carcigenicate For performance. I don't want to import a whole logging module or do the check on every call. I like to import only if necessary and do the comparisons once. Commented Nov 20, 2020 at 17:14

2 Answers 2

2

Functions are values in python so you can arbitrarily reassign them.

You can do something like this (simplified example):

class Feedbacker(object):
    def __init__(self, switch):
        if switch:
            self.foo = self.bar

    def foo(*args):
        return "something"

    def bar(*args):
        return "something_different"

print(Feedbacker(False).foo()) # something
print(Feedbacker(True).foo()) # something_different
Sign up to request clarification or add additional context in comments.

Comments

1

This re-edit of what you had works, I think (limited testing). I had to make a dummy task definition which is certainly different from your original:

from datetime import datetime
from pathlib import Path

class Task:
    LOG = True
    LOG_DIR = 'C:\Temp\Logs'
    DEBUG = True
    QUIET = True

task = Task()

class Feedbacker(object):
    def __init__(self, task):
        self.LOG = task.LOG
        self.LOG_DIR = task.LOG_DIR
        self.DEBUG = task.DEBUG
        self.QUIET = task.QUIET

        self.timestamp = datetime.now().strftime("%Y-%m-%d_%H%M%S")

        # Logging
        # Based on parameter input. Creates a log file and logs all info output.
        if self.LOG: # If logging parameter was provided -> Initiate logging
            Path(self.LOG_DIR).mkdir(parents=True, exist_ok=True) # Creates directory

            import logging
            logging.basicConfig(format='%(asctime)s %(message)s',\
                handlers=[logging.FileHandler(\
                f"{self.LOG_DIR}/ytr_log_{self.timestamp}.log", 'w', 'utf-8')]) # UTC-8
            logging.logThreads = 0
            logging.logProcesses = 0
            self.logger=logging.getLogger()
            self.logger.setLevel(logging.ERROR)
            self.log = self.log_a

        else: # If logging is not provided, log will still be run, but will do nothing.
            self.log = self.log_b

        # Debug message handling
        if self.DEBUG:
            self.dbg = self.dbg_a
        else:
            self.dbg = self.dbg_b

        # Quiet execution
        if self.QUIET:
            self.info = self.info_a
        else:
            self.info = self.info_b

    def log_a(self,*args,**kwargs):
        msg = " ".join(args) # Joins all args into one string. " " seperator.
        self.logger.log(60, msg) # First agr is the log level.

    def log_b(self,*args,**kwargs):
        pass

    def dbg_a(self,*args, head = "DEBUG", **kwargs):
        self.info(*args, head = head, **kwargs)

    def dbg_b(self, *args, head = "DEBUG", **kwargs):
        self.log(f"[{head}]: ", *args, **kwargs)

    def info_a(self,*args, head = "INFO", **kwargs):
        self.log(f"[{head}]: ", *args,**kwargs)

    def info_b(self,*args, head = "INFO", **kwargs):
        print(f"[{head}]: ", *args,**kwargs)
        self.log(f"[{head}]: ", *args,**kwargs)

# Create the logging object and output test message
fb = Feedbacker(task)
fb.dbg("Test message")

After reading your comment, you can see it is far cleaner and simpler to just examine your configuration variables within the various calls:

class Feedbacker(object):
    def __init__(self, task):
        self.LOG = task.LOG
        self.LOG_DIR = task.LOG_DIR
        self.DEBUG = task.DEBUG
        self.QUIET = task.QUIET

        self.timestamp = datetime.now().strftime("%Y-%m-%d_%H%M%S")

        # Logging
        # Based on parameter input. Creates a log file and logs all info output.
        if self.LOG: # If logging parameter was provided -> Initiate logging
            Path(self.LOG_DIR).mkdir(parents=True, exist_ok=True) # Creates directory

            import logging
            logging.basicConfig(format='%(asctime)s %(message)s',
                handlers=[logging.FileHandler(
                f"{self.LOG_DIR}/ytr_log_{self.timestamp}.log", 'w', 'utf-8')]) # UTC-8
            logging.logThreads = 0
            logging.logProcesses = 0
            self.logger=logging.getLogger()
            self.logger.setLevel(logging.ERROR)

    def log(self,*args,**kwargs):
        if self.LOG:
            msg = " ".join(args) # Joins all args into one string. " " seperator.
            self.logger.log(60, msg) # First agr is the log level.

    def dbg(self,*args, head = "DEBUG", **kwargs):
        if self.DEBUG:
            self.info(*args, head = head, **kwargs)
        else:
            self.log(f"[{head}]: ", *args, **kwargs)

    def info(self,*args, head = "INFO", **kwargs):
        if not self.QUIET:
            print(f"[{head}]: ", *args,**kwargs)
        self.log(f"[{head}]: ", *args,**kwargs)

# Sample call
fb = Feedbacker(task)

fb.dbg("Test message")

2 Comments

Works, yet seems to add some clunkyness. Subjectively also more confusing. Since you seem to understand what I am trying to achieve with debug info and logging, from you experience, is there a more intuitive way to handle delivering feedback to user?
The un-clunky version would probably allow the dbg, info, and log calls to simply inspect the instance configuration variables that already have been saved. I'll add another answer...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.