Skip to content

Commit

Permalink
Merge branch 'release/3.0.0'
Browse files Browse the repository at this point in the history
[v3.0.0] - 2023.09.18
Added
- Error handling for airport data loading.
- Unit testing for main endpoints parsing, internal retryable queries w/ backoff, error handling and logging.

Changed
- Module console logging is now only set up if handlers haven't already been specified.
- `dataclass` usage instead of `namedtuple`.
- Only load airport data as needed.
- Separated out concerns to `SessionManager`.
- Less redundant logging.
- Propagate up exceptions if all retries fail.

Removed
- **Removed the availability API.**
  - Unfortunately, grabbing a session cookie is now insufficient to use this API.
Usage of the API now requires a session cookie to be generated within a "real" browser session.
I do not wish to add the capability to specifically work around this, seemingly intentional, limitation.
  - With all this in mind, I've decided to regrettably remove the ability to use this endpoint from the library,
since it will fail in most cases without such a workaround implemented.
- Methods deprecated in v2.0.0 have now been completely removed.
  • Loading branch information
cohaolain committed Sep 18, 2023
2 parents ca9a982 + 1265556 commit 0cc904c
Show file tree
Hide file tree
Showing 14 changed files with 1,040 additions and 275 deletions.
36 changes: 36 additions & 0 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Python application

on:
push:
branches: [ "develop" ]
pull_request:
branches: [ "develop" ]

permissions:
contents: read

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt -r requirements.dev.txt
- name: Black
run: black --check --verbose -- .
- name: Run unit testing with pytest
run: |
pytest --cov --cov-report xml
- name: Coveralls GitHub Action
uses: coverallsapp/github-action@v2
with:
path-to-lcov: coverage.xml

4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ __pycache__
build
dist
ryanair_py.egg-info
*coverage*

*.iml
inspectionProfiles
modules.xml
vcs.xml
.idea
.idea
.vscode
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# Changelog

# [v3.0.0] - 2023.09.18
### Added
- Error handling for airport data loading.
- Unit testing for main endpoints parsing, internal retryable queries w/ backoff, error handling and logging.

### Changed
- Module console logging is now only set up if handlers haven't already been specified.
- `dataclass` usage instead of `namedtuple`.
- Only load airport data as needed.
- Separated out concerns to `SessionManager`.
- Less redundant logging.
- Propagate up exceptions if all retries fail.

### Removed
- **Removed the availability API.**
- Unfortunately, grabbing a session cookie is now insufficient to use this API.
Usage of the API now requires a session cookie to be generated within a "real" browser session.
I do not wish to add the capability to specifically work around this, seemingly intentional, limitation.
- With all this in mind, I've decided to regrettably remove the ability to use this endpoint from the library,
since it will fail in most cases without such a workaround implemented.
- Methods deprecated in v2.0.0 have now been completely removed.

# [v2.3.1] - 2023.05.03
### Added
- README warning note for availability API
Expand Down
56 changes: 3 additions & 53 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
# Ryanair Python
![Testing status](https://github.com/cohaolain/ryanair-py/actions/workflows/python-app.yml/badge.svg) [![Coverage Status](https://coveralls.io/repos/github/cohaolain/ryanair-py/badge.svg?branch=develop)](https://coveralls.io/github/cohaolain/ryanair-py?branch=develop)

This module allows you to retrieve either:
1) The cheapest flights, with or without return flights, within a fixed set of dates.
or
2) All available flights between two locations, on a given date
This module allows you to retrieve the cheapest flights, with or without return flights, within a fixed set of dates.

This is done directly through Ryanair's API, and does not require an API key.

Expand Down Expand Up @@ -36,7 +34,7 @@ from ryanair import Ryanair

# You can set a currency at the API instance level, so could also be GBP etc. also.
# Note that this may not *always* be respected by the API, so always check the currency returned matches
# your expectation. For example, the underlying API for get_all_flights does not support this.
# your expectation.
api = Ryanair("EUR")
```
### Get the cheapest one-way flights
Expand Down Expand Up @@ -68,51 +66,3 @@ tomorrow_1 = tomorrow + timedelta(days=1)
trips = api.get_cheapest_return_flights("DUB", tomorrow, tomorrow, tomorrow_1, tomorrow_1)
print(trips[0]) # Trip(totalPrice=85.31, outbound=Flight(departureTime=datetime.datetime(2023, 3, 12, 7, 30), flightNumber='FR5437', price=49.84, currency='EUR', origin='DUB', originFull='Dublin, Ireland', destination='EMA', destinationFull='East Midlands, United Kingdom'), inbound=Flight(departureTime=datetime.datetime(2023, 3, 13, 7, 45), flightNumber='FR5438', price=35.47, origin='EMA', originFull='East Midlands, United Kingdom', destination='DUB', destinationFull='Dublin, Ireland'))
```

### Get all available flights between two airports
> ⚠️ __Warning:__ This API appears to be very tightly rate-limited.
> Use it as infrequently as possible, with some backoff if possible.
> Improper or over-usage could result in your IP address being blocked from using the API,
> __which is required to book flights__.
E.g. get all available flights from Dublin to London Gatwick, or London, tomorrow:
```python
from datetime import datetime, timedelta

from ryanair import Ryanair
from tabulate import tabulate

# We don't need to specify a currency if we're only using `get_all_flights`, as this API doesn't support currency
# conversion. It will always return dares denominated in the currency of the departure country.
api = Ryanair()
tomorrow = datetime.today().date() + timedelta(days=1)

flights = api.get_all_flights("DUB", tomorrow, "LGW")
print(tabulate(flights, headers="keys", tablefmt="github"))

# We can even expand it to include all vaguely-London airports:
flights = api.get_all_flights("DUB", tomorrow, "LON", destination_is_mac=True)
print(tabulate(flights, headers="keys", tablefmt="github"))
```

This prints the following:

| departureTime | flightNumber | price | currency | origin | originFull | destination | destinationFull |
|---------------------|----------------|---------|----------|----------|--------------|---------------|-------------------|
| 2023-03-12 06:25:00 | FR 114 | 61.99 | EUR | DUB | Dublin | LGW | London (Gatwick) |
| 2023-03-12 09:20:00 | FR 112 | 88.12 | EUR | DUB | Dublin | LGW | London (Gatwick) |
| 2023-03-12 11:30:00 | FR 122 | 120.37 | EUR | DUB | Dublin | LGW | London (Gatwick) |
| ... | | | EUR | | | | |


and

| departureTime | flightNumber | price | currency | origin | originFull | destination | destinationFull |
|---------------------|----------------|---------|----------|----------|--------------|---------------|-------------------|
| 2023-03-12 06:25:00 | FR 114 | 61.99 | EUR | DUB | Dublin | LGW | LON |
| 2023-03-12 06:35:00 | FR 202 | 65.09 | EUR | DUB | Dublin | STN | LON |
| 2023-03-12 07:10:00 | FR 342 | 65.09 | EUR | DUB | Dublin | LTN | LON |
| 2023-03-12 08:20:00 | FR 206 | 102.09 | EUR | DUB | Dublin | STN | LON |
| ... | | | | | | | |


3 changes: 3 additions & 0 deletions requirements.dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
black==23.3.0
pytest==7.4.0
pytest-cov==4.1.0
1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
requests
Deprecated
backoff
16 changes: 16 additions & 0 deletions ryanair/SessionManager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import requests


class SessionManager:
BASE_SITE_FOR_SESSION_URL = "https://www.ryanair.com/ie/en"

def __init__(self):
self.session = requests.Session()
self._update_session_cookie()

def _update_session_cookie(self):
# Visit main website to get session cookies
self.session.get(self.BASE_SITE_FOR_SESSION_URL)

def get_session(self):
return self.session
49 changes: 38 additions & 11 deletions ryanair/airport_utils.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,50 @@
import os
from collections import namedtuple
from dataclasses import dataclass
from math import radians, sin, cos, asin, sqrt

import csv
from typing import Any

from ryanair.types import Flight

Airport = namedtuple("Airport", ("IATA_code", "lat", "lng", "location"))
AIRPORTS = None

AIRPORTS = {}
with open(os.path.join(os.path.dirname(__file__), 'airports.csv'), newline='', encoding="utf8") as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
iata_code = row["iata_code"]
location = ','.join((row["iso_region"], row["iso_country"]))
lat = float(row["latitude_deg"])
lng = float(row["longitude_deg"])

AIRPORTS[iata_code] = Airport(IATA_code=iata_code, lat=lat, lng=lng, location=location)
@dataclass
class Airport:
IATA_code: str
lat: float
lng: float
location: str


def load_airports():
global AIRPORTS
if AIRPORTS is not None:
return AIRPORTS

AIRPORTS = {}
try:
with open(
os.path.join(os.path.dirname(__file__), "airports.csv"),
newline="",
encoding="utf8",
) as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
row: dict[str, Any] = row

iata_code = row["iata_code"]
location = ",".join((row["iso_region"], row["iso_country"]))
lat = float(row["latitude_deg"])
lng = float(row["longitude_deg"])

AIRPORTS[iata_code] = Airport(
IATA_code=iata_code, lat=lat, lng=lng, location=location
)
except Exception as e:
print(f"Error loading airports data: {e}")
return AIRPORTS


def _haversine(lat1, lon1, lat2, lon2):
Expand Down
Loading

0 comments on commit 0cc904c

Please sign in to comment.