Skip to content

makepy: support for enums and type-hints#1364

Closed
tobias-loew wants to merge 11 commits intomhammond:masterfrom
tobias-loew:master
Closed

makepy: support for enums and type-hints#1364
tobias-loew wants to merge 11 commits intomhammond:masterfrom
tobias-loew:master

Conversation

@tobias-loew
Copy link
Copy Markdown

Hi,
I've added command flags to generate enum and type-hints.
I've tested it with a quite large typelib (generated py-file has > 100k lines) and it seems to work.
Regarding the enums: there's also code for creating "Enums" (instead of "IntEnums"; use createEnums == 1) but a could find a way to make properties working without either putting a runtime penalty on everyone or breaking the ABI in init.py. Maybe you've got an idea!
Tobias

Hi,
I've added command flags to generate enum and type-hints.
I've tested it with a quite large typelib (generated py-file has > 100k lines) and it seems to work.
Regarding the enums: there's also code for creating "Enums" (instead of "IntEnums"; use createEnums == 1) but a could find a way to make properties working without either putting a runtime penalty on everyone or breaking the ABI in __init__.py. Maybe you've got an idea!
Tobias
@thopiekar
Copy link
Copy Markdown
Contributor

Hello @tobias-loew !
Thank you for your contribution. 👍

Can you tell us which typelib has been used to test your work? Work be great to know to be able to reproduce your work.
Additionally, I still see some commented out lines in your code. Is there still some work to do to finish your PR? Are these to-dos you want to fix in the future?

Thanks! 🙂

@tobias-loew
Copy link
Copy Markdown
Author

tobias-loew commented Jul 22, 2019

Hi,
sorry for the commented code - I'll have a look at it.
I tested the extension with EbsOpen.tlb (in attached EbsOpen.zip), the COM-Library of the product I'm the lead developer (EBSILONProfessional, www.ebsilon.com)
EbsOpen.zip

Copy link
Copy Markdown
Owner

@mhammond mhammond left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay. Can you please give some examples of the output this generates? It's difficult to read given all the 2to3 changes here, which I'd prefer to not be part of this patch (although I really should make python 2.7 compatible changes to the entire tree)

tobias-loew and others added 2 commits September 11, 2019 09:35
removed unused option from command line help
removed unused option from command line help
@tobias-loew
Copy link
Copy Markdown
Author

tobias-loew commented Sep 11, 2019

I've import the "Microsoft Scripting Runtime" three times: the old way, with enums and with enums & typehints.
ScriptingRuntime.zip

And here is the imported "with enums and typehints" version of EbsOpen.py (the product I develop)
EbsOpen.zip

@tobias-loew
Copy link
Copy Markdown
Author

The extension for enums and type-hints require Python 3. So, all changes here target only Python 3.
I'm not a Python expert, so I don't know how to (if possible) hide code from Python 2.

@CarliJoy
Copy link
Copy Markdown

@tobias-loew to hide code from Python 2 use:

import sys
if sys.version_info >= (3, 0):
  your_python_3_code()

@mhammond given that version 300 was just released, the problems with 2to3 changes should be resolved or?

@mhammond
Copy link
Copy Markdown
Owner

@mhammond given that version 300 was just released, the problems with 2to3 changes should be resolved or?

Yes, please!

@tobias-loew
Copy link
Copy Markdown
Author

I've resolved the conflicts but didn't yet have time to make the "sys.version_info >= (3, 0)" changes.

@tobias-loew
Copy link
Copy Markdown
Author

IMHO the best way is to add an additional option to support the generation of files with enums for version 3 AND the old style for version 2.
Thus, python 3- only users won't have to suffer from the runtime overhead.
Any objections?

@CarliJoy
Copy link
Copy Markdown

Python 2 is not supported anymore. You can drop any Python 2 code.
Also pywin32 droppped Python 2 support beginning with Version 300. So you can simply ignore Python 2.
We just have to find out why test test are failing (currently Github has troubles downloading the log for me)

@kxrob
Copy link
Copy Markdown
Collaborator

kxrob commented Nov 29, 2020

We just have to find out why test test are failing (currently Github has troubles downloading the log for me)

Thats because of the deprecated "::set-env" command in the github CI runner - since 2 weeks or so. A fix is already in #1622 (patch github CI: Fix broken "::set-env". Use the new $GITHUB_ENV ) since some time. But @mhammond seems not to be around currently.

@tobias-loew
Copy link
Copy Markdown
Author

I made a local branch with the setenv-fix: all tests (but one that seems to hang) passed (https://github.com/tobias-loew/pywin32/actions/runs/390146137)

Copy link
Copy Markdown
Owner

@mhammond mhammond left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a quick look as I'm very busy at the moment, so might take some time to get back to this. I can't even remember what's in the .zip file you attached previously, but I do note that this really needs some comments - eg, what exactly is an enum in this context? What is a type-hint? When would I want to enable those options? When would I not want to enable those options? How is the large NativeTypeMap object used, etc? Ideally we'd also have tests, maybe by abusing PyCOMTest.idl?

@@ -0,0 +1,33 @@
"""Contains RelaxedIntEnum

This module is used by modules build by @makepy@ using enums.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit - "built"

typename = "DispatchItem"

def __init__(self, typeinfo=None, attr=None, doc=None, bForUser=1):
def __init__(self, typeinfo=None, attr=None, doc=None, bForUser=1, iCreateEnums=0):
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a huge fan of iCreateEnums - it looks everywhere like it's actually a bool, except in one place where magic values of 1 and 2 are used. ISTM an - err - enum would make sense here?

return None

def BuildCallList(fdesc, names, defNamedOptArg, defNamedNotOptArg, defUnnamedArg, defOutArg, is_comment = False):
def BuildCallList(fdesc, names, defNamedOptArg, defNamedNotOptArg, defUnnamedArg, defOutArg, is_comment = False, bTypeHints = 0):
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use False as the default.

@mhammond
Copy link
Copy Markdown
Owner

mhammond commented Sep 5, 2021

Thanks for the contribution, and feel free to reopen this if you end up making the requested changes.

@mhammond mhammond closed this Sep 5, 2021
@tobias-loew
Copy link
Copy Markdown
Author

Hi Mark,

I've seen your currently working on the project, so let me pick up the pieces from 2 years ago and answer your questions:

  • What's an enum in this context?
    It's a IDL enum (i.e. a C++ unscoped enum) on the COM-side (https://docs.microsoft.com/en-us/windows/win32/midl/enum). And for Python it's either a native python-enum (https://docs.python.org/3/library/enum.html) or it's a "relaxed" python enum that adds unknown values on the fly (see implementation in RelaxedIntEnum.py)

  • Type-hints are defined here https://peps.python.org/pep-0484/ and come in very handy when working with large libraries

  • The NativeTypeMap is needed to generate the appropriate type-hints for COM-automation types

  • some words on iCreateEnums:

    • Python-enums started with version 3.4, but versions before have to be supported, so enum-generation is an opt-in (same for type-hints). That's also the reason I didn't use an enum for iCreateEnums.
    • Why the hell are there two different enum-generation options (apart from "no enums" iCreateEnums == 0)?
      • option iCreateEnums == 1 generates native Python enums. But there is an issue: a COM method may be called with a value for an enum that is not among the "known" values. The Python-enum will throw an exception in that case. Which may be good or not. It depends on, what the user expects. So, there is also
      • option iCreateEnums == 2, which creates "RelaxedIntEnum"s which simply add unknown values to their internal map and don't throw.

    The CLI currently only allows to select option 2, but this could be changed easily.

I adopted my changes to the new main branch. In case your still interested in these changes, I think it would be best to open a new PR on main.

best
Tobias

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants