speechlight 2.0.2__tar.gz → 3.0.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.
Files changed (23) hide show
  1. {speechlight-2.0.2 → speechlight-3.0.0}/PKG-INFO +5 -5
  2. {speechlight-2.0.2 → speechlight-3.0.0}/pyproject.toml +5 -5
  3. speechlight-3.0.0/src/speechlight/_version.py +1 -0
  4. {speechlight-2.0.2 → speechlight-3.0.0}/src/speechlight/windows.py +49 -8
  5. speechlight-3.0.0/uv.lock +3641 -0
  6. speechlight-2.0.2/src/speechlight/_version.py +0 -1
  7. speechlight-2.0.2/uv.lock +0 -3441
  8. {speechlight-2.0.2 → speechlight-3.0.0}/LICENSE.txt +0 -0
  9. {speechlight-2.0.2 → speechlight-3.0.0}/README.md +0 -0
  10. {speechlight-2.0.2 → speechlight-3.0.0}/src/speechlight/__init__.py +0 -0
  11. {speechlight-2.0.2 → speechlight-3.0.0}/src/speechlight/base.py +0 -0
  12. {speechlight-2.0.2 → speechlight-3.0.0}/src/speechlight/darwin.py +0 -0
  13. {speechlight-2.0.2 → speechlight-3.0.0}/src/speechlight/dummy.py +0 -0
  14. {speechlight-2.0.2 → speechlight-3.0.0}/src/speechlight/py.typed +0 -0
  15. {speechlight-2.0.2 → speechlight-3.0.0}/src/speechlight/speech_libs/SAAPI32.dll +0 -0
  16. {speechlight-2.0.2 → speechlight-3.0.0}/src/speechlight/speech_libs/SAAPI64.dll +0 -0
  17. {speechlight-2.0.2 → speechlight-3.0.0}/src/speechlight/speech_libs/nvdaControllerClient32.dll +0 -0
  18. {speechlight-2.0.2 → speechlight-3.0.0}/src/speechlight/speech_libs/nvdaControllerClient64.dll +0 -0
  19. {speechlight-2.0.2 → speechlight-3.0.0}/tests/__init__.py +0 -0
  20. {speechlight-2.0.2 → speechlight-3.0.0}/tests/speechlight/__init__.py +0 -0
  21. {speechlight-2.0.2 → speechlight-3.0.0}/tests/speechlight/test_darwin.py +0 -0
  22. {speechlight-2.0.2 → speechlight-3.0.0}/tests/speechlight/test_dummy.py +0 -0
  23. {speechlight-2.0.2 → speechlight-3.0.0}/tests/speechlight/test_windows.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: speechlight
3
- Version: 2.0.2
3
+ Version: 3.0.0
4
4
  Summary: A lightweight Python library providing a common interface to multiple TTS and screen reader APIs.
5
5
  Keywords: blind,braille,screen reader,tts,speech,accessibility,jaws,nvda,sapi,system access
6
6
  Author-Email: Nick Stockton <nstockton@users.noreply.github.com>
@@ -11,11 +11,11 @@ Classifier: License :: OSI Approved :: MIT License
11
11
  Classifier: Programming Language :: Python
12
12
  Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Programming Language :: Python :: 3 :: Only
14
- Classifier: Programming Language :: Python :: 3.9
15
14
  Classifier: Programming Language :: Python :: 3.10
16
15
  Classifier: Programming Language :: Python :: 3.11
17
16
  Classifier: Programming Language :: Python :: 3.12
18
17
  Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
19
  Classifier: Programming Language :: Python :: Implementation
20
20
  Classifier: Programming Language :: Python :: Implementation :: CPython
21
21
  Classifier: Operating System :: MacOS
@@ -34,10 +34,10 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
34
34
  Project-URL: homepage, https://github.com/nstockton/speechlight
35
35
  Project-URL: repository, https://github.com/nstockton/speechlight
36
36
  Project-URL: documentation, https://nstockton.github.io/speechlight
37
- Requires-Python: <4.0,>=3.9
37
+ Requires-Python: <4.0,>=3.10
38
38
  Requires-Dist: knickknacks<1.0.0,>=0.6.0
39
- Requires-Dist: pyobjc<11.0,>=10.0; sys_platform == "darwin"
40
- Requires-Dist: pywin32<400,>=306; sys_platform == "win32"
39
+ Requires-Dist: pyobjc<13.0,>=12.0; sys_platform == "darwin"
40
+ Requires-Dist: pywin32<400,>=311; sys_platform == "win32"
41
41
  Description-Content-Type: text/markdown
42
42
 
43
43
  # Speechlight
@@ -11,11 +11,11 @@ authors = [
11
11
  ]
12
12
  description = "A lightweight Python library providing a common interface to multiple TTS and screen reader APIs."
13
13
  readme = "README.md"
14
- requires-python = ">=3.9,<4.0"
14
+ requires-python = ">=3.10,<4.0"
15
15
  dependencies = [
16
16
  "knickknacks>=0.6.0,<1.0.0",
17
- "pyobjc>=10.0,<11.0; sys_platform == \"darwin\"",
18
- "pywin32>=306,<400; sys_platform == \"win32\"",
17
+ "pyobjc>=12.0,<13.0; sys_platform == \"darwin\"",
18
+ "pywin32>=311,<400; sys_platform == \"win32\"",
19
19
  ]
20
20
  dynamic = []
21
21
  keywords = [
@@ -37,11 +37,11 @@ classifiers = [
37
37
  "Programming Language :: Python",
38
38
  "Programming Language :: Python :: 3",
39
39
  "Programming Language :: Python :: 3 :: Only",
40
- "Programming Language :: Python :: 3.9",
41
40
  "Programming Language :: Python :: 3.10",
42
41
  "Programming Language :: Python :: 3.11",
43
42
  "Programming Language :: Python :: 3.12",
44
43
  "Programming Language :: Python :: 3.13",
44
+ "Programming Language :: Python :: 3.14",
45
45
  "Programming Language :: Python :: Implementation",
46
46
  "Programming Language :: Python :: Implementation :: CPython",
47
47
  "Operating System :: MacOS",
@@ -58,7 +58,7 @@ classifiers = [
58
58
  "Topic :: Software Development :: Libraries",
59
59
  "Topic :: Software Development :: Libraries :: Python Modules",
60
60
  ]
61
- version = "2.0.2"
61
+ version = "3.0.0"
62
62
 
63
63
  [project.license]
64
64
  text = "MIT"
@@ -0,0 +1 @@
1
+ __version__: str = "3.0.0"
@@ -25,8 +25,9 @@ from __future__ import annotations
25
25
 
26
26
  # Built-in Modules:
27
27
  import ctypes
28
+ import re
29
+ import shutil
28
30
  import sys
29
- from contextlib import suppress
30
31
  from typing import Any, Optional
31
32
 
32
33
  # Local Modules:
@@ -35,7 +36,6 @@ from .base import BaseSpeech
35
36
 
36
37
 
37
38
  if sys.platform == "win32": # pragma: no cover
38
- import win32com.client
39
39
  from pywintypes import com_error as ComError # NOQA: N812
40
40
 
41
41
 
@@ -45,6 +45,51 @@ SPF_PURGE_BEFORE_SPEAK: int = 2 # Purges all pending speak requests prior to th
45
45
  SPF_IS_NOT_XML: int = 16 # The input text will not be parsed for XML markup.
46
46
 
47
47
 
48
+ def dispatch(*args: Any, **kwargs: Any) -> Any: # pragma: no cover
49
+ """
50
+ Calls win32com.client.Dispatch with the supplied arguments.
51
+
52
+ If the call fails, then an attempt is made to clear the cache and try again.
53
+
54
+ Note:
55
+ https://stackoverflow.com/questions/33267002/why-am-i-suddenly-getting-a-no-attribute-clsidtopackagemap-error-with-win32com
56
+
57
+ Args:
58
+ *args: Positional arguments to be passed to win32com.client.Dispatch.
59
+ **kwargs: Key-word only arguments to be passed to win32com.client.Dispatch.
60
+
61
+ Returns:
62
+ The resulting COM reference.
63
+ """
64
+ app = None
65
+ if sys.platform == "win32":
66
+ try:
67
+ from win32com import client # NOQA: PLC0415
68
+
69
+ app = client.Dispatch(*args, **kwargs)
70
+ except AttributeError:
71
+ # Remove cache and try again.
72
+ from win32com.client import gencache # NOQA: PLC0415
73
+
74
+ if not hasattr(gencache, "GetGeneratePath"):
75
+ return None
76
+ cache_location = gencache.GetGeneratePath()
77
+ del gencache
78
+ modules = [m.__name__ for m in sys.modules.values()]
79
+ for module in modules:
80
+ if re.match(r"win32com\.(?:gen_py|client)\..+", module):
81
+ del sys.modules[module]
82
+ if "gen_py" in cache_location:
83
+ shutil.rmtree(cache_location, ignore_errors=True)
84
+ from win32com import client # NOQA: PLC0415
85
+
86
+ app = client.Dispatch(*args, **kwargs)
87
+ except ComError:
88
+ return None
89
+ del client
90
+ return app
91
+
92
+
48
93
  class Speech(BaseSpeech): # NOQA: PLR0904
49
94
  """Implements Speech for Windows."""
50
95
 
@@ -73,17 +118,13 @@ class Speech(BaseSpeech): # NOQA: PLR0904
73
118
  @property
74
119
  def sapi(self) -> Any: # type: ignore[misc] # pragma: no cover
75
120
  """The SAPI COM object."""
76
- if sys.platform == "win32":
77
- with suppress(ComError):
78
- self._sapi = win32com.client.Dispatch("SAPI.SpVoice")
121
+ self._sapi = dispatch("SAPI.SpVoice")
79
122
  return self._sapi
80
123
 
81
124
  @property
82
125
  def jfw(self) -> Any: # type: ignore[misc] # pragma: no cover
83
126
  """The JFW COM object."""
84
- if sys.platform == "win32":
85
- with suppress(ComError):
86
- self._jfw = win32com.client.Dispatch("FreedomSci.JawsApi")
127
+ self._jfw = dispatch("FreedomSci.JawsApi")
87
128
  return self._jfw
88
129
 
89
130
  def jfw_braille(self, text: str) -> None: