Skip to content

ESOAPI.__init__ fails for environment='production_lasilla' because it unconditionally requires a Phase 1 (p1api) connection that doesn't support that environment #55

Description

@talister

Title

ESOAPI.__init__ fails for environment='production_lasilla' because it unconditionally requires a Phase 1 (p1api) connection that doesn't support that environment

Summary

tom_eso.eso_api.ESOAPI.__init__ always constructs two API connections — a Phase 1 connection (p1api.ApiConnection) followed by a Phase 2 connection (p2api.ApiConnection) — even for callers who only need Phase 2 functionality (e.g. getOB, getOBExecutions, getNightExecutions, getRuns). This makes it impossible to construct an ESOAPI instance for La Silla (environment='production_lasilla') at all, because the p1api (Phase 1 / Proposal Preparation) client doesn't support that environment string, even though the underlying Phase 2 API does.

Versions

  • tom-eso 0.2.4
  • p2api (PyPI p2api) 1.0.10
  • p1api (PyPI phase1api) 0.0.2

Steps to reproduce

from tom_eso.eso_api import ESOAPI

eso = ESOAPI('production_lasilla', username, password)

Expected behavior

Given real, working ESO P2 credentials with La Silla access (confirmed via the ESO P2 web portal, https://www.eso.org/p2ls/home), this should succeed and allow calling Phase-2-only methods (getOB, getOBExecutions, getNightExecutions, getRuns, etc.) against La Silla.

Actual behavior

Raises immediately, before the Phase 2 connection is ever attempted:

ESOAPI.__init__: Error creating API connections: (500, 'POST', 'production_lasilla', 'environment not supported')
p1api.p1api.P1Error: (500, 'POST', 'production_lasilla', 'environment not supported')

Root cause

In tom_eso/eso_api.py, ESOAPI.__init__ does:

self.api1 = p1api.ApiConnection(self.environment, self.username, self.password)
self.api2 = p2api.ApiConnection(self.environment, self.username, self.password)

self.api1 (Phase 1) is constructed first, and unconditionally, regardless of whether the caller ever uses any Phase 1 functionality.

p1api.p1api.API_URL only defines two environments:

API_URL = {
    'production' : 'https://www.eso.org/cop1/api',
    'demo'       : 'https://www.eso.org/cop1demo/api'
}

There is no production_lasilla entry, so p1api.ApiConnection.__init__ raises P1Error(500, 'POST', 'production_lasilla', 'environment not supported') — before self.api2 (the Phase 2 connection actually needed for OB status/execution data) is ever constructed.

By contrast, p2api.p2api.API_URL does define a La Silla entry:

API_URL = {
    'production'        : 'https://www.eso.org/cop/api/v1',
    'production_lasilla': 'https://www.eso.org/copls/api/v1',
    ...
}

So the Phase 2 API itself supports La Silla — ESOAPI just never gets the chance to reach it.

Confirmed workaround

Bypassing ESOAPI entirely and constructing a p2api.ApiConnection directly against production_lasilla connects successfully and returns real data:

import p2api
p2api.ApiConnection('production_lasilla', username, password).getRuns()

This confirms the account has working La Silla P2 (Phase 2) access, and that the failure above is purely an artifact of ESOAPI's unconditional Phase 1 connection, not a genuine API/account limitation.

Suggested fix

One of:

  1. Make the Phase 1 connection lazy — only construct self.api1 when a Phase 1 method is actually called (or via a property/lazy-init), so Phase-2-only usage (which is most of what ESOAPI exposes today — getOB, getOBExecutions, getNightExecutions, getRuns, etc.) doesn't require it at all.
  2. Make the Phase 1 connection optional — e.g. a constructor flag or try/except around self.api1 construction that logs a warning and leaves self.api1 = None on environments Phase 1 doesn't support, rather than failing the whole ESOAPI construction.
  3. At minimum, if Phase 1 genuinely doesn't support La Silla, that's worth calling out explicitly in ESOAPI's docstring/README, since the current failure mode (a P1Error about production_lasilla "not supported") reads as "La Silla isn't supported at all," which isn't true for Phase 2.

Happy to submit this as a PR if a maintainer can confirm which direction (1 vs 2) is preferred.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

UserIssue Raised by a userbugSomething isn't working

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions