Skip to content

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

python-krairport-api

KAC 출도착 GW 전환 (2026-09-29)

KAC departures()/arrivals()는 15158625의 B551178/flight-status/depart, /arrival을 사용한다. IIAC와 주차 API는 바뀌지 않는다. 기존 ODCloud raw 메서드는 구 계약 그대로이며 GW를 대신 호출하지 않는다.

async with KrairportClient.from_env(retries=0) as client:
    flights = await client.kac.flight_status(
        airport_code="GMP", searchday="20260929", num_of_rows=100, max_pages=20
    )

flight_status()는 출발·도착 전체 페이지의 정합성을 확인한 뒤 list[Flight]를 반환한다. 메타데이터 누락·변경, 반복/빈 중간 페이지, 상한 도달은 예외다. 하루의 모든 운항이나 동일 시점의 스냅샷을 보장한다는 뜻은 아니다. 범위와 검증 정책. Flight에 공항명, line_type, 공동운항 대표 편명 master_flight_id 선택 필드를 추가했다. 신규 승인 후 청주 출·도착 105건 조회를 확인했다. 소비자 운영 배포/live 검증은 별도다.

공동운항은 같은 fid를 공유해도 개별 flight_id를 보존한다. 같은 방향의 fid 재사용은 명시적인 공동운항 표시와 동일 대표 편명·노선·예정시각이 확인되고, 해당 방향의 출발/도착 공항이 요청 공항과 일치할 때만 허용한다. 같은 (fid, flight_id) 반복은 시각이 바뀌어도 오류다. 2026-10-25 김포 하루 전체 473편을 별도 제한 조회로 확인했다. 공식 명세와 실제 응답의 차이·회귀 근거.

Debug UI와 fixture replay

krairport는 디버그 UI가 테스트 fixture를 만들 수 있도록 DebugRun과 await client.debug()를 제공합니다. 라이브러리 자체는 Streamlit에 의존하지 않고, tools/streamlit_debug_ui의 별도 UI 패키지가 설치된 krairport를 import해서 실행합니다.

from krairport import KrairportClient

async with KrairportClient.from_env() as client:
    run = (await client.debug_departures(airport_code="GMP", searchday="20260430"))
    print(run.response["body"])
    print(run.processed)

저장된 fixture는 tests/fixtures/{function}/{case}.json에 두며, python -m pytest tests/test_generated_fixtures.py가 외부 API 호출 없이 replay합니다. 자세한 설계와 assertion mode는 docs/debug-fixtures.md를 참고하세요.

지원 endpoint 카탈로그는 api_catalog()로 확인할 수 있습니다. 각 항목에는 사람이 읽는 데이터셋명과 공공데이터포털 서비스키 신청 링크가 포함됩니다.

from krairport import api_catalog

for item in api_catalog("departures"):
    print(item.provider, item.dataset_name, item.service_key_url)

비동기 전용 클라이언트와 TPS

KrairportClient, KacClient, IiacClient는 비동기 전용이다. 조회·디버그는 await, 페이지 순회는 async for를 사용한다. 로컬 공항 메타데이터·좌표 helper는 일반 함수다. 기존 Async 이름과 aio/sync facade를 제거했다. 아래 예제는 async 함수 안에서 실행한다.

from krairport import KrairportClient

async with KrairportClient.from_env(max_rps=5) as client:
    rows = await client.departures(airport_code="GMP", num_of_rows=10)
    async for page in client.iter_pages(
        client.world_weather, direction="arrival", airport_code="ICN", max_pages=2
    ):
        print(page.page, len(page.items))

KAC·IIAC를 합한 예산을 사용하며 여러 클라이언트에는 같은 AsyncTokenBucket을 주입할 수 있다. docs/async-tps.md에 용량·취소·redirect 범위를 설명한다. 모델의 raw, model_dump(mode="json"), page_no/num_of_rows 계약은 유지한다.

한국공항공사(KAC)와 인천국제공항공사(IIAC) OpenAPI를 하나의 Python 인터페이스로 묶기 위한 공항 데이터 라이브러리 설계 문서입니다.

python-krairport-api는 "인천공항은 인천국제공항공사, 그 외 전국공항은 한국공항공사"라는 공급자 경계를 내부에서 흡수하고, 운항/주차/혼잡도/공항 메타데이터를 Pydantic 기반 Python 타입 모델로 일관되게 제공하는 것을 목표로 합니다. Python 코드에서는 krairport로 import합니다.

현재 저장소는 0.1.0 초기 구현을 포함합니다. KAC/IIAC provider adapter, 통합 KrairportClient, KST 시간 파서, XML/JSON 정규화, CLI, fixture 기반 테스트가 들어 있으며, live API 테스트는 서비스키가 있을 때 별도 marker로 확장합니다.


핵심 특징

  • KAC + IIAC 통합 인터페이스: 사용자는 공항코드만 넘기고, 라이브러리가 적절한 공급자 API를 선택합니다.
  • 공항 라우팅 내장: ICN은 IIAC, 그 외 KAC 운영 공항은 KAC API로 자동 분기합니다.
  • 운항/주차/교통/시설 중심 초기 범위: 항공편 도착/출발, 정기 운항스케줄, 항공기 등록번호/기종, 주차요금/현황, 입국장 혼잡도, 승객예고, 공항버스/택시, 시설/취항지/기상을 우선 지원 대상으로 둡니다.
  • JSON/XML 차이 흡수: KAC의 XML 중심 응답과 IIAC의 JSON/XML 응답을 내부에서 정규화합니다.
  • KST datetime 표준화: YYYYMMDD, HHMM, YYYYMMDDHHMM, 과학적 표기 숫자 문자열 등을 timezone-aware datetime이나 int/str로 변환합니다.
  • 공급자별 필드명 흡수: airport_code, schAirCode, airport, flight_id, f_id, schFID처럼 기관마다 다른 필드명을 Pythonic 인터페이스로 통합합니다.
  • Pydantic 모델: Flight, AircraftAssignment, ParkingFee, ArrivalCongestion, PassengerForecast 같은 immutable BaseModel과 public StrEnum/type alias를 제공합니다.
  • 위경도 표준화: 공항 좌표와 provider 좌표 필드를 krairport.Coordinate로 정규화하고, GeoJSON용 (longitude, latitude) 변환을 제공합니다.
  • 주소 표준화: 시설 provider row의 주소 필드는 문자열로 보존하고, 공항 내부 위치 문자열은 location에 따로 보존합니다.
  • 공항 메타데이터 레지스트리: get_airport(), list_airports(), nearest_airport()로 지도/검색/근접 공항 계산을 지원합니다.
  • 누락 API raw fallback: 아직 typed 모델로 고정하지 않은 KAC/IIAC 공식 엔드포인트도 kac_raw_items() / iiac_raw_items()로 접근할 수 있습니다.
  • fixture 기반 테스트 우선: 기본 테스트는 실 API 호출 없이 동작하고, live 테스트는 각 기관 서비스키가 있을 때만 분리 실행합니다.

시작하기

1단계: 인증키 발급

KAC/IIAC 모두 data.go.kr 계열 서비스이므로 환경변수 이름은 하나로 통일합니다.

  1. 공공데이터포털에서 한국공항공사 API 활용신청을 합니다.
  2. 같은 포털에서 인천국제공항공사 API 활용신청을 합니다.
  3. 발급받은 디코딩 인증키를 환경변수로 저장합니다.
export DATA_GO_KR_SERVICE_KEY="발급받은_data.go.kr_디코딩_인증키"

Windows PowerShell:

$env:DATA_GO_KR_SERVICE_KEY="발급받은_data.go.kr_디코딩_인증키"

2단계: 설치

현재는 문서/스캐폴딩 단계이므로 개발 설치를 기준으로 안내합니다.

git clone https://github.com/digitie/python-krairport-api.git
cd python-krairport-api
python -m venv .venv
pip install -e ".[dev]"

3단계: 사용 예시

from krairport import Airport, Coordinate, Direction, KrairportClient

async with KrairportClient.from_env() as airport:

    # 1) 김포공항 출발편 조회 -> KAC로 자동 라우팅
    for flight in (await airport.departures(airport_code=Airport.GMP, searchday="20260430", from_time="0600", to_time="1200")):
        print(flight.flight_id, flight.status_korean, flight.scheduled_at, flight.provider)

    # 2) 인천공항 도착편 조회 -> IIAC로 자동 라우팅
    for flight in (await airport.arrivals(airport_code="ICN", searchday="20260430", from_time="0600", to_time="1200")):
        print(flight.flight_id, flight.arrival_airport_code, flight.estimated_at, flight.terminal)

    # 3) 인천공항 입국장 혼잡도
    for row in (await airport.arrival_congestion(terminal="T1")):
        print(row.entry_gate, row.flight_id, row.korean_count, row.foreign_count)

    # 4) 김포공항 주차요금
    for fee in (await airport.parking_fees(airport_code="GMP")):
        print(fee.airport_code, fee.small_basic_minutes, fee.small_basic_fee)

    # 5) 김포/제주 등 KAC 실시간 항공기 등록번호/기종
    for plane in (await airport.aircraft_assignments(airport_code="CJU", sch_st_time="202604300600", sch_ed_time="202604301200")):
        print(plane.flight_id, plane.aircraft_registration, plane.aircraft_type)

    # 6) enum/type/좌표 메타데이터 활용
    icn = airport.airport_metadata(Airport.ICN)
    print(icn.coordinate.as_geojson_position())
    print(airport.nearest_airport(Coordinate.from_values("37.56 N", "126.79 E")).code)

    # direction도 문자열과 enum을 모두 받습니다.
    (await airport.flight_schedules(airport_code=Airport.ICN, direction=Direction.ARRIVAL))

제공 API

0.1.0 초기 구현 범위는 아래와 같습니다.

Public method Provider Source endpoint 반환
KrairportClient.departures(...) KAC 또는 IIAC KAC flight-status/depart, IIAC getPassengerDeparturesDeOdp/getPassengerDeparturesOdp list[Flight]
KrairportClient.arrivals(...) KAC 또는 IIAC KAC flight-status/arrival, IIAC getPassengerArrivalsDeOdp/getPassengerArrivalsOdp list[Flight]
KrairportClient.aircraft_assignments(...) KAC getFlightStatusAPLList list[AircraftAssignment]
KrairportClient.parking_fees(...) KAC parkingfee list[ParkingFee]
KrairportClient.parking_status(...) KAC 또는 IIAC KAC airportParkingCongestionRT, IIAC getTrackingParking list[ParkingAreaStatus]
KrairportClient.arrival_congestion(...) IIAC getArrivalsCongestion list[ArrivalCongestion]
KrairportClient.passenger_forecast(...) IIAC getfPassengerNoticeIKR list[PassengerForecast]
KrairportClient.flight_schedules(...) KAC 또는 IIAC KAC getDflightScheduleList/getIflightScheduleList, IIAC getPaxFltSchedArrivals/getPaxFltSchedDepartures list[FlightSchedule]
KrairportClient.airport_facilities(...) KAC 또는 IIAC KAC getAirportFacilities, IIAC getFacilityKR list[AirportFacility]
KrairportClient.bus_routes(...) KAC 또는 IIAC KAC businfo, IIAC getBusInfo list[BusRoute]
KrairportClient.taxi_status(...) KAC 또는 IIAC KAC getJejuTaxiWaitInfo, IIAC getTaxiStatus list[TaxiStatus]
KrairportClient.world_weather(...) IIAC getPassengerArrivalsWorldWeather/getPassengerDeparturesWorldWeather list[WorldWeather]
KrairportClient.service_destinations(...) IIAC getServiceDestinationInfo list[ServiceDestination]
KrairportClient.kac_raw_items(...) KAC 임의 KAC service/operation list[dict]
KrairportClient.iiac_raw_items(...) IIAC 임의 B551177 service/operation list[dict]
KrairportClient.airport_metadata(...) local 번들 공항 메타데이터 AirportMetadata
KrairportClient.airports(...) local provider/active 필터 가능한 메타데이터 목록 tuple[AirportMetadata, ...]
KrairportClient.nearest_airport(...) local WGS84 좌표 기준 근접 공항 `AirportMetadata

자세한 커버리지와 raw 지원 범위는 docs/api-coverage.md, enum/type/좌표 규칙은 docs/coordinates-and-types.md를 참고하세요.

확장 권장 순서:

  1. departures() / arrivals()로 공항 라우팅 계층 완성
  2. aircraft_assignments()로 KAC 운항 부가정보 연동
  3. parking_fees() / parking_status()로 주차 계열 분리
  4. arrival_congestion() / passenger_forecast()로 IIAC 혼잡도 계열 추가
  5. kac_raw_items() / iiac_raw_items()로 아직 typed 모델이 없는 공식 엔드포인트를 먼저 연결한 뒤 fixture가 쌓이면 모델 승격

응답 모델

Flight

from datetime import datetime
from krairport import Direction, KrairportModel, Provider

class Flight(KrairportModel):
    provider: Provider
    airport_code: str
    flight_id: str
    flight_unique_id: str | None
    direction: Direction
    airline_name: str | None
    airline_code: str | None
    departure_airport_code: str | None
    arrival_airport_code: str | None
    scheduled_at: datetime | None
    estimated_at: datetime | None
    status_korean: str | None
    status_english: str | None
    terminal: str | None
    gate: str | None
    codeshare: bool | None
    raw: dict

AircraftAssignment

class AircraftAssignment(KrairportModel):
    airport_code: str
    flight_id: str
    flight_unique_id: str | None
    aircraft_registration: str | None
    aircraft_type: str | None
    airline_name: str | None
    scheduled_at: datetime | None
    estimated_at: datetime | None
    gate: str | None
    raw: dict

ParkingFee

class ParkingFee(KrairportModel):
    airport_code: str
    parking_name: str | None
    small_basic_minutes: int | None
    small_basic_fee: int | None
    large_basic_minutes: int | None
    large_basic_fee: int | None
    small_daily_max_fee: int | None
    large_daily_max_fee: int | None
    airport_name: str | None = None
    small_free_minutes: int | None = None
    small_unit_minutes: int | None = None
    small_unit_fee: int | None = None
    large_free_minutes: int | None = None
    large_unit_minutes: int | None = None
    large_unit_fee: int | None = None
    small_holiday_free_minutes: int | None = None
    small_holiday_basic_minutes: int | None = None
    small_holiday_basic_fee: int | None = None
    small_holiday_unit_minutes: int | None = None
    small_holiday_unit_fee: int | None = None
    small_holiday_daily_max_fee: int | None = None
    large_holiday_free_minutes: int | None = None
    large_holiday_basic_minutes: int | None = None
    large_holiday_basic_fee: int | None = None
    large_holiday_unit_minutes: int | None = None
    large_holiday_unit_fee: int | None = None
    large_holiday_daily_max_fee: int | None = None
    raw: dict

parking_fees()는 KAC의 실제 parkingParkingName, parkingMaxAccount(d)와 parkingHoli*를 정규화합니다. 기존 이름·최대요금 별칭도 유지하며 실제 필드를 먼저 사용합니다. 빈 값과 -는 None, 명시적인 0은 0으로 보존합니다. 음수·소수·비수치 요금을 절삭하거나 무료 요금으로 바꾸지 않고 KrairportParseError로 거부합니다. 쉼표는 정상적인 세 자리 천단위 묶음만 허용하고, 손상된 구분 표기는 추정하지 않고 None으로 남깁니다. 추가 필드는 기본값 None이라 기존 생성자 호출을 유지합니다. 이 모델은 공급자 요금표이며 공휴일 판정·주차장 연결·무료 회차 적용·최종 주차요금 계산은 포함하지 않습니다.

ArrivalCongestion

class ArrivalCongestion(KrairportModel):
    terminal: str
    entry_gate: str
    flight_id: str | None
    airport_code: str | None
    gate_number: str | None
    scheduled_at: datetime | None
    estimated_at: datetime | None
    korean_count: int | None
    foreign_count: int | None
    raw: dict

PassengerForecast

class PassengerForecast(KrairportModel):
    display_date: str
    time_range: str
    t1_arrival_east: int | None
    t1_arrival_west: int | None
    t1_departure_total: int | None
    t2_arrival_total: int | None
    t2_departure_total: int | None
    raw: dict

Python 타입 정책

공항 OpenAPI는 기관마다 응답형식과 필드명이 크게 다르지만, krairport는 모델 경계에서 타입을 정규화하는 것을 기본 원칙으로 둡니다.

원본 값 Python 표면 타입 규칙
20260430 date 또는 str 날짜 의미가 확실하면 date, 단순 조회 키면 str 유지
0600, 2400 str 조회 파라미터는 zero-padding 보존
202604300930 KST aware datetime 일정/변경 시각은 Asia/Seoul 기준
2.02112E+11 datetime 또는 정규화된 문자열 IIAC 과학적 표기 시각은 안전하게 파싱
Y / N bool 코드쉐어/사용여부 계열
숫자형 문자열 int 또는 float 의미가 count/요금이면 int, 비율/소수면 float
공항코드 GMP, ICN str 또는 Airport 항상 대문자 IATA 코드 보존
공급자/방향 Provider, Direction StrEnum이라 문자열 비교/JSON 직렬화 가능
위경도 Coordinate WGS84 decimal degrees, public DTO (lat, lon), GeoJSON은 as_geojson_position()
주소 `str None`
편명 KE123, 7C1101 str leading zero 가능성을 고려해 숫자형 변환 금지
빈 문자열, 공백 None 공통 정규화

모든 public 응답 모델은 Pydantic v2 BaseModel 기반입니다. 외부 앱에서는 model_dump(mode="json"), model_dump_json(), 또는 to_dict() / to_json()을 사용할 수 있습니다.


공급자 라우팅 규칙

한국 공항 OpenAPI는 기관별 책임 경계가 분명합니다.

공항 공급자 비고
ICN 인천국제공항공사 (IIAC) 인천공항 전용
GMP, PUS, CJU, TAE, CJJ, KWJ, RSU, USN, MWX, YNY, KUV, HIN, WJU, KPO 등 한국공항공사 (KAC) 인천 제외 전국공항

핵심 규칙:

  • ICN 관련 운항/주차/혼잡도는 무조건 IIAC로 보냅니다.
  • KAC 데이터셋 설명에 "전국공항(인천공항 제외)"가 명시된 경우 ICN 요청을 허용하지 않습니다.
  • IIAC의 입국장/승객예고/주차 데이터는 인천공항 전용이므로 다른 공항코드로 우회하지 않습니다.
  • 통합 클라이언트는 airport_code만 보고 provider를 선택하되, low-level provider client도 별도로 둡니다.

에러 처리

KrairportError
├── KrairportAuthError         # 인증키 오류, 활용승인 미완료
├── KrairportRequestError      # 잘못된 파라미터, 지원하지 않는 공항/조합
├── KrairportRateLimitError    # 일 트래픽 초과
├── KrairportNetworkError      # httpx timeout / connection error
├── KrairportServerError       # 5xx, 공급자 응답 이상
├── KrairportParseError        # XML/JSON 구조 또는 타입 변환 오류
└── UnsupportedAirportError    # 해당 기능을 지원하지 않는 공항

기관별 에러 코드/메시지는 다르므로 내부에서 매핑하되, public API는 위 공통 예외 계층만 노출하는 쪽을 권장합니다.


개발

python -m compileall src/krairport tests
python -m pytest
python -m pytest --cov=krairport --cov-fail-under=85
ruff check .
mypy src/krairport

기본 테스트는 실 API를 호출하지 않는 fixture 기반이어야 합니다. 실제 키를 사용하는 테스트는 아래처럼 분리합니다.

pytest -m live_kac
pytest -m live_iiac

자세한 테스트 정책은 docs/testing.md, 반복 실수 방지 로그는 docs/repeated-mistakes.md, 장애 대응 메모는 docs/troubleshooting.md를 참고하세요.


프로젝트 파일

.
├── README.md
├── AGENTS.md
├── krairport-api.md
├── SKILL.md
├── CHANGELOG.md
├── pyproject.toml
├── docs/
│   ├── repeated-mistakes.md
│   ├── coordinates-and-types.md
│   ├── testing.md
│   └── troubleshooting.md
├── src/
│   └── krairport/
│       ├── __init__.py
│       ├── airports.py
│       ├── client.py
│       ├── providers/
│       │   ├── kac.py
│       │   └── iiac.py
│       ├── models.py
│       ├── enums.py
│       ├── types.py
│       ├── exceptions.py
│       ├── _http.py
│       ├── _xml.py
│       ├── _time.py
│       ├── _convert.py
│       ├── _routing.py
│       ├── cli.py
│       └── py.typed

테스트 구조:

tests/
├── fixtures/
├── test_airports.py
├── test_client.py
├── test_cli.py
├── test_convert.py
├── test_geo.py
├── test_http.py
├── test_kac.py
├── test_iiac.py
├── test_pydantic_models.py
├── test_routing.py
├── test_time.py
└── test_xml.py

운영상 주의

  • KAC와 IIAC는 같은 공항 데이터처럼 보여도 파라미터명과 시간 의미가 다릅니다.
  • KAC는 XML-only 엔드포인트가 아직 많으므로 JSON 가정 금지입니다.
  • IIAC는 동일한 주제에 당일 Odp, 상세 DeOdp, 혼잡도, 승객예고처럼 API가 나뉘므로 이름이 비슷해도 응답 스키마가 다릅니다.
  • IIAC 공공데이터포털 서비스는 2026년에도 URL 변경 공지가 있었으므로, 새 API를 typed 모델로 올리기 전 docs/api-coverage.md와 변경 공지를 먼저 확인합니다.
  • 상세 운항 API는 KAC/IIAC 모두 D-3 ~ D+6 범위 문서가 많지만, 당일 운항 API는 당일 또는 H-2 ~ H+2 같은 더 좁은 범위를 사용합니다.
  • 일부 IIAC 응답 예시에는 estimatedtime, scheduletime이 일반 문자열이 아니라 과학적 표기처럼 보이는 예시가 있어 파서가 느슨해야 합니다.
  • 좌표는 krairport.Coordinate를 사용합니다. as_tuple()과 as_lat_lon()은 (latitude, longitude)이고, GeoJSON 순서가 필요하면 as_geojson_position()을 사용합니다.
  • 문서의 파일 위치 정보는 src/krairport/client.py처럼 프로젝트 기준 상대 경로로 작성합니다.
  • Python 내부 문서(module/class/function docstring과 설명용 주석)는 한글로 작성합니다. provider 원문, 코드 식별자, URL은 원문을 유지합니다.
  • Windows 작업 환경에서 rg가 권한 문제로 막히면 PowerShell Get-ChildItem / Select-String으로 우회합니다.
  • PowerShell에서 한글 문서를 읽거나 검색할 때는 Get-Content -Encoding UTF8, Select-String -Encoding UTF8처럼 인코딩을 명시합니다.
  • 문서상 serviceURL과 실제 요청 함수명이 분리되므로 base URL + operation 경로를 함께 관리해야 합니다.
  • Windows/Python 환경에는 IANA timezone database가 없을 수 있으므로 tzdata 의존성을 포함합니다. 설치 전 실행 환경에서도 Asia/Seoul 고정 UTC+9 fallback을 사용합니다.

참고 링크

확인 기준일: 2026-05-06


변경 이력

  • 0.1.0: KAC/IIAC 통합 클라이언트, provider adapter, KST 시간/타입 변환, XML/JSON 파서, CLI, fixture 기반 테스트와 문서 보강.

주차장 완결 집합 API

await client.parking_raw_set(provider="kac", page_size=100, max_pages=10)은 원천 total과 실제 페이지 수신을 검증한 ParkingRawSet을 반환한다. IIAC는 provider="iiac"를 쓴다. 기존 목록 API는 그대로다. 완결성·오류·상한 계약을 참고한다.

수집 승인용 엄격한 현황 값

parse_parking_snapshot_values(raw, provider="kac"|"iiac")는 ParkingSnapshotValues로 총면수·점유면수·timezone-aware KST 관측시각을 반환한다. 숫자의 오류문자열/음수/bool/ 소수/상한초과와 없거나 유효하지 않은 원천시각을 원문 없는 KrairportParseError로 거부한다. 기존 status API의 느슨한 숫자·시각 변환은 바꾸지 않는다. HTTP를 호출하지 않는 public 원천검증 함수이므로 수집 승인 전에 raw와 canonical 값의 대응을 확인할 수 있다.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages