Skip to content

Commit

Permalink
add better support for freezing
Browse files Browse the repository at this point in the history
  • Loading branch information
spyoungtech committed Jan 12, 2023
1 parent bc5895b commit 1da2609
Show file tree
Hide file tree
Showing 8 changed files with 2,458 additions and 19 deletions.
7 changes: 7 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ repos:
- unasync
- tokenize_rt
- black
- id: set-constants
name: set-constants
entry: python _set_constants.py
language: python
types: [python]
pass_filenames: false
files: ^(ahk/daemon\.ahk|ahk/_constants\.py)

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
Expand Down
31 changes: 31 additions & 0 deletions _set_constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import shutil
import subprocess
import sys

with open('ahk/daemon.ahk') as f:
daemon_script = f.read()

GIT_EXECUTABLE = shutil.which('git')

if not GIT_EXECUTABLE:
raise RuntimeError('git executable not found')

new_contents = f'''\
# THIS FILE IS AUTOGENERATED BY _set_constants.py
# DO NOT EDIT BY HAND
DAEMON_SCRIPT = r"""{daemon_script}
"""
'''

with open('ahk/_constants.py', encoding='utf-8') as f:
constants_text = f.read()

if constants_text != new_contents:
with open('ahk/_constants.py', 'w', encoding='utf-8') as f:
f.write(new_contents)
print('MODIFIED _constants.py', file=sys.stderr)
subprocess.run([GIT_EXECUTABLE, 'add', '--intent-to-add', 'ahk/_constants.py'])
raise SystemExit(1)
else:
raise SystemExit(0)
7 changes: 5 additions & 2 deletions ahk/_async/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,8 @@ async def key_state(
if mode not in ('T', 'P'):
raise ValueError(f'Invalid value for mode parameter. Mode must be `T` or `P`. Got {mode!r}')
args.append(mode)
return await self._transport.function_call('AHKKeyState', args, blocking=blocking)
resp = await self._transport.function_call('AHKKeyState', args, blocking=blocking)
return resp

# fmt: off
@overload
Expand Down Expand Up @@ -1108,7 +1109,9 @@ async def set_capslock_state(
f'Invalid value for state. Must be one of On, Off, AlwaysOn, AlwaysOff or None. Got {state!r}'
)
args.append(str(state))
return await self._transport.function_call('AHKSetCapsLockState', args, blocking=blocking)

resp = await self._transport.function_call('AHKSetCapsLockState', args, blocking=blocking)
return resp

async def set_volume(self, value: int, device_number: int = 1) -> None:
raise NotImplementedError()
Expand Down
39 changes: 34 additions & 5 deletions ahk/_async/transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import os
import subprocess
import sys
import tempfile
import warnings
from abc import ABC
from abc import abstractmethod
Expand Down Expand Up @@ -37,6 +38,7 @@
from ahk.message import RequestMessage
from ahk.message import ResponseMessage
from ahk.message import Position
from ahk._constants import DAEMON_SCRIPT as _DAEMON_SCRIPT

from concurrent.futures import Future, ThreadPoolExecutor

Expand Down Expand Up @@ -483,7 +485,11 @@ async def function_call(
engine: Optional[AsyncAHK] = None,
) -> Any:
if not self._started:
await self.init()
with warnings.catch_warnings(record=True) as caught_warnings:
await self.init()
if caught_warnings:
for warning in caught_warnings:
warnings.warn(warning.message, warning.category, stacklevel=3)
request = RequestMessage(function_name=function_name, args=args)
if blocking:
return await self.send(request, engine=engine)
Expand Down Expand Up @@ -515,6 +521,7 @@ class AsyncDaemonProcessTransport(AsyncTransport):
def __init__(self, *, executable_path: Union[str, os.PathLike[AnyStr]] = ''):
self._proc: Optional[AsyncAHKProcess]
self._proc = None
self._temp_script: Optional[str] = None
super().__init__(executable_path=executable_path)

async def init(self) -> None:
Expand All @@ -524,13 +531,35 @@ async def init(self) -> None:

async def start(self) -> None:
assert self._proc is None, 'cannot start a process twice'
daemon_script = os.path.abspath(os.path.join(os.path.dirname(__file__), '../daemon.ahk'))
runargs = [self._executable_path, '/CP65001', '/ErrorStdOut', daemon_script]
self._proc = AsyncAHKProcess(runargs=runargs)
await self._proc.start()
with warnings.catch_warnings(record=True) as caught_warnings:
self._proc = await self._create_process()
if caught_warnings:
for warning in caught_warnings:
warnings.warn(warning.message, warning.category, stacklevel=2)

async def _create_process(self) -> AsyncAHKProcess:
daemon_script = os.path.abspath(os.path.join(os.path.dirname(__file__), '../daemon.ahk'))
if not os.path.exists(daemon_script):
if self._temp_script is None or not os.path.exists(self._temp_script):
warnings.warn(
'daemon script not found. This is typically the result of a error in attempting to '
'repackage/redistribute `ahk` without including its package data. Will attempt to run '
'daemon script from tempfile, but this action may be blocked by some security tools. '
'To fix this warning, make sure to include package data when bundling applications that '
'depend on `ahk`',
category=UserWarning,
stacklevel=2,
)

with tempfile.NamedTemporaryFile(
mode='w', prefix='python-ahk-', suffix='.ahk', delete=False
) as tempscriptfile:
tempscriptfile.write(_DAEMON_SCRIPT) # XXX: can we make this async?
self._temp_script = tempscriptfile.name
daemon_script = self._temp_script
atexit.register(os.remove, tempscriptfile.name)
else:
daemon_script = self._temp_script
runargs = [self._executable_path, '/CP65001', '/ErrorStdOut', daemon_script]
proc = AsyncAHKProcess(runargs=runargs)
await proc.start()
Expand Down
Loading

0 comments on commit 1da2609

Please sign in to comment.