3

I have a piece of software (2100 SLOC) that I consider to run in two different versions: one version provides verbose debug information to the console and the other version is an optimized release version.

My goal is to have a single git branch to maintain. Is there a way to mark the debug parts of the code and signal the Python interpreter to ignore these parts of the code?

Possible applications include: print statements, Python's logging facility, profiling, and assertions [Edit: These are apparently ignored by setting the -O flag].

noumenal
  • 1,077
  • 2
  • 16
  • 36
  • 1
    Where did you read that decorators were bad practice? Have you considered simply setting different logging output levels in the two different environments, and only using `logging` rather than `print`? You can just use `-O` when invoking Python to exclude any `assert`ions you may have. – jonrsharpe Jun 26 '16 at 11:17
  • @jonrsharpe I read about decorators [here](http://stackoverflow.com/a/862899/1103558). I am not familiar with how the interpreter handles logging. – noumenal Jun 26 '16 at 11:26
  • That's why you wouldn't use it to mark every function as debuggable, it's not clear why you think that's relevant here. – jonrsharpe Jun 26 '16 at 11:27
  • @jonrsharpe That was a thought error of mine concerning the generalizability of the statement. I have updated the question. – noumenal Jun 26 '16 at 11:34
  • 1
    I found this useful when creating my first big Python project: http://jeffknupp.com/blog/2013/08/16/open-sourcing-a-python-project-the-right-way/ – jonrsharpe Jun 26 '16 at 11:58

2 Answers2

4

I think you are overcomplicating this. You should ideally not have different code paths for development and production environments, just different configuration, otherwise it becomes harder to be sure whether your tests actually reflect how the code will behave when deployed. Things like profiling and debugging the code should be external to that process, things you run on your codebase rather than part of your codebase.

If all you're concerned with is the logging, just set different output levels in different environments. Assuming you have a standard library logging setup, you could do something like:

import logging
import os

logging.basicConfig(
    level=getattr(logging, os.getenv('LOG_LEVEL', 'DEBUG')),
    ...
)

in your entry point, this way you could set an explicit LOG_LEVEL environment variable (one of the allowed values) in your production environment, and default to DEBUG for development. Alternatively make the default the production level (e.g. ERROR) and set it explicitly in your development environments. You should then only output messages via logging, and not use print at all.

You should also let the loggers handle any string interpolation, i.e. using:

logger.info('hello %s', 'world')

rather than:

logger.info('hello %s' % 'world')  # or logger.info('hello {}'.format('world'))

So that if that logging level isn't active it can optimise out the interpolation for you.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • I am looking forward to refactoring my project and setting up an additional `-O` run argument in my IDE. My only remaining concern is whether [`isEnabledFor`](https://docs.python.org/2/howto/logging.html#optimization) will be called in `-O` mode. – noumenal Jun 26 '16 at 11:43
  • 1
    @noumenal unless you're doing computationally expensive things *only to log* (in which case re-think whether you really need them) you don't need to call that at all. But no, `-O` won't remove that call. – jonrsharpe Jun 26 '16 at 11:45
  • I am just getting started with unit testing, but that is probably the better way to handle computationally expensive 'logging', e.g. using [hypothesis](http://hypothesis.works). – noumenal Jun 26 '16 at 11:50
  • @noumenal that's for *testing*, not *logging*, and therefore shouldn't be part of the deployed code at all. Typically the tests are in a separate directory to the package itself, and you only deploy the package (once the tests all pass). The logging/output done by the tests is irrelevant as far as production performance goes. – jonrsharpe Jun 26 '16 at 11:52
2

I found an answer here:

if __debug__:
    doSomething()

To set __debug__ to false requires you to run Python with either flag -O or -OO

Community
  • 1
  • 1
noumenal
  • 1,077
  • 2
  • 16
  • 36