Menu

#122 Provide enums dynamically

Unstable (example)
closed-wont-fix
nobody
None
5
2017-11-25
2013-03-25
No

In COM enums are transported as integers and hence hard to use for a programmer, which always has to map these numbers to comprehensive names. Since the enums are only available in typelibraries a wrapper had to be generated (makepy, gencache) to use them. There was no way that a enum could be used dynamically the same way a a COM object. The patch provides a way to use enums dynamically without generating a wrapper. So it is easy to use from a programmers viewpoint. The enum implementation used metaclasses so that the representation of the enum is always in a readable form and the enums are provided via members of enum classes. Used typelibraries are scanned inclusive their dependencies.

>>> from win32com.client import Enums
>>> from win32com.client import Dispatch
>>> Word = Dispatch("Word.Application")
>>> constants = Enums(Word)
>>> constants.CertificateDetail.certdetIssuer
<certdetIssuer 2>
>>> print constants.CertificateDetail.certdetIssuer
certdetIssuer
>>> constants.CertificateDetail.certdetIssuer + 2
4

This enums class is used for over a year in our Python distribution and tested against Python 2.7.3 and Python 3.2.3

Discussion

  • Stefan Schukat

    Stefan Schukat - 2013-05-03

    Diff for patch

     
  • Stefan Schukat

    Stefan Schukat - 2013-05-03

    Added the patch with pep8 checked source and unit tests.

     
  • Mark Hammond

    Mark Hammond - 2013-05-06

    You might need to sell this one some more. I see that having constants from dynamic objects is a win, but all the other behaviour seems of questionable utility, especially given the size of the additional code (eg, why is that repr or print a win given it would be quite obvious to the developer without them, why can arbitrary integers be added to enums, etc)

    I'd be very happy with a patch that extended the existing simple-to-understand "constants" to work with dynamic objects though. Also note that pywin32 works with Python 2.5 and later, so code that works only in 2.7+ wouldn't be acceptable (although I haven't checked to see what the min version this code actually does work with)

     
  • Stefan Schukat

    Stefan Schukat - 2013-05-06

    Actually the code was developed with Python 2.5 and then tested with 2.7.4 and 3.2, so backward compatibility should be no issue.
    The extra code in the str function is due to the use cases that in a GUI or with an print the user should be able to see the enum names and not the values (e.g. in a combobox). With the str utility function the developer must not make it own mapping for the display. The repr function is overwritten because a simple integer value (which would be valid for the eval function) would not represent the originally used enum item. Hence I used the angle bracket notation to show the enum named and integer value. In addition a REPL situation it is easier to determine the value of an enum
    >>> from win32com.client import Dispatch, Enums
    >>> App = Dispatch("Word.Application")
    >>> constants = Enums(App)
    >>> Doc = App.Documents.Add()
    >>> print constants.WdShowFilter(Doc.FormattingShowFilter)
    wdShowFilterFormattingRecommended
    >>> print constants.WdLineEndingType(Doc.TextLineEnding)
    wdCRLF
    >>> constants.WdLineEndingType(Doc.TextLineEnding)
    <wdCRLF 0>

    The arbitrary integer comment I don't understand, the valid enum values are encoded in the _names attribute. All other values lead to an unknown element, which is not added to the internal list.
    During the writing I found a bug in the str methods of the enum and bitmask classes. Fix is added to the patch queue and added the diff as file.

     
  • Stefan Schukat

    Stefan Schukat - 2013-05-06

    Bug ix in str method

     
  • Mark Hammond

    Mark Hammond - 2013-05-06

    Re the integers - it was a throw-away comment regarding:

    >>> constants.CertificateDetail.certdetIssuer + 2
    4

    where adding integers to an enum doesn't really make sense unless the enum is being treated as integer - which they are now.

    I'm not yet convinced the amount of code here is worthwhile when, best I can tell, you are suggesting the primary benefit is for a GUI environment where these values appear in a drop-down - I'd then argue that this burden belongs in that GUI. I can't really see how a developer *not* using such a GUI would benefit from these new objects, and it adds cognitive overhead for the average user (eg, "when do I use an enum vs win32com.client.constants?", "what are the benefits of one over the other?", etc)

    python-dev is also discussing adding enums as a builtin type (via PEP 435), so I'm inclined to reject this at least until that discussion settles down and we can see if pywin32 should use the new type rather than rolling our own (even if that type is only available in 3.? and later - .constants works fine for everyone else.

     
  • Stefan Schukat

    Stefan Schukat - 2013-05-06

    The problem with the win32com.constants is that the generated module is bound to a specific version of the typelibrary. This module could not be easily accessed from an object created with client.Dispatch or gencache.EnsureDispatch. If you use gencache.EnsureModule to access the constants there is no easy way to get the information needed if you only have the ProgId which is enough for the creation of the objects.
    In addition to that the constants in win32com.client wrappers only give access to the enums in one typelibrary. If the enums are defined in a dependent typelibrary you would have to generate this typelibrary too (e.g. mso.. constants for office). This implementation automatically scans all dependent typelibraries and merges the constants.

     
  • Mark Hammond

    Mark Hammond - 2013-05-06

    I agree that fixes for those issues with win32com.constants would be ideal. What I'm pushing back on is the introduction of a new object and implementation that serves the same basic role. IOW, I'd much rather see improvements to win32com.constants...

     
  • Stefan Schukat

    Stefan Schukat - 2013-05-06

    Fair enough, two places which serve similar functionality decrease the maintainability of an API. I'll have a look at the constants implementation, to see if these use cases could be coupled without breaking backward compatibility.

     
  • Mark Hammond

    Mark Hammond - 2017-11-25
    • status: open --> closed-wont-fix
    • Group: --> Unstable (example)
     

Log in to post a comment.