winmd2py 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
winmd2py-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mahmoud Komaiha
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,67 @@
1
+ Metadata-Version: 2.4
2
+ Name: winmd2py
3
+ Version: 0.1.0
4
+ Summary: Generate ctypes bindings for classic COM interfaces from .winmd metadata, in pure Python
5
+ Author-email: Mahmoud Komaiha <mkomaiha@umich.edu>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/mkomaiha/portacom
8
+ Project-URL: Repository, https://github.com/mkomaiha/portacom
9
+ Project-URL: Issues, https://github.com/mkomaiha/portacom/issues
10
+ Project-URL: Changelog, https://github.com/mkomaiha/portacom/blob/main/CHANGELOG.md
11
+ Keywords: com,ctypes,winmd,win32metadata,bindings,code generator
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Operating System :: Microsoft :: Windows
20
+ Classifier: Operating System :: POSIX :: Linux
21
+ Classifier: Operating System :: MacOS
22
+ Classifier: Topic :: Software Development :: Code Generators
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Provides-Extra: runtime
27
+ Requires-Dist: portacom<0.2,>=0.1; extra == "runtime"
28
+ Dynamic: license-file
29
+
30
+ # winmd2py
31
+
32
+ Generates [portacom](https://pypi.org/project/portacom/) ctypes bindings from
33
+ a `.winmd` file in the Win32 metadata format, in pure Python (no .NET).
34
+
35
+ ```bash
36
+ pip install "winmd2py[runtime]" # the generator, and portacom, which the bindings import
37
+ winmd2py Windows.Win32.winmd -n Windows.Win32.Graphics.Direct3D.Dxc -o bindings
38
+ winmd2py Microsoft.Direct3D.D3D12.winmd --ref Windows.Win32.winmd -o d3d12
39
+ ```
40
+
41
+ or from Python:
42
+
43
+ ```python
44
+ import winmd2py
45
+
46
+ winmd2py.generate("Microsoft.Direct3D.D3D12.winmd", "d3d12", refs=["Windows.Win32.winmd"])
47
+ ```
48
+
49
+ - `--ref OTHER.winmd` (repeatable) is a file whose types the input uses. Since
50
+ Win32Metadata 71, D3D12 is in `Microsoft.Direct3D.D3D12.winmd` and uses
51
+ `Windows.Win32.winmd`'s types. What is used from a reference file is
52
+ generated too, into partial modules, so the output needs nothing else.
53
+ - Without the file that declares a type, a struct that holds it by value, or an
54
+ interface derived from it, still imports but raises `TypeError` when used,
55
+ and the generator says which file to pass with `--ref`.
56
+ - Types and functions that the metadata declares once per architecture (x86,
57
+ x64, ARM64) are declared once; what differs is chosen on import by
58
+ `portacom.ARCH`.
59
+ - Delegates become classes with their signatures, so callbacks take Python
60
+ callables; one whose signature can't be described is passed as `void*`, and
61
+ reported.
62
+
63
+ The bindings follow the Windows ABI that the metadata describes. For a library
64
+ built differently off Windows, declare how with `portacom.use_abi()` before
65
+ importing them. See the
66
+ [project README](https://github.com/mkomaiha/portacom#readme), which also says
67
+ what a `.winmd` for your own IDL needs.
@@ -0,0 +1,38 @@
1
+ # winmd2py
2
+
3
+ Generates [portacom](https://pypi.org/project/portacom/) ctypes bindings from
4
+ a `.winmd` file in the Win32 metadata format, in pure Python (no .NET).
5
+
6
+ ```bash
7
+ pip install "winmd2py[runtime]" # the generator, and portacom, which the bindings import
8
+ winmd2py Windows.Win32.winmd -n Windows.Win32.Graphics.Direct3D.Dxc -o bindings
9
+ winmd2py Microsoft.Direct3D.D3D12.winmd --ref Windows.Win32.winmd -o d3d12
10
+ ```
11
+
12
+ or from Python:
13
+
14
+ ```python
15
+ import winmd2py
16
+
17
+ winmd2py.generate("Microsoft.Direct3D.D3D12.winmd", "d3d12", refs=["Windows.Win32.winmd"])
18
+ ```
19
+
20
+ - `--ref OTHER.winmd` (repeatable) is a file whose types the input uses. Since
21
+ Win32Metadata 71, D3D12 is in `Microsoft.Direct3D.D3D12.winmd` and uses
22
+ `Windows.Win32.winmd`'s types. What is used from a reference file is
23
+ generated too, into partial modules, so the output needs nothing else.
24
+ - Without the file that declares a type, a struct that holds it by value, or an
25
+ interface derived from it, still imports but raises `TypeError` when used,
26
+ and the generator says which file to pass with `--ref`.
27
+ - Types and functions that the metadata declares once per architecture (x86,
28
+ x64, ARM64) are declared once; what differs is chosen on import by
29
+ `portacom.ARCH`.
30
+ - Delegates become classes with their signatures, so callbacks take Python
31
+ callables; one whose signature can't be described is passed as `void*`, and
32
+ reported.
33
+
34
+ The bindings follow the Windows ABI that the metadata describes. For a library
35
+ built differently off Windows, declare how with `portacom.use_abi()` before
36
+ importing them. See the
37
+ [project README](https://github.com/mkomaiha/portacom#readme), which also says
38
+ what a `.winmd` for your own IDL needs.
@@ -0,0 +1,43 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "winmd2py"
7
+ version = "0.1.0"
8
+ description = "Generate ctypes bindings for classic COM interfaces from .winmd metadata, in pure Python"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ authors = [{ name = "Mahmoud Komaiha", email = "mkomaiha@umich.edu" }]
13
+ requires-python = ">=3.10"
14
+ dependencies = []
15
+ keywords = ["com", "ctypes", "winmd", "win32metadata", "bindings", "code generator"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Intended Audience :: Developers",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Operating System :: Microsoft :: Windows",
25
+ "Operating System :: POSIX :: Linux",
26
+ "Operating System :: MacOS",
27
+ "Topic :: Software Development :: Code Generators",
28
+ ]
29
+
30
+ [project.optional-dependencies]
31
+ runtime = ["portacom>=0.1,<0.2"]
32
+
33
+ [project.urls]
34
+ Homepage = "https://github.com/mkomaiha/portacom"
35
+ Repository = "https://github.com/mkomaiha/portacom"
36
+ Issues = "https://github.com/mkomaiha/portacom/issues"
37
+ Changelog = "https://github.com/mkomaiha/portacom/blob/main/CHANGELOG.md"
38
+
39
+ [project.scripts]
40
+ winmd2py = "winmd2py.cli:main"
41
+
42
+ [tool.setuptools.packages.find]
43
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,11 @@
1
+ """winmd2py: generate portacom ctypes bindings from a .winmd file, in pure Python.
2
+
3
+ winmd2py.generate("Windows.Win32.winmd", "bindings", ["Windows.Win32.Graphics.Direct3D.Dxc"])
4
+ writes the bindings of that namespace, and of what it uses, as the package "bindings".
5
+ """
6
+
7
+ __version__ = "0.1.0"
8
+
9
+ from .emit import Generator, generate # noqa: E402 (emit reads __version__)
10
+
11
+ __all__ = ["generate", "Generator", "__version__"]
@@ -0,0 +1,3 @@
1
+ from .cli import main
2
+
3
+ raise SystemExit(main())
@@ -0,0 +1,58 @@
1
+ """winmd2py FILE.winmd [-n NAMESPACE ...] [--ref OTHER.winmd ...] -o OUTDIR"""
2
+
3
+ import argparse
4
+ import sys
5
+ import time
6
+
7
+ from . import __version__
8
+ from .emit import Generator
9
+ from .model import WinMD
10
+
11
+
12
+ def main(argv=None):
13
+ parser = argparse.ArgumentParser(
14
+ prog="winmd2py",
15
+ description="Generate portacom ctypes bindings for classic COM interfaces from a .winmd file. "
16
+ "The bindings follow the Windows ABI the metadata describes; for a library built differently, "
17
+ "call portacom.use_abi() before importing them.",
18
+ )
19
+ parser.add_argument("winmd", help="the .winmd file (Win32 metadata format)")
20
+ parser.add_argument(
21
+ "-n",
22
+ "--namespace",
23
+ action="append",
24
+ dest="namespaces",
25
+ help="namespace to generate (repeatable; default: all namespaces in the file)",
26
+ )
27
+ parser.add_argument(
28
+ "--ref",
29
+ action="append",
30
+ default=[],
31
+ metavar="OTHER.winmd",
32
+ help="a .winmd whose types the file uses, such as Windows.Win32.winmd for "
33
+ "Microsoft.Direct3D.D3D12.winmd (repeatable); what is used from it is generated too",
34
+ )
35
+ parser.add_argument("-o", "--outdir", help="output package directory")
36
+ parser.add_argument("--list", action="store_true", help="list the namespaces in the file and exit")
37
+ parser.add_argument("-q", "--quiet", action="store_true", help="do not print what was left out or simplified")
38
+ parser.add_argument("--version", action="version", version=f"winmd2py {__version__}")
39
+ args = parser.parse_args(argv)
40
+ if not args.list and not args.outdir:
41
+ parser.error("-o/--outdir is required")
42
+
43
+ start = time.time()
44
+ try:
45
+ if args.list:
46
+ for ns in WinMD(args.winmd).namespaces():
47
+ print(ns)
48
+ return 0
49
+ generator = Generator(args.winmd, args.namespaces, refs=args.ref)
50
+ written = generator.generate(args.outdir)
51
+ except (OSError, ValueError) as error:
52
+ print(f"winmd2py: error: {error}", file=sys.stderr)
53
+ return 1
54
+ if not args.quiet:
55
+ for note in generator.notes:
56
+ print(f"winmd2py: {note}", file=sys.stderr)
57
+ print(f"winmd2py: wrote {len(written)} modules to {args.outdir} in {time.time() - start:.1f}s")
58
+ return 0