wineole 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.
wineole-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 firelzrd
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.
wineole-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,264 @@
1
+ Metadata-Version: 2.4
2
+ Name: wineole
3
+ Version: 0.1.0
4
+ Summary: Drive Win32OLE/COM automation of Wine-hosted Windows apps from Python
5
+ License-Expression: MIT
6
+ Project-URL: Homepage, https://github.com/firelzrd/wineole
7
+ Project-URL: Repository, https://github.com/firelzrd/wineole
8
+ Project-URL: Issues, https://github.com/firelzrd/wineole/issues
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Operating System :: POSIX :: Linux
12
+ Requires-Python: >=3.9
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Dynamic: license-file
16
+
17
+ # WineOLE
18
+
19
+ Drive Windows OLE/COM automation (Excel, Word, ...) from Linux, through Wine.
20
+ A small Windows-side bridge process (`wineole-bridge`) runs under `wine` and
21
+ speaks a JSON Lines RPC protocol to native Python and Ruby clients, so host
22
+ code can script a Windows application as if it were a local object.
23
+
24
+ ## Installation
25
+
26
+ Python:
27
+
28
+ ```
29
+ pip install wineole
30
+ ```
31
+
32
+ Ruby:
33
+
34
+ ```
35
+ gem install wineole
36
+ ```
37
+
38
+ Both packages bundle the prebuilt `wineole-bridge` binaries -- no separate
39
+ build step, and no Windows build of Python or Ruby is needed.
40
+
41
+ ## Usage
42
+
43
+ The quickest way to get started -- open the default bridge and create a
44
+ COM object in one call each:
45
+
46
+ Python:
47
+
48
+ ```python
49
+ import wineole
50
+
51
+ xl = wineole.create('Excel.Application')
52
+ xl.Visible = True
53
+ xl.Workbooks().Add()
54
+ xl.Worksheets()[1].Range('A1').Value = 'Hello from Python'
55
+ ```
56
+
57
+ Ruby:
58
+
59
+ ```ruby
60
+ require 'wineole'
61
+
62
+ xl = WineOLE.create('Excel.Application')
63
+ xl.Visible = true
64
+ xl.Workbooks.Add
65
+ xl.Worksheets[1].Range('A1').Value = 'Hello from Ruby'
66
+ ```
67
+
68
+ `WineOLE.create`/`wineole.create()` (create a new instance), `.connect`/
69
+ `connect()` (attach to an already-running instance, failing if none exists),
70
+ and `.connect_or_create`/`connect_or_create()` (attach if something's
71
+ running, otherwise create -- the classic VBScript `GetObject`-or-
72
+ `CreateObject` idiom) all lazily open a default bridge connection the first
73
+ time any of them is called, then reuse it -- no separate client variable
74
+ needed for the common case. `WineOLE.close`/`wineole.close()` releases that
75
+ implicit default early if you want to (otherwise it lives for the process's
76
+ lifetime).
77
+
78
+ For anything beyond the zero-config case -- a specific host/port, an auth
79
+ token, more than one bridge connection at once -- use `Client.open`
80
+ explicitly and create objects on it directly:
81
+
82
+ Python:
83
+
84
+ ```python
85
+ import wineole
86
+
87
+ client = wineole.Client.open()
88
+ xl = client.create('Excel.Application')
89
+
90
+ xl.Visible = True
91
+ xl.Workbooks().Add()
92
+ xl.Worksheets()[1].Range('A1').Value = 'Hello from Python'
93
+
94
+ client.close()
95
+ ```
96
+
97
+ Ruby:
98
+
99
+ ```ruby
100
+ require 'wineole'
101
+
102
+ client = WineOLE::Client.open
103
+ xl = client.create('Excel.Application')
104
+
105
+ xl.Visible = true
106
+ xl.Workbooks.Add
107
+ xl.Worksheets[1].Range('A1').Value = 'Hello from Ruby'
108
+
109
+ client.close
110
+ ```
111
+
112
+ `WineOLE.open`/`wineole.open()` sits between the two: it's `Client.open`
113
+ reachable without typing `Client`, and it *also* becomes the implicit
114
+ default, so a `WineOLE.create`/`wineole.create()` call right after uses the
115
+ client you just explicitly configured rather than a second, separate
116
+ zero-config one.
117
+
118
+ The two clients are otherwise near-identical in capability -- the extra `()`
119
+ in the Python version is the one real syntactic difference: Python's
120
+ `__getattr__` can't tell a property read from a method call apart the way
121
+ Ruby's `method_missing` can, so every COM member access returns a callable
122
+ that has to actually be called. See `bindings/ruby/examples/` and
123
+ `bindings/python/examples/` for a larger, visual demo of both.
124
+
125
+ ### Meta-methods and the `ole_` prefix
126
+
127
+ A `Proxy` forwards any name it doesn't recognize straight to the remote COM
128
+ object, so its own bookkeeping methods are named with an `ole_` prefix --
129
+ `ole_handle`, `ole_session_id`, `ole_release`, `ole_const_load`, and
130
+ `ole_created?`/`ole_created` (below) -- to keep them out of the way of a
131
+ real COM member that happens to share the plain name. `invoke` is the one
132
+ deliberate exception: it's kept bare and public as an explicit escape hatch
133
+ for the rare case where a COM object really does define a member called
134
+ e.g. `ole_handle` -- `proxy.invoke('ole_handle', [], {})` reaches it
135
+ directly, bypassing the local method entirely. This mirrors real Ruby
136
+ `WIN32OLE`'s own `ole_*`-prefixed introspection methods and its own bare,
137
+ public `invoke`.
138
+
139
+ `create`/`connect`/`connect_or_create` set `ole_created?`/`ole_created` on
140
+ the `Proxy` they return: `true`/`True` if a new instance was created,
141
+ `false`/`False` if an existing one was attached to, and `nil`/`None` for
142
+ any object derived from another (`xl.Worksheets`, `xl.Workbooks.Add`, ...)
143
+ -- attach-vs-create isn't a meaningful question for those. Handy for
144
+ deciding whether to `Quit` on the way out:
145
+
146
+ Python:
147
+
148
+ ```python
149
+ xl = wineole.connect_or_create('Excel.Application')
150
+ try:
151
+ ...
152
+ finally:
153
+ if xl.ole_created:
154
+ xl.Quit()
155
+ ```
156
+
157
+ Ruby:
158
+
159
+ ```ruby
160
+ xl = WineOLE.connect_or_create('Excel.Application')
161
+ begin
162
+ ...
163
+ ensure
164
+ xl.Quit if xl.ole_created?
165
+ end
166
+ ```
167
+
168
+ `Client.open`/`wineole`'s equivalents reuse an already-running bridge on the
169
+ given port, or spawn one and wait for it to come up -- either language's
170
+ client can talk to a bridge the other one started. `client.close()`/
171
+ `client.close` (or the implicit default's own eventual cleanup) releases the
172
+ session; the bridge automatically frees everything the connection owned (COM
173
+ objects included) once it sees the connection drop, and shuts down after 30
174
+ minutes of no active connections.
175
+
176
+ ## Remote bridges
177
+
178
+ `wineole-bridge` binds to `127.0.0.1` only by default, so it's unreachable
179
+ over the network unless you opt in. On the machine that will run the bridge:
180
+
181
+ ```
182
+ WINEOLE_BIND=0.0.0.0 WINEOLE_TOKEN=<a secret> wine wineole-bridge.exe 47800
183
+ ```
184
+
185
+ `WINEOLE_TOKEN` is optional but strongly recommended: without it, anything
186
+ that can reach that port can drive COM automation on that machine. The token
187
+ is only required from non-loopback connections, so this doesn't change
188
+ anything about local (`127.0.0.1`) use.
189
+
190
+ Then, from the client, pass `host:`/`host=` and `token:`/`token=` to
191
+ `Client.open`:
192
+
193
+ Python:
194
+
195
+ ```python
196
+ client = wineole.Client.open(host='192.168.1.50', port=47800, token='<a secret>')
197
+ ```
198
+
199
+ Ruby:
200
+
201
+ ```ruby
202
+ client = WineOLE::Client.open(host: '192.168.1.50', port: 47800, token: '<a secret>')
203
+ ```
204
+
205
+ `Client.open`'s auto-spawn fallback always launches the bridge on the
206
+ *local* machine -- it has no way to start one remotely. That's harmless when
207
+ the remote bridge is already running (the fast path just connects to it and
208
+ the spawn logic is never reached), but if it isn't running yet, the client
209
+ will spend the full `timeout` retrying a connection to a host nothing is
210
+ listening on yet, then raise, having pointlessly spawned a useless local
211
+ bridge in the meantime. Start the remote bridge yourself first, or pass a
212
+ `spawner:`/`spawner=` that raises instead of spawning locally, e.g.
213
+ `spawner: ->(port) { raise 'start the remote bridge manually' }`.
214
+
215
+ The wire protocol itself is plain, unencrypted TCP -- the token authenticates
216
+ but does not encrypt. Tunnel through SSH or a VPN if the network between the
217
+ client and the bridge isn't trusted.
218
+
219
+ ## Prebuilt binaries
220
+
221
+ Prebuilt `wineole-bridge` binaries are cross-compiled for three Windows
222
+ architectures:
223
+
224
+ - `x86_64-pc-windows-gnu` and `i686-pc-windows-gnu`, built with the widely
225
+ available `mingw-w64` toolchain (`apt install mingw-w64` on Debian/Ubuntu).
226
+ These are exercised by this project's real-Excel integration tests on every
227
+ change.
228
+ - `aarch64-pc-windows-gnullvm`, built with the
229
+ [`llvm-mingw`](https://github.com/mstorsjo/llvm-mingw) toolchain instead
230
+ (not packaged for apt — download a release tarball and put its `bin/` on
231
+ `PATH`; `wineole-bridge/.cargo/config.toml` points the target at
232
+ `aarch64-w64-mingw32-clang` from it). **This binary has never been run.**
233
+ This host (and every host this project has been developed on) has no way
234
+ to execute an ARM64 Windows binary at all -- Wine here only supports
235
+ x86/x86_64 execution, and there is no ARM64 CPU emulation layer (no
236
+ `qemu-user`, no ARM64 Wine build) to bridge that gap. The binary is a
237
+ structurally valid `PE32+ Aarch64` executable (verified with `file`) built
238
+ from the same source as the other two targets, but nothing about its
239
+ runtime correctness -- COM marshaling, struct layouts, calling conventions
240
+ under the ARM64 ABI -- has been verified. Treat it as unverified until
241
+ someone actually runs it on real ARM64 Wine.
242
+ It is also currently behind the other two: it predates the
243
+ `connect_or_create` RPC and will reject that call, so
244
+ `connect_or_create`/`ole_created?`/`ole_created` do not work on ARM64
245
+ until someone rebuilds it with `llvm-mingw` on `PATH`.
246
+
247
+ On an unsupported host architecture both clients raise an explicit "no
248
+ prebuilt wineole-bridge binary for host architecture" error listing what is
249
+ available.
250
+
251
+ ## Repository layout
252
+
253
+ `wineole-bridge/` is the shared Rust core: it builds the `wineole-bridge`
254
+ binaries and holds the prebuilt output in `wineole-bridge/dist/`. Each
255
+ language client lives in its own self-contained package directory under
256
+ `bindings/<lang>/` (`bindings/python/`, `bindings/ruby/`), so it can be built
257
+ and published independently. Because both RubyGems and setuptools reject
258
+ package file references that escape the package directory with `../`, each
259
+ binding instead contains a relative symlink back to `wineole-bridge/dist/`
260
+ (`bindings/python/wineole/dist` and `bindings/ruby/wineole-bridge-dist`) and
261
+ lists files through that symlink. These symlinks are load-bearing, not
262
+ decorative: if one is deleted or replaced with a real (empty) directory, the
263
+ gem or wheel will still build and install successfully, then fail at runtime
264
+ with no bridge binary present.
@@ -0,0 +1,248 @@
1
+ # WineOLE
2
+
3
+ Drive Windows OLE/COM automation (Excel, Word, ...) from Linux, through Wine.
4
+ A small Windows-side bridge process (`wineole-bridge`) runs under `wine` and
5
+ speaks a JSON Lines RPC protocol to native Python and Ruby clients, so host
6
+ code can script a Windows application as if it were a local object.
7
+
8
+ ## Installation
9
+
10
+ Python:
11
+
12
+ ```
13
+ pip install wineole
14
+ ```
15
+
16
+ Ruby:
17
+
18
+ ```
19
+ gem install wineole
20
+ ```
21
+
22
+ Both packages bundle the prebuilt `wineole-bridge` binaries -- no separate
23
+ build step, and no Windows build of Python or Ruby is needed.
24
+
25
+ ## Usage
26
+
27
+ The quickest way to get started -- open the default bridge and create a
28
+ COM object in one call each:
29
+
30
+ Python:
31
+
32
+ ```python
33
+ import wineole
34
+
35
+ xl = wineole.create('Excel.Application')
36
+ xl.Visible = True
37
+ xl.Workbooks().Add()
38
+ xl.Worksheets()[1].Range('A1').Value = 'Hello from Python'
39
+ ```
40
+
41
+ Ruby:
42
+
43
+ ```ruby
44
+ require 'wineole'
45
+
46
+ xl = WineOLE.create('Excel.Application')
47
+ xl.Visible = true
48
+ xl.Workbooks.Add
49
+ xl.Worksheets[1].Range('A1').Value = 'Hello from Ruby'
50
+ ```
51
+
52
+ `WineOLE.create`/`wineole.create()` (create a new instance), `.connect`/
53
+ `connect()` (attach to an already-running instance, failing if none exists),
54
+ and `.connect_or_create`/`connect_or_create()` (attach if something's
55
+ running, otherwise create -- the classic VBScript `GetObject`-or-
56
+ `CreateObject` idiom) all lazily open a default bridge connection the first
57
+ time any of them is called, then reuse it -- no separate client variable
58
+ needed for the common case. `WineOLE.close`/`wineole.close()` releases that
59
+ implicit default early if you want to (otherwise it lives for the process's
60
+ lifetime).
61
+
62
+ For anything beyond the zero-config case -- a specific host/port, an auth
63
+ token, more than one bridge connection at once -- use `Client.open`
64
+ explicitly and create objects on it directly:
65
+
66
+ Python:
67
+
68
+ ```python
69
+ import wineole
70
+
71
+ client = wineole.Client.open()
72
+ xl = client.create('Excel.Application')
73
+
74
+ xl.Visible = True
75
+ xl.Workbooks().Add()
76
+ xl.Worksheets()[1].Range('A1').Value = 'Hello from Python'
77
+
78
+ client.close()
79
+ ```
80
+
81
+ Ruby:
82
+
83
+ ```ruby
84
+ require 'wineole'
85
+
86
+ client = WineOLE::Client.open
87
+ xl = client.create('Excel.Application')
88
+
89
+ xl.Visible = true
90
+ xl.Workbooks.Add
91
+ xl.Worksheets[1].Range('A1').Value = 'Hello from Ruby'
92
+
93
+ client.close
94
+ ```
95
+
96
+ `WineOLE.open`/`wineole.open()` sits between the two: it's `Client.open`
97
+ reachable without typing `Client`, and it *also* becomes the implicit
98
+ default, so a `WineOLE.create`/`wineole.create()` call right after uses the
99
+ client you just explicitly configured rather than a second, separate
100
+ zero-config one.
101
+
102
+ The two clients are otherwise near-identical in capability -- the extra `()`
103
+ in the Python version is the one real syntactic difference: Python's
104
+ `__getattr__` can't tell a property read from a method call apart the way
105
+ Ruby's `method_missing` can, so every COM member access returns a callable
106
+ that has to actually be called. See `bindings/ruby/examples/` and
107
+ `bindings/python/examples/` for a larger, visual demo of both.
108
+
109
+ ### Meta-methods and the `ole_` prefix
110
+
111
+ A `Proxy` forwards any name it doesn't recognize straight to the remote COM
112
+ object, so its own bookkeeping methods are named with an `ole_` prefix --
113
+ `ole_handle`, `ole_session_id`, `ole_release`, `ole_const_load`, and
114
+ `ole_created?`/`ole_created` (below) -- to keep them out of the way of a
115
+ real COM member that happens to share the plain name. `invoke` is the one
116
+ deliberate exception: it's kept bare and public as an explicit escape hatch
117
+ for the rare case where a COM object really does define a member called
118
+ e.g. `ole_handle` -- `proxy.invoke('ole_handle', [], {})` reaches it
119
+ directly, bypassing the local method entirely. This mirrors real Ruby
120
+ `WIN32OLE`'s own `ole_*`-prefixed introspection methods and its own bare,
121
+ public `invoke`.
122
+
123
+ `create`/`connect`/`connect_or_create` set `ole_created?`/`ole_created` on
124
+ the `Proxy` they return: `true`/`True` if a new instance was created,
125
+ `false`/`False` if an existing one was attached to, and `nil`/`None` for
126
+ any object derived from another (`xl.Worksheets`, `xl.Workbooks.Add`, ...)
127
+ -- attach-vs-create isn't a meaningful question for those. Handy for
128
+ deciding whether to `Quit` on the way out:
129
+
130
+ Python:
131
+
132
+ ```python
133
+ xl = wineole.connect_or_create('Excel.Application')
134
+ try:
135
+ ...
136
+ finally:
137
+ if xl.ole_created:
138
+ xl.Quit()
139
+ ```
140
+
141
+ Ruby:
142
+
143
+ ```ruby
144
+ xl = WineOLE.connect_or_create('Excel.Application')
145
+ begin
146
+ ...
147
+ ensure
148
+ xl.Quit if xl.ole_created?
149
+ end
150
+ ```
151
+
152
+ `Client.open`/`wineole`'s equivalents reuse an already-running bridge on the
153
+ given port, or spawn one and wait for it to come up -- either language's
154
+ client can talk to a bridge the other one started. `client.close()`/
155
+ `client.close` (or the implicit default's own eventual cleanup) releases the
156
+ session; the bridge automatically frees everything the connection owned (COM
157
+ objects included) once it sees the connection drop, and shuts down after 30
158
+ minutes of no active connections.
159
+
160
+ ## Remote bridges
161
+
162
+ `wineole-bridge` binds to `127.0.0.1` only by default, so it's unreachable
163
+ over the network unless you opt in. On the machine that will run the bridge:
164
+
165
+ ```
166
+ WINEOLE_BIND=0.0.0.0 WINEOLE_TOKEN=<a secret> wine wineole-bridge.exe 47800
167
+ ```
168
+
169
+ `WINEOLE_TOKEN` is optional but strongly recommended: without it, anything
170
+ that can reach that port can drive COM automation on that machine. The token
171
+ is only required from non-loopback connections, so this doesn't change
172
+ anything about local (`127.0.0.1`) use.
173
+
174
+ Then, from the client, pass `host:`/`host=` and `token:`/`token=` to
175
+ `Client.open`:
176
+
177
+ Python:
178
+
179
+ ```python
180
+ client = wineole.Client.open(host='192.168.1.50', port=47800, token='<a secret>')
181
+ ```
182
+
183
+ Ruby:
184
+
185
+ ```ruby
186
+ client = WineOLE::Client.open(host: '192.168.1.50', port: 47800, token: '<a secret>')
187
+ ```
188
+
189
+ `Client.open`'s auto-spawn fallback always launches the bridge on the
190
+ *local* machine -- it has no way to start one remotely. That's harmless when
191
+ the remote bridge is already running (the fast path just connects to it and
192
+ the spawn logic is never reached), but if it isn't running yet, the client
193
+ will spend the full `timeout` retrying a connection to a host nothing is
194
+ listening on yet, then raise, having pointlessly spawned a useless local
195
+ bridge in the meantime. Start the remote bridge yourself first, or pass a
196
+ `spawner:`/`spawner=` that raises instead of spawning locally, e.g.
197
+ `spawner: ->(port) { raise 'start the remote bridge manually' }`.
198
+
199
+ The wire protocol itself is plain, unencrypted TCP -- the token authenticates
200
+ but does not encrypt. Tunnel through SSH or a VPN if the network between the
201
+ client and the bridge isn't trusted.
202
+
203
+ ## Prebuilt binaries
204
+
205
+ Prebuilt `wineole-bridge` binaries are cross-compiled for three Windows
206
+ architectures:
207
+
208
+ - `x86_64-pc-windows-gnu` and `i686-pc-windows-gnu`, built with the widely
209
+ available `mingw-w64` toolchain (`apt install mingw-w64` on Debian/Ubuntu).
210
+ These are exercised by this project's real-Excel integration tests on every
211
+ change.
212
+ - `aarch64-pc-windows-gnullvm`, built with the
213
+ [`llvm-mingw`](https://github.com/mstorsjo/llvm-mingw) toolchain instead
214
+ (not packaged for apt — download a release tarball and put its `bin/` on
215
+ `PATH`; `wineole-bridge/.cargo/config.toml` points the target at
216
+ `aarch64-w64-mingw32-clang` from it). **This binary has never been run.**
217
+ This host (and every host this project has been developed on) has no way
218
+ to execute an ARM64 Windows binary at all -- Wine here only supports
219
+ x86/x86_64 execution, and there is no ARM64 CPU emulation layer (no
220
+ `qemu-user`, no ARM64 Wine build) to bridge that gap. The binary is a
221
+ structurally valid `PE32+ Aarch64` executable (verified with `file`) built
222
+ from the same source as the other two targets, but nothing about its
223
+ runtime correctness -- COM marshaling, struct layouts, calling conventions
224
+ under the ARM64 ABI -- has been verified. Treat it as unverified until
225
+ someone actually runs it on real ARM64 Wine.
226
+ It is also currently behind the other two: it predates the
227
+ `connect_or_create` RPC and will reject that call, so
228
+ `connect_or_create`/`ole_created?`/`ole_created` do not work on ARM64
229
+ until someone rebuilds it with `llvm-mingw` on `PATH`.
230
+
231
+ On an unsupported host architecture both clients raise an explicit "no
232
+ prebuilt wineole-bridge binary for host architecture" error listing what is
233
+ available.
234
+
235
+ ## Repository layout
236
+
237
+ `wineole-bridge/` is the shared Rust core: it builds the `wineole-bridge`
238
+ binaries and holds the prebuilt output in `wineole-bridge/dist/`. Each
239
+ language client lives in its own self-contained package directory under
240
+ `bindings/<lang>/` (`bindings/python/`, `bindings/ruby/`), so it can be built
241
+ and published independently. Because both RubyGems and setuptools reject
242
+ package file references that escape the package directory with `../`, each
243
+ binding instead contains a relative symlink back to `wineole-bridge/dist/`
244
+ (`bindings/python/wineole/dist` and `bindings/ruby/wineole-bridge-dist`) and
245
+ lists files through that symlink. These symlinks are load-bearing, not
246
+ decorative: if one is deleted or replaced with a real (empty) directory, the
247
+ gem or wheel will still build and install successfully, then fail at runtime
248
+ with no bridge binary present.
@@ -0,0 +1,25 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "wineole"
7
+ version = "0.1.0"
8
+ description = "Drive Win32OLE/COM automation of Wine-hosted Windows apps from Python"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ classifiers = [
14
+ "Development Status :: 3 - Alpha",
15
+ "Programming Language :: Python :: 3",
16
+ "Operating System :: POSIX :: Linux",
17
+ ]
18
+
19
+ [project.urls]
20
+ Homepage = "https://github.com/firelzrd/wineole"
21
+ Repository = "https://github.com/firelzrd/wineole"
22
+ Issues = "https://github.com/firelzrd/wineole/issues"
23
+
24
+ [tool.setuptools.package-data]
25
+ wineole = ["dist/**/*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+