Skip to content

fix: upgrade alpyca to PyPI release#137

Open
dgegen wants to merge 5 commits into
ppp-one:mainfrom
dgegen:main
Open

fix: upgrade alpyca to PyPI release#137
dgegen wants to merge 5 commits into
ppp-one:mainfrom
dgegen:main

Conversation

@dgegen
Copy link
Copy Markdown
Collaborator

@dgegen dgegen commented May 30, 2026

Pull Request

Description
Upgrades alpyca from a git-pinned pre-release (2.0.4) to the stable PyPI release (>=3.1.2,<4), and fixes several issues that surfaced during the migration. The most significant fix moves device instantiation out of __init__ and into run(), which is where it should live in a multiprocessing context, as creating a networked device object in the parent process before forking risks shared sockets and pickle failures. Subprocess initialisation now also sets a 60 s default timeout and randomises client IDs per process to prevent conflicts when multiple device processes run concurrently.

As a secondary cleanup, the no_kwargs sentinel pattern in get__ is replaced with a straightforward if callable(data): data = data(**kwargs), which is both simpler and safer (plain property reads are no longer at risk of a spurious call attempt).

Changes Made

  • Pin alpyca to >=3.1.2,<4 from PyPI instead of a git dependency
  • Move AlpacaDevice device instantiation from __init__ to run() so the device object is created inside the subprocess
  • Add _ensure_60s_default_timeouts(): monkey-patches Device._put/_get to default to a 60 s timeout (applied once per subprocess)
  • Add _seed_client_ids(): randomises Device._client_id and _client_trans_id using a PID-derived seed to avoid inter-process conflicts
  • Simplify callable dispatch in get__: replace the no_kwargs sentinel with if callable(data): data = data(**kwargs); removes the only caller site (observatory.py) that passed no_kwargs=True
  • Fix AbortExposure call in observatory.py — was incorrectly double-called via camera.get("AbortExposure")()
  • Add tests/test_alpaca_device_process.py covering the callable auto-execution path

Checklist

  • Code follows project style guidelines
  • Tests added/updated
  • Documentation updated (if needed)
  • All checks pass

…isation

Upgrade alpyca from a git pin to the stable PyPI release (>=3.1.2).

Move device instantiation from __init__ to run() so that the alpyca
device object (which opens network connections) is created inside the
subprocess rather than in the parent, avoiding pickling issues and
shared-socket hazards under multiprocessing.

Initialise subprocess-local state in run(): patch Device._put/_get to
default to a 60 s timeout and seed client IDs with a PID-derived random
value to prevent conflicts across processes.

Simplify callable dispatch in get__: replace the no_kwargs sentinel
with `if callable(data): data = data(**kwargs)`, which handles both
zero-arg methods (empty kwargs → data()) and methods with arguments,
and correctly skips the call for plain property reads.
Copilot AI review requested due to automatic review settings May 30, 2026 15:52
@dgegen dgegen changed the title fix: upgrade alpyca to PyPI release and fix subprocess device initial… fix: upgrade alpyca to PyPI release May 30, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR upgrades alpyca to the PyPI 3.x release and adjusts the Alpaca device subprocess wrapper for safer multiprocessing behavior.

Changes:

  • Replaces the git-pinned alpyca dependency with alpyca>=3.1.2,<4.
  • Moves Alpaca device construction into the subprocess run() path and adds timeout/client ID setup.
  • Simplifies get__ callable handling and updates related observatory calls/tests.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pyproject.toml Updates the alpyca dependency specifier.
uv.lock Refreshes locked dependency metadata for alpyca and transitive packages.
src/astra/alpaca_device_process.py Moves device instantiation to subprocess runtime and changes callable dispatch behavior.
src/astra/observatory.py Updates calls affected by the new callable execution behavior.
tests/test_alpaca_device_process.py Adds coverage for auto-executing a callable device method.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/astra/alpaca_device_process.py Outdated
Comment on lines +522 to +526
if data == "not get":
data = getattr(self.device, method)

# if kwargs, call method with kwargs
if kwargs:
if "no_kwargs" in kwargs:
data = data()
else:
data = data(**kwargs)
if callable(data):
data = data(**kwargs)
Comment thread src/astra/alpaca_device_process.py Outdated
Comment on lines +393 to +406
else:
self.queue.put(
(
self.metadata,
{
"type": "log",
"data": (
"warning",
f"{self.device_type} is not a valid device type",
),
},
)
)
return
Comment thread src/astra/alpaca_device_process.py Outdated
Comment on lines +525 to +526
if callable(data):
data = data(**kwargs)
dgegen added 4 commits May 30, 2026 21:17
There are 4 occurrences of `self.telescope.get("PulseGuide")(...)`.
The new behaviour, get now auto-calls the callable in the subproces).
Consequently, this needed to be updated
If getattr() succeeded but the subsequent call raised, data was left
holding the bound method rather than the "not get" sentinel, causing
the retry loop and final attempt to be silently skipped, then failing
to pickle the method on send. Use a temporary variable so data is only
updated from the sentinel once the full operation completes.
The previous late check in run() left the parent holding open pipes to a
dead subprocess, resulting in an EOFError on the next get() or set() call
rather than a meaningful error. Raising ValueError in __init__ fails fast
before start() is called and any pipes are created, giving callers an
immediate and unambiguous error message.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants