Wemake-python-styleguide: Rationale for why print and pprint are in the blacklisted functions?

Created on 16 Aug 2020  路  4Comments  路  Source: wemake-services/wemake-python-styleguide

I am writing a cli application that does a lot of writing to stdout and also takes in prompts. I am wondering what is the reason the print functions are blacklisted and what else I should be using instead?

Most helpful comment

@orsinium that was a very helpful example to get me to re-think how I'm using side-effects, thank you!

I think my question has been answered, so I'll close.

All 4 comments

Side-effects

Prefer pure functions, try to return the result instead of printing it:

# bad
def f() -> None:
  print('oh hi mark')

# good
def f() -> str:
  return 'oh hi mark'

Read about pure functions and side-effects for more context.

Of course, you can't have an application without side-effects. So, your main function which is the entry point for the CLI does the printing. Use noqa to make this exception.

def main():
  print(command()) # noqa: WPS

Getting more control

AFAIK, if side-effects are ok for you, I'd recommend using logging instead. For example, see how it is done in DepHell:

In this way, you can easily configure output format (enable and disable the colored output, use JSON, etc), set verbosity level, provide additional context etc.

Putting together

  • Prefer returning information that you're going to test.
  • Prefer logging for non-important additional information.

Thanks for the very detailed response!

Of course, you can't have an application without side-effects. So, your main function which is the entry point for the CLI does the printing. Use noqa to make this exception.

I admit I'm probably not the norm, but my application is split into atomic "plugins" where each deals with one aspect of the application via subcommands (think git). Due to the "main" entrypoint not knowing which plugins are enabled ahead of time, and since some will produce output, some won't, some will alter other's output, etc. It seems more feasible to have these side-effects in each plugin and let them do any output they need to.

AFAIK, if side-effects are ok for you, I'd recommend using logging instead.

I am already using logging, but I didn't think it made sense to have prompts, where user input is required, to operate under the log, among other uses like executing commands who's sole job is to print stuff out to stdout.

See the logging docs also where it says print() should be used for

Display console output for ordinary usage of a command line script or program

If my application seems like a special case, then I suppose I'll just use noqa throughout where needed.

Probably, in this case, dependency injection would work best for you:

class PushCommand:
    stream = sys.stdout
    silent = False

    def echo(self, *text: str, sep: str = ' ', end: str = '\n') -> None:
        if silent:
            return
        print(*text, sep=sep, end=end, file=self.stream)  # noqa: WPS

    def __call__(self, *args):
        self.echo('oh hi mark')

This is an intermediate solution when you still have side-effects but can disable them, tweak verbosity, and overload the echo function in the tests.

In general, the rule is to reduce points where side-effects happen as much as you can. Just see what works best in your case.

@orsinium that was a very helpful example to get me to re-think how I'm using side-effects, thank you!

I think my question has been answered, so I'll close.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Dreamsorcerer picture Dreamsorcerer  路  4Comments

webknjaz picture webknjaz  路  3Comments

webartifex picture webartifex  路  5Comments

sobolevn picture sobolevn  路  3Comments

serhii73 picture serhii73  路  3Comments