4

I'm writing a library to create and manipulate Word .docx files in Python. In general, I take a lot of influence from the Microsoft VBA/C# API for Word in designing the API, figuring they've given it a lot more thought than I'll ever be able to. Several times I've found the wisdom in designing it the way they did only after getting much further down the road.

A table has the properties .rows and .columns, each of which is a sequence of the Row and Column instances in the table, respectively. In the MS API, the methods for adding a new one are Table.rows.add() and Table.columns.add().

I'm inclined to believe this is more complicated than necessary, making my API harder for beginners to learn without really providing any benefit. I'm thinking Table.add_row() and Table.add_column() would better suit. As it happens, it also simplifies the code somewhat; that's not a motivator, just an observation that I wonder might be trying to tell me something.

Is there an argument for preferring the former?

0
1

If all you're doing is mapping the Word API commands, you may not be giving any actual value over just spooling up an instance of winword.exe and utilizing the API over COM. So, you should consider what it is that you're trying to achieve.

  1. If you're trying to replace the COM calls with a native implementation, you should hew as close to the underlying API as practical. It would be valuable to be able to invoke a same-process library to generate the appropriate WordML as either an XML or a ZIP'd archive (renamed to DOCX, of course), but if you do so there's no value in deviating from the extant API.

  2. If instead you're trying to simplify the process of creating or populating a Word Document in Python, your API should be focused on the use case you present rather than replicating what Word provides. There are lots of concepts in Word's model that only make sense due to word's peculiarities, and aren't necessary if you're going to be filling out a "form" based on fields, or adding multiple paragraphs, or adding rows from some data query. In general, you should implement your own methods, and only copy the Word interface when necessary.

Personally, I'm a big fan of higher-level task methods, like your proposed Table.add_row() method, that provide additional functionality. Being to able to call add_row and pass it the values for that row would be useful, especially if you could abstract it to an add_rows method to make a table from a two-dimensional array or similar construct.

1
  • Thanks Doug, this is just the kind of insight I was looking for. My aims are much closer to the latter you mention. The library will not be connected to COM or .NET and seems most popular on non-Windows platforms. Your advice gives me the encouragement I needed to follow my intuition on this one :) I like your notion of an add_rows() method, I'll give that one a noodle, maybe could directly feed a resultset from a sqlalchemy query or something :). Thanks again. – scanny Jan 5 '14 at 5:08
5

It's generally easier to manage a hierarchical system of things than a flat structure when there's more than a few of them. Your two methods don't reveal this, there's only two. But you also need delete_column, move_column, sort_column, column_width, column_border and so on, plus the same for rows...

I suspect you'll find that there's a big tree of properties and methods attached to the table. And just the properties will be a fairly long list. It'll probably have categories of properties - appearance, structure, behaviour and more. Each property will have methods and properties of its own. Thousands of them, in all likelihood.

The combination of nodes like those, plus the links between them (the dots, in this notation - so the node "table" links to "column") gives you a big, complex graph. Note that the graph might have loops and other things, it's not just a tree. Which means it might not be even possible to flatten it the way you are thinking of.

For example, the table, the column, the cell all have a font property. And fonts have a bold property. So, how many "bold" properties will your flattened list have?

This is one of the things object oriented design started out trying to solve, BTW - "things" in the code that have both attributes (bold) and behaviour (add_row). Relationships in this case are just attributes "has a" (references and pointers) or "is a" (inheritance).

1
  • Thanks for your answer, that helps me see the question of symmetry, which I hadn't considered. I'm not proposing to flatten all the members onto table, column will still have its width and borders properties for example; I was just puzzling over where the add() method would be most natural. The symmetry question is interesting, delete and perhaps move would come into it on that. The pythonic delete would be on the collection del rows[idx]. I'm not sure how I would do move just yet. But this is helpful, thanks :) – scanny Jan 4 '14 at 10:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.