Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Python str subclass with lazy evaluation of its value

I am building a command-line program that uses argparse.
In the (assumed-to-be) rare case of a wrong call, argparse will show a description string supplied when creating the ArgumentParser.

I want this description to show the version number of my program.
I want to extract this from the pyproject.toml file via tomllib.
Since this is an expensive operation (and even more so since I want to learn how to do it), I would like the description string to be evaluated lazily: only when it is actually to be printed.

I have not yet found a way to do it even though I am willing to build a one-trick-pony object specialized for this particular value:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

  • collections.UserString could provide the lazy evaluation (via overriding __getattribute__ for the data attribute), but, alas, some code in argparse uses re.sub() on it, which appears to check isinstance(x, str), which a UserString does not fulfill.
  • a subclass of str can override any operation done on a string — but not perform lazy evaluation for a plain use of the entire string. (Is this true?)
  • if ArgumentParser would use str(description) instead of description when it is about to print the description, one could supply an object that performs the lazy evaluation in its __str__ method. But, alas, ArgumentParser does not do this.

Is there any approach that does the job?

>Solution :

In a roundabout way: don’t set description, and only set it just before ArgumentParser would format the help.

import argparse
import time


class MyArgParser(argparse.ArgumentParser):
    def format_help(self):
        if not self.description:
            print("Now thinking hard...")
            time.sleep(3)
            self.description = "An application!"
        return super().format_help()


ap = MyArgParser()
ap.add_argument("--foo", help="foo")
args = ap.parse_args()
print(args)

This program is fast when run without arguments, or with --foo=bar, and takes its sweet time when you run with --help.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading