quickmacapp 2023.2.21__tar.gz → 2023.4.24__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.
- {quickmacapp-2023.2.21 → quickmacapp-2023.4.24}/LICENSE +3 -2
- {quickmacapp-2023.2.21 → quickmacapp-2023.4.24}/PKG-INFO +9 -6
- {quickmacapp-2023.2.21 → quickmacapp-2023.4.24}/README.rst +8 -5
- {quickmacapp-2023.2.21 → quickmacapp-2023.4.24}/pyproject.toml +1 -1
- {quickmacapp-2023.2.21 → quickmacapp-2023.4.24}/src/quickmacapp/__init__.py +4 -0
- quickmacapp-2023.4.24/src/quickmacapp/_interactions.py +107 -0
- {quickmacapp-2023.2.21 → quickmacapp-2023.4.24}/src/quickmacapp/_quickapp.py +1 -1
- {quickmacapp-2023.2.21 → quickmacapp-2023.4.24}/src/quickmacapp.egg-info/PKG-INFO +9 -6
- {quickmacapp-2023.2.21 → quickmacapp-2023.4.24}/src/quickmacapp.egg-info/SOURCES.txt +1 -0
- {quickmacapp-2023.2.21 → quickmacapp-2023.4.24}/setup.cfg +0 -0
- {quickmacapp-2023.2.21 → quickmacapp-2023.4.24}/src/quickmacapp/py.typed +0 -0
- {quickmacapp-2023.2.21 → quickmacapp-2023.4.24}/src/quickmacapp.egg-info/dependency_links.txt +0 -0
- {quickmacapp-2023.2.21 → quickmacapp-2023.4.24}/src/quickmacapp.egg-info/requires.txt +0 -0
- {quickmacapp-2023.2.21 → quickmacapp-2023.4.24}/src/quickmacapp.egg-info/top_level.txt +0 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright
|
|
4
|
-
|
|
3
|
+
Copyright
|
|
4
|
+
(c) 2023 Glyph
|
|
5
|
+
(c) 2023 Palo Alto Networks
|
|
5
6
|
|
|
6
7
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
8
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: quickmacapp
|
|
3
|
-
Version: 2023.
|
|
3
|
+
Version: 2023.4.24
|
|
4
4
|
Summary: Make it easier to write Mac apps in Python
|
|
5
5
|
Description-Content-Type: text/x-rst
|
|
6
6
|
License-File: LICENSE
|
|
@@ -15,19 +15,22 @@ QuickMacApp
|
|
|
15
15
|
rapidly and if you want to use this to ship an app you probably will want
|
|
16
16
|
to contribute to it as well.
|
|
17
17
|
|
|
18
|
-
Make it easier to write small applications for macOS
|
|
18
|
+
Make it easier to write small applications for macOS in Python, using Twisted.
|
|
19
19
|
|
|
20
20
|
To get a very basic status menu API:
|
|
21
21
|
|
|
22
22
|
.. code::
|
|
23
23
|
python
|
|
24
24
|
|
|
25
|
-
from quickmacapp import mainpoint, Status, quit
|
|
25
|
+
from quickmacapp import mainpoint, Status, answer, quit
|
|
26
|
+
from twisted.internet.defer import Deferred
|
|
26
27
|
|
|
27
28
|
@mainpoint()
|
|
28
|
-
def app(reactor
|
|
29
|
-
Status("☀️ 💣")
|
|
30
|
-
|
|
29
|
+
def app(reactor):
|
|
30
|
+
s = Status("☀️ 💣")
|
|
31
|
+
s.menu([("Do Something", lambda: Deferred.fromCoroutine(answer("something"))),
|
|
32
|
+
("Quit", quit)])
|
|
33
|
+
app.runMain()
|
|
31
34
|
|
|
32
35
|
Packaging this into a working app bundle is currently left as an exercise for
|
|
33
36
|
the reader.
|
|
@@ -8,19 +8,22 @@ QuickMacApp
|
|
|
8
8
|
rapidly and if you want to use this to ship an app you probably will want
|
|
9
9
|
to contribute to it as well.
|
|
10
10
|
|
|
11
|
-
Make it easier to write small applications for macOS
|
|
11
|
+
Make it easier to write small applications for macOS in Python, using Twisted.
|
|
12
12
|
|
|
13
13
|
To get a very basic status menu API:
|
|
14
14
|
|
|
15
15
|
.. code::
|
|
16
16
|
python
|
|
17
17
|
|
|
18
|
-
from quickmacapp import mainpoint, Status, quit
|
|
18
|
+
from quickmacapp import mainpoint, Status, answer, quit
|
|
19
|
+
from twisted.internet.defer import Deferred
|
|
19
20
|
|
|
20
21
|
@mainpoint()
|
|
21
|
-
def app(reactor
|
|
22
|
-
Status("☀️ 💣")
|
|
23
|
-
|
|
22
|
+
def app(reactor):
|
|
23
|
+
s = Status("☀️ 💣")
|
|
24
|
+
s.menu([("Do Something", lambda: Deferred.fromCoroutine(answer("something"))),
|
|
25
|
+
("Quit", quit)])
|
|
26
|
+
app.runMain()
|
|
24
27
|
|
|
25
28
|
Packaging this into a working app bundle is currently left as an exercise for
|
|
26
29
|
the reader.
|
|
@@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta"
|
|
|
9
9
|
name = "quickmacapp"
|
|
10
10
|
description = "Make it easier to write Mac apps in Python"
|
|
11
11
|
readme = "README.rst"
|
|
12
|
-
version = "2023.
|
|
12
|
+
version = "2023.04.24"
|
|
13
13
|
dependencies = [
|
|
14
14
|
"pyobjc-framework-Cocoa",
|
|
15
15
|
"pyobjc-framework-ExceptionHandling",
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
from typing import Iterable, Iterator, TypeVar
|
|
2
|
+
|
|
3
|
+
from AppKit import (
|
|
4
|
+
NSAlertFirstButtonReturn,
|
|
5
|
+
NSAlertSecondButtonReturn,
|
|
6
|
+
NSAlertThirdButtonReturn,
|
|
7
|
+
NSAlert,
|
|
8
|
+
NSApp,
|
|
9
|
+
)
|
|
10
|
+
from Foundation import (
|
|
11
|
+
NSRunLoop,
|
|
12
|
+
NSTextField,
|
|
13
|
+
NSRect,
|
|
14
|
+
)
|
|
15
|
+
from twisted.internet.defer import Deferred
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
NSModalResponse = int
|
|
19
|
+
T = TypeVar("T")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def asyncModal(alert: NSAlert) -> Deferred[NSModalResponse]:
|
|
23
|
+
"""
|
|
24
|
+
Run an NSAlert asynchronously.
|
|
25
|
+
"""
|
|
26
|
+
d: Deferred[NSModalResponse] = Deferred()
|
|
27
|
+
|
|
28
|
+
def runAndReport() -> None:
|
|
29
|
+
try:
|
|
30
|
+
NSApp().activateIgnoringOtherApps_(True)
|
|
31
|
+
result = alert.runModal()
|
|
32
|
+
except:
|
|
33
|
+
d.errback()
|
|
34
|
+
else:
|
|
35
|
+
d.callback(result)
|
|
36
|
+
|
|
37
|
+
NSRunLoop.currentRunLoop().performBlock_(runAndReport)
|
|
38
|
+
return d
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _alertReturns() -> Iterator[NSModalResponse]:
|
|
42
|
+
"""
|
|
43
|
+
Enumerate the values used by NSAlert for return values in the order of the
|
|
44
|
+
buttons that occur.
|
|
45
|
+
"""
|
|
46
|
+
yield NSAlertFirstButtonReturn
|
|
47
|
+
yield NSAlertSecondButtonReturn
|
|
48
|
+
yield NSAlertThirdButtonReturn
|
|
49
|
+
i = 1
|
|
50
|
+
while True:
|
|
51
|
+
yield NSAlertThirdButtonReturn + i
|
|
52
|
+
i += 1
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
async def choose(values: Iterable[tuple[T, str]], question: str, description: str="") -> T:
|
|
56
|
+
"""
|
|
57
|
+
Prompt the user to choose between the given values, on buttons labeled in
|
|
58
|
+
the given way.
|
|
59
|
+
"""
|
|
60
|
+
msg = NSAlert.alloc().init()
|
|
61
|
+
msg.setMessageText_(question)
|
|
62
|
+
msg.setInformativeText_(description)
|
|
63
|
+
potentialResults = {}
|
|
64
|
+
for (value, label), alertReturn in zip(values, _alertReturns()):
|
|
65
|
+
msg.addButtonWithTitle_(label)
|
|
66
|
+
potentialResults[alertReturn] = value
|
|
67
|
+
msg.layout()
|
|
68
|
+
return potentialResults[await asyncModal(msg)]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
async def ask(question: str, description: str="", defaultValue: str="") -> str | None:
|
|
72
|
+
"""
|
|
73
|
+
Prompt the user for a short string of text.
|
|
74
|
+
"""
|
|
75
|
+
msg = NSAlert.alloc().init()
|
|
76
|
+
msg.addButtonWithTitle_("OK")
|
|
77
|
+
msg.addButtonWithTitle_("Cancel")
|
|
78
|
+
msg.setMessageText_(question)
|
|
79
|
+
msg.setInformativeText_(description)
|
|
80
|
+
|
|
81
|
+
txt = NSTextField.alloc().initWithFrame_(NSRect((0, 0), (200, 100)))
|
|
82
|
+
txt.setMaximumNumberOfLines_(5)
|
|
83
|
+
txt.setStringValue_(defaultValue)
|
|
84
|
+
msg.setAccessoryView_(txt)
|
|
85
|
+
msg.window().setInitialFirstResponder_(txt)
|
|
86
|
+
msg.layout()
|
|
87
|
+
|
|
88
|
+
response: NSModalResponse = await asyncModal(msg)
|
|
89
|
+
|
|
90
|
+
if response == NSAlertFirstButtonReturn:
|
|
91
|
+
result: str = txt.stringValue()
|
|
92
|
+
return result
|
|
93
|
+
|
|
94
|
+
return None
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
async def answer(message: str, description: str="") -> None:
|
|
98
|
+
"""
|
|
99
|
+
Give the user a message.
|
|
100
|
+
"""
|
|
101
|
+
msg = NSAlert.alloc().init()
|
|
102
|
+
msg.setMessageText_(message)
|
|
103
|
+
msg.setInformativeText_(description)
|
|
104
|
+
# msg.addButtonWithTitle("OK")
|
|
105
|
+
msg.layout()
|
|
106
|
+
|
|
107
|
+
await asyncModal(msg)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: quickmacapp
|
|
3
|
-
Version: 2023.
|
|
3
|
+
Version: 2023.4.24
|
|
4
4
|
Summary: Make it easier to write Mac apps in Python
|
|
5
5
|
Description-Content-Type: text/x-rst
|
|
6
6
|
License-File: LICENSE
|
|
@@ -15,19 +15,22 @@ QuickMacApp
|
|
|
15
15
|
rapidly and if you want to use this to ship an app you probably will want
|
|
16
16
|
to contribute to it as well.
|
|
17
17
|
|
|
18
|
-
Make it easier to write small applications for macOS
|
|
18
|
+
Make it easier to write small applications for macOS in Python, using Twisted.
|
|
19
19
|
|
|
20
20
|
To get a very basic status menu API:
|
|
21
21
|
|
|
22
22
|
.. code::
|
|
23
23
|
python
|
|
24
24
|
|
|
25
|
-
from quickmacapp import mainpoint, Status, quit
|
|
25
|
+
from quickmacapp import mainpoint, Status, answer, quit
|
|
26
|
+
from twisted.internet.defer import Deferred
|
|
26
27
|
|
|
27
28
|
@mainpoint()
|
|
28
|
-
def app(reactor
|
|
29
|
-
Status("☀️ 💣")
|
|
30
|
-
|
|
29
|
+
def app(reactor):
|
|
30
|
+
s = Status("☀️ 💣")
|
|
31
|
+
s.menu([("Do Something", lambda: Deferred.fromCoroutine(answer("something"))),
|
|
32
|
+
("Quit", quit)])
|
|
33
|
+
app.runMain()
|
|
31
34
|
|
|
32
35
|
Packaging this into a working app bundle is currently left as an exercise for
|
|
33
36
|
the reader.
|
|
File without changes
|
|
File without changes
|
{quickmacapp-2023.2.21 → quickmacapp-2023.4.24}/src/quickmacapp.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|