Python Success & A question or two

I have had a massive problem for years involving MS Word and templates. I have a set of “core document” templates that I create for every new case that I handle. I’ve wanted for years to figure out a method to automate populating these templates for each new case. There are some automation tools that exist on the market, but they are exceedingly expensive. After listening to episode 54 with Dr. Drang, I decided I was going to finally sit down and figure this out on my own. I discovered a way to do this in Python and, honestly, it could not have been easier to do. I’m thrilled because it will save me and (primarily) my assistant hours of needless repetitive work that the computer should be doing for us. It’s great!

But I now have three questions.

  1. One of the fields in my MS Word merge file uses a forward slash. When I try to reference it and assign data to the field, I get an error from Python. I assume it thinks the forward slash means I want to divide. I’ve tried bracketing the field, which seems to be the way poorly formatted SQL columns are handled, but that didn’t do the trick. I tried using quotation marks, and I tried using the backslash as an escape character. Neither of those worked, either. I control the Word file, so I can change this field name. But I’d rather figure out how to be able to use it as is in Python (if possible).

  2. My Mac has three versions of Python: 2.7x, 3.7, and 3.8.4. If I run the program from IDLE, it works perfectly. If I run it from the command line, I get errors. It seems the cause is that the shebang is referencing Python 2.7 in /usr/bin. Must I use “/usr/local/bin/Python3.8/” as the shebang in all of my python programs? And if so, what happens when Python updates to 3.9 or 4.0 or something else? Anything I can do to avoid hardwiring the Python version in my program?

  3. I needed two packages to make this work. lmxl and docx-mailmerge. I was able to install them with pip. They seem to work just fine when I run my program from within IDLE or even the interactive interpreter from terminal; however, from the command line the interpreter can’t seem to access the mailmerge package. When I run pip from command line it confirms that the seemingly “missing” package has been installed.

Appreciate any help, ideas, or links elsewhere.

P.S. If these questions would be better on Stack Overflow or some place else, just say the word and I’ll ask this there.

If you use python3 when calling your script in the terminal, it will use the highest python3 version installed (3.8 in your case). It’s likely IDLE is automatically using a version of python 3. Similarly, using pip3, should resolve your issues with it not seeing the modules you’ve installed.

Virtual Environment Info

A common way to make this easier is to use a virtual environment. It essentially copies your python installation to a relative folder. You can then install modules in that environment. That way making sure all of your dependencies are in the right spot is just calling

source <venv folder>/bin/activate

And then your script. The link above explains it better than I ever could.

With regards to your slashes, can you include an example?

Thanks! I pulled up the virtual environment link and am reviewing that. As far invoking the script, I just use ./ So, I don’t call python3. If I invoked the script by calling python3, would it disregard the directive in the shebang?

Here is the code:

document = MailMerge(template_file)
    case_name='xxx v. yyy',
    court='Los Angeles Superior Court',

The problem is the “c/m” field name.

Note: Bracketed ([]) text is not actual code but a placeholder for this post.
Note 2: The text in document.merge is only hardcoded for this example.

So if your shebang is along the lines of #!/usr/bin/env/python3 It has the same effect as calling with python3

So a cool thing here is the mail merge library is using what’s called kwargs which is a way of describing an infinite number of arguments as a key/value pair, See explanation here

But, what that means is you can re-write that block as

document = MailMerge(template_file)
    "case_name": 'xxx v. yyy',
    "court": 'Los Angeles Superior Court',
    "c/m": 'ZZZZZ',
    "ct_file_no": 'xyz-abc-def'

and it should work the way you’re looking for (with the / escaped!). Assuming that the mail merge library is treating the variable name as a string too.

Edit: How I checked: Link

I thought I might be of some help, but I see @dustinknopoff has you well in hand, The only thing I should point out is a typo in one part of his last answer. Your shebang line should be

#!/usr/bin/env python3



In case you’re wondering where this is leading…


Thank you for this. So, all is working from the command line or the GUI or console interpreter. I was not able to get the kwargs version to work. The program runs w/o error, but no data gets written into the document. I don’t know if that means the merge fields are not actually being assigned data or if the problem is elsewhere. I’ll study the articles you linked a little more closely and keep trying. Thanks for your help.

And @dfay, that’s almost exactly what my mental picture of all of this looked like.

Shoot, I missed something else. When your function is expecting a set of keyword arguments and you want to pass it a dictionary of keyword/value pairs, you have to “unpack” the dictionary by using the ** operator.

So for the mail merge example, this should do the trick:

document = MailMerge(template_file)
kwargs = {"case_name": 'xxx v. yyy',
          "court": 'Los Angeles Superior Court',
          "c/m": 'ZZZZZ',
          "ct_file_no": 'xyz-abc-def'}

Good catch! I missed that when I was copying in to the browser.

1 Like

Thank you both. This works like magic! It’s perfect.

Dustin and Dr. Drang - Now that a month has gone by, I wanted to say thanks, again. I use this script regularly and not only does it save a huge amount of time it also results in the project getting done rather than get avoided. Last weekend, a ran a number of cases through it. It would have probably taken an hour and a half of opening templates, gathering the information (which isn’t even that much from every case), copying and pasting that information into several places, and then saving the new populated documents. It took fewer than 10 minutes using this script. It would have been even fewer if I hadn’t had to look up something from a court website. Thank you!