I have about a dozen functions (that are run as scripts) that have very similar sections interleaved with specialized code. I copied two of the scripts below. Here’s the first:
def pitz_estimate_task(): p = optparse.OptionParser() p.add_option('--version', action='store_true', help='Print the version and exit') # This script requires these arguments. p.set_usage("%prog task [estimate]") options, args = p.parse_args() if options.version: print_version() return # This is unique to this script. if not args: p.print_usage() return # And now we're back to boring generic stuff. pitzdir = Project.find_pitzdir(options.pitzdir) proj = Project.from_pitzdir(pitzdir) proj.find_me() # This section is specific to this script. t = proj[args] if len(args) == 2: est = proj[args] else: est = Estimate.choose_from_already_instantiated() t['estimate'] = est # That was the last thing that was specific to just this script. # Save the project (generic). proj.save_entities_to_yaml_files()
That script does some “generic” stuff to build an object p, then adds on some extra tweaks to p, and uses p to build an options object and an args object.
Then the script does some generic stuff to build a proj object based on the data in the options.pitzdir object, and does some various method calls on the proj object.
And here’s another script:
def pitz_attach_file(): p = optparse.OptionParser() p.add_option('--version', action='store_true', help='Print the version and exit') # Notice this line is different than the one in pitz_estimate_task. p.set_usage("%prog entity file-to-attach") options, args = p.parse_args() if options.version: print_version() return # This section is different too. if len(args) != 2: p.print_usage() return # Back to the generic code to build the project. pitzdir = Project.find_pitzdir(options.pitzdir) proj = Project.from_pitzdir(pitzdir) proj.find_me() # Some interesting stuff that is specific just for this script. e, filepath = proj[args], args e.save_attachment(filepath) # Save the project. (Generic). proj.save_entities_to_yaml_files()
So, the pattern in every script is: generic code, specific code, generic code, specific code, generic code. And each step depends on the previous step.
I know I could do stuff like wrap all the generic stuff into functions, but I’m not really a fan of that approach. I’m looking for an interesting way to reduce all repetition, but keep the legibility. I’m thinking some nested context managers or decorators might be the way to go. I like to hear ideas from other people, so, please, let me hear them.
By the way, all this code is from the command-line module of pitz, available here. That’s where you can see all the different variations on the same theme.