Skip to content

Commit eb99607

Browse files
committedMar 29, 2017
initial code commit
1 parent 8f36c3a commit eb99607

10 files changed

+497
-1
lines changed
 

‎LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
652652
If the program does terminal interaction, make it output a short
653653
notice like this when it starts in an interactive mode:
654654

655-
{project} Copyright (C) {year} {fullname}
655+
SSIM Copyright (C) 2017 Rok Mihevc
656656
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657657
This is free software, and you are welcome to redistribute it
658658
under certain conditions; type `show c' for details.

‎README.rst

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
SSIM parser
2+
===========
3+
4+
5+
Introduction
6+
------------
7+
IATA SSIM (Standard Schedules Information Manual) file parser is a tool to read the standard IATA file format.
8+
9+
10+
Usage example
11+
-------------
12+
13+
.. code-block:: python
14+
15+
import ssim
16+
17+
slots, header, footer = ssim.read('slotfile_example.SCR')
18+
19+
20+
Authors
21+
-------
22+
23+
Rok.Mihevc_
24+
25+
License
26+
-------
27+
28+
Uses the `GPLv3`_ license.
29+
30+
.. _GPLv3: https://opensource.org/licenses/GPL-3.0
31+
.. _Rok.Mihevc: https://rok.github.io

‎setup.py

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from distutils.core import setup
2+
setup(
3+
name = 'SSIM',
4+
packages = ['SSIM'],
5+
version = '0.1',
6+
description = 'A parser for SSIM',
7+
author = 'Rok Mihevc',
8+
author_email = 'rok.mihevc@gmail.com',
9+
url = 'https://github.com/rok/SSIM',
10+
download_url = 'https://github.com/rok/SSIM/archive/0.1.tar.gz',
11+
keywords = ['parsing', 'SSIM', 'data'],
12+
classifiers = [],
13+
)

‎ssim.py

+195
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
import re
2+
from datetime import datetime
3+
4+
# For email parsing see: emailregex.com
5+
header_pattern = (
6+
'^(?P<file_type>SCR|SIR)\s*\n'
7+
'/{0,1}(?P<email>[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+){0,1}\n{0,1}'
8+
'(?P<season>\w+)\s*\n'
9+
'(?P<export_date>\w+)\s*\n'
10+
'(?P<origin>\w+)\n'
11+
)
12+
footer_pattern = (
13+
'(?P<special_information>SI [A-Za-z0-9 ()\.:=]+)\n'
14+
'(?P<general_information>GI [A-Za-z0-9 ()\.:=]+)\n*$'
15+
)
16+
17+
return_row_pattern = (
18+
'(?P<action_code>[A-Z])'
19+
'(?P<arrival_flight_prefix>[A-Z]{2,3})'
20+
'(?P<arrival_flight_suffix>\d+[A-Z]*)'
21+
'\s'
22+
'(?P<departure_flight_prefix>[A-Z]{2,3})'
23+
'(?P<departure_flight_suffix>\d+[A-Z]*)'
24+
'\s'
25+
'(?P<start_date_of_operation>\d{2}[A-Z]{3})'
26+
'(?P<end_date_of_operation>\d{2}[A-Z]{3})'
27+
'\s'
28+
'(?P<days_of_operation>\d{7})'
29+
'\s'
30+
'(?P<seat_number>\d{3})'
31+
'(?P<aircraft_type_3_letter>\w{3})'
32+
'\s'
33+
'(?P<origin_of_flight>[A-Z]{3})'
34+
'(?P<scheduled_time_of_arrival_utc>\d{4})'
35+
'\s'
36+
'(?P<scheduled_time_of_departure_utc>\d{4})'
37+
'(?P<overnight_indicator>[0-6])*'
38+
'(?P<destination_of_flight>[A-Z]{3})'
39+
'\s'
40+
'(?P<arrival_type_of_flight>[A-Z])'
41+
'(?P<departure_type_of_flight>[A-Z])'
42+
'\n*'
43+
)
44+
45+
departure_row_pattern = (
46+
'(?P<action_code>[A-Z])'
47+
'\s'
48+
'(?P<departure_flight_prefix>[A-Z]{2,3})'
49+
'(?P<departure_flight_suffix>\d+[A-Z]*)'
50+
'\s'
51+
'(?P<start_date_of_operation>\d{2}[A-Z]{3})'
52+
'(?P<end_date_of_operation>\d{2}[A-Z]{3})'
53+
'\s'
54+
'(?P<days_of_operation>\d{7})'
55+
'\s'
56+
'(?P<seat_number>\d{3})'
57+
'(?P<aircraft_type_3_letter>\w{3})'
58+
'\s'
59+
'(?P<scheduled_time_of_departure_utc>\d{4})'
60+
'(?P<destination_of_flight>[A-Z]{3})'
61+
'\s'
62+
'(?P<departure_type_of_flight>[A-Z])'
63+
'\n*'
64+
)
65+
66+
arrival_row_pattern = (
67+
'(?P<action_code>[A-Z])'
68+
'(?P<arrival_flight_prefix>[A-Z]{2,3})'
69+
'(?P<arrival_flight_suffix>\d+[A-Z]*)'
70+
'\s'
71+
'(?P<start_date_of_operation>\d{2}[A-Z]{3})'
72+
'(?P<end_date_of_operation>\d{2}[A-Z]{3})'
73+
'\s'
74+
'(?P<days_of_operation>\d{7})'
75+
'\s'
76+
'(?P<seat_number>\d{3})'
77+
'(?P<aircraft_type_3_letter>\w{3})'
78+
'\s'
79+
'(?P<origin_of_flight>[A-Z]{3})'
80+
'(?P<scheduled_time_of_arrival_utc>\d{4})'
81+
'\s'
82+
'(?P<arrival_type_of_flight>[A-Z])'
83+
'\n*'
84+
)
85+
86+
row_patterns = [re.compile(arrival_row_pattern),
87+
re.compile(departure_row_pattern),
88+
re.compile(return_row_pattern)]
89+
90+
91+
def _add_year(dt):
92+
93+
return datetime(dt.year + 1, dt.month, dt.day)
94+
95+
96+
def _parse_slotfile(text):
97+
"""
98+
Parses a SSIM message and returns it as a dicts.
99+
100+
Parameters
101+
----------.
102+
text : string
103+
104+
Returns
105+
-------
106+
parsed_rows: list of dicts, describing rows of a slotfile.
107+
header: dict, describing the header of the slotfile.
108+
footer: dict, describing the footer of the slotfile.
109+
"""
110+
111+
header_match = re.search(header_pattern, text)
112+
footer_match = re.search(footer_pattern, text)
113+
114+
header = header_match.groupdict()
115+
footer = footer_match.groupdict()
116+
117+
rows = text[header_match.end():footer_match.start()].splitlines()
118+
119+
parsed_rows = []
120+
121+
for row in rows:
122+
for row_pattern in row_patterns:
123+
try:
124+
parsed_rows.append(re.search(row_pattern, row).groupdict())
125+
except:
126+
pass
127+
128+
return parsed_rows, header, footer
129+
130+
131+
def _process_slots(slots, header, year_prefix='20'):
132+
"""
133+
Processes parsed SSIM messages to insert the correct start
134+
and end dates.
135+
136+
Parameters
137+
----------.
138+
slots : list of dicts, describing rows of a slotfile.
139+
header: dict, describing the header of the slotfile.
140+
year_prefix: string, defining the century of the flight.
141+
142+
Returns
143+
-------
144+
processed_slots: list of dicts, describing exact slots of a slotfile.
145+
"""
146+
147+
year = year_prefix + header['season'][1:]
148+
season = header['season'][0]
149+
processed_slots = []
150+
151+
for slot in slots:
152+
153+
slot['start_date_of_operation'] = \
154+
datetime.strptime(slot['start_date_of_operation'] + year, '%d%b%Y')
155+
slot['end_date_of_operation'] = \
156+
datetime.strptime(slot['end_date_of_operation'] + year, '%d%b%Y')
157+
158+
if season == 'W':
159+
if slot['end_date_of_operation'].month < 6:
160+
slot['end_date_of_operation'] = _add_year(slot['end_date_of_operation'])
161+
162+
if slot['start_date_of_operation'].month < 6:
163+
slot['start_date_of_operation'] = _add_year(slot['start_date_of_operation'])
164+
165+
slot['start_date_of_operation'] = slot['start_date_of_operation'].strftime('%Y-%m-%d')
166+
slot['end_date_of_operation'] = slot['end_date_of_operation'].strftime('%Y-%m-%d')
167+
168+
processed_slots.append(slot)
169+
170+
return processed_slots
171+
172+
173+
def read(slotfile, year_prefix='20'):
174+
"""
175+
Parses and processes a valid SSIM file.
176+
177+
Parameters
178+
----------.
179+
slotfile : path to a slotfile.
180+
year_prefix: string, defining the century of the flight.
181+
182+
Returns
183+
-------
184+
slots: list of dicts, describing exact slots of a slotfile.
185+
header: dict, describing the header of the slotfile.
186+
footer: dict, describing the footer of the slotfile.
187+
"""
188+
189+
with open(slotfile) as f:
190+
text = f.read()
191+
192+
slots, header, footer = _parse_slotfile(text)
193+
slots = _process_slots(slots, header, year_prefix)
194+
195+
return slots, header, footer

‎test/__init__.py

Whitespace-only changes.

‎test/conftest.py

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import pytest
2+
import glob
3+
import yaml
4+
5+
6+
@pytest.fixture
7+
def slotfiles():
8+
slotfiles_files = glob.glob('data/slots_*.yml')
9+
10+
slotfiles = []
11+
for slotfile in slotfiles_files:
12+
with open(slotfile) as f:
13+
text = yaml.load(f.read())
14+
15+
slotfiles.append(text)
16+
17+
return slotfiles

‎test/data/slots_austria.yml

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
raw_data: |
2+
SCR
3+
W07
4+
07FEB
5+
VIE
6+
NABC1234 08FEB08FEB 0000500 150319 LNZ0900 C
7+
N ABC5678 09FEB09FEB 0000060 150319 1200LNZ C
8+
NABC1234 ABC5678 10FEB10FEB 0000007 150319 LNZ1430 1455LNZ CC
9+
SI free text
10+
GI free text
11+
12+
header:
13+
email: null
14+
export_date: '07FEB'
15+
file_type: 'SCR'
16+
origin: 'VIE'
17+
season: 'W07'
18+
19+
slots:
20+
- action_code: 'N'
21+
arrival_flight_prefix: 'ABC'
22+
arrival_flight_suffix: '1234'
23+
start_date_of_operation: '08FEB'
24+
end_date_of_operation: '08FEB'
25+
days_of_operation: '0000500'
26+
seat_number: '150'
27+
aircraft_type_3_letter: '319'
28+
origin_of_flight: 'LNZ'
29+
scheduled_time_of_arrival_utc: '0900'
30+
arrival_type_of_flight: 'C'
31+
32+
- action_code: 'N'
33+
departure_flight_prefix: 'ABC'
34+
departure_flight_suffix: '5678'
35+
start_date_of_operation: '09FEB'
36+
end_date_of_operation: '09FEB'
37+
days_of_operation: '0000060'
38+
seat_number: '150'
39+
aircraft_type_3_letter: '319'
40+
scheduled_time_of_departure_utc: '1200'
41+
destination_of_flight: 'LNZ'
42+
departure_type_of_flight: 'C'
43+
44+
- action_code: 'N'
45+
arrival_flight_prefix: 'ABC'
46+
arrival_flight_suffix: '1234'
47+
departure_flight_prefix: 'ABC'
48+
departure_flight_suffix: '5678'
49+
start_date_of_operation: '10FEB'
50+
end_date_of_operation: '10FEB'
51+
days_of_operation: '0000007'
52+
seat_number: '150'
53+
aircraft_type_3_letter: '319'
54+
origin_of_flight: 'LNZ'
55+
scheduled_time_of_arrival_utc: '1430'
56+
scheduled_time_of_departure_utc: '1455'
57+
overnight_indicator: null
58+
destination_of_flight: 'LNZ'
59+
arrival_type_of_flight: 'C'
60+
departure_type_of_flight: 'C'
61+
62+
processed_slots:
63+
- action_code: 'N'
64+
arrival_flight_prefix: 'ABC'
65+
arrival_flight_suffix: '1234'
66+
start_date_of_operation: '2008-02-08'
67+
end_date_of_operation: '2008-02-08'
68+
days_of_operation: '0000500'
69+
seat_number: '150'
70+
aircraft_type_3_letter: '319'
71+
origin_of_flight: 'LNZ'
72+
scheduled_time_of_arrival_utc: '0900'
73+
arrival_type_of_flight: 'C'
74+
75+
- action_code: 'N'
76+
departure_flight_prefix: 'ABC'
77+
departure_flight_suffix: '5678'
78+
start_date_of_operation: '2008-02-09'
79+
end_date_of_operation: '2008-02-09'
80+
days_of_operation: '0000060'
81+
seat_number: '150'
82+
aircraft_type_3_letter: '319'
83+
scheduled_time_of_departure_utc: '1200'
84+
destination_of_flight: 'LNZ'
85+
departure_type_of_flight: 'C'
86+
87+
- action_code: 'N'
88+
arrival_flight_prefix: 'ABC'
89+
arrival_flight_suffix: '1234'
90+
departure_flight_prefix: 'ABC'
91+
departure_flight_suffix: '5678'
92+
start_date_of_operation: '2008-02-10'
93+
end_date_of_operation: '2008-02-10'
94+
days_of_operation: '0000007'
95+
seat_number: '150'
96+
aircraft_type_3_letter: '319'
97+
origin_of_flight: 'LNZ'
98+
scheduled_time_of_arrival_utc: '1430'
99+
scheduled_time_of_departure_utc: '1455'
100+
overnight_indicator: null
101+
destination_of_flight: 'LNZ'
102+
arrival_type_of_flight: 'C'
103+
departure_type_of_flight: 'C'
104+
105+
footer:
106+
special_information: 'SI free text'
107+
general_information: 'GI free text'

‎test/data/slots_belgium.yml

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
raw_data: |
2+
SCR
3+
/someone@example.com
4+
S08
5+
10DEC
6+
BRU
7+
NXY123 XY124 01JUL30SEP 1234500 120319 CDG0700 07501CDG JJ
8+
NABC1234 08JUN08JUN 0000007 150319 LNZ0900 C
9+
N ABC1234 09JUN09JUN 1000000 150319 0900LNZ C
10+
SI = Special Information (e.g. database ABC)
11+
GI = General Information (e.g. BRGDS)
12+
13+
header:
14+
email: 'someone@example.com'
15+
export_date: '10DEC'
16+
file_type: 'SCR'
17+
origin: 'BRU'
18+
season: 'S08'
19+
20+
slots:
21+
- action_code: 'N'
22+
arrival_flight_prefix: 'XY'
23+
arrival_flight_suffix: '123'
24+
departure_flight_prefix: 'XY'
25+
departure_flight_suffix: '124'
26+
start_date_of_operation: '01JUL'
27+
end_date_of_operation: '30SEP'
28+
days_of_operation: '1234500'
29+
seat_number: '120'
30+
aircraft_type_3_letter: '319'
31+
origin_of_flight: 'CDG'
32+
scheduled_time_of_arrival_utc: '0700'
33+
scheduled_time_of_departure_utc: '0750'
34+
overnight_indicator: '1'
35+
destination_of_flight: 'CDG'
36+
arrival_type_of_flight: 'J'
37+
departure_type_of_flight: 'J'
38+
39+
- action_code: 'N'
40+
arrival_flight_prefix: 'ABC'
41+
arrival_flight_suffix: '1234'
42+
start_date_of_operation: '08JUN'
43+
end_date_of_operation: '08JUN'
44+
days_of_operation: '0000007'
45+
seat_number: '150'
46+
aircraft_type_3_letter: '319'
47+
origin_of_flight: 'LNZ'
48+
scheduled_time_of_arrival_utc: '0900'
49+
arrival_type_of_flight: 'C'
50+
51+
- action_code: 'N'
52+
departure_flight_prefix: 'ABC'
53+
departure_flight_suffix: '1234'
54+
start_date_of_operation: '09JUN'
55+
end_date_of_operation: '09JUN'
56+
days_of_operation: '1000000'
57+
seat_number: '150'
58+
aircraft_type_3_letter: '319'
59+
scheduled_time_of_departure_utc: '0900'
60+
destination_of_flight: 'LNZ'
61+
departure_type_of_flight: 'C'
62+
63+
processed_slots:
64+
- action_code: 'N'
65+
arrival_flight_prefix: 'XY'
66+
arrival_flight_suffix: '123'
67+
departure_flight_prefix: 'XY'
68+
departure_flight_suffix: '124'
69+
start_date_of_operation: '2008-07-01'
70+
end_date_of_operation: '2008-09-30'
71+
days_of_operation: '1234500'
72+
seat_number: '120'
73+
aircraft_type_3_letter: '319'
74+
origin_of_flight: 'CDG'
75+
scheduled_time_of_arrival_utc: '0700'
76+
scheduled_time_of_departure_utc: '0750'
77+
overnight_indicator: '1'
78+
destination_of_flight: 'CDG'
79+
arrival_type_of_flight: 'J'
80+
departure_type_of_flight: 'J'
81+
82+
- action_code: 'N'
83+
arrival_flight_prefix: 'ABC'
84+
arrival_flight_suffix: '1234'
85+
start_date_of_operation: '2008-06-08'
86+
end_date_of_operation: '2008-06-08'
87+
days_of_operation: '0000007'
88+
seat_number: '150'
89+
aircraft_type_3_letter: '319'
90+
origin_of_flight: 'LNZ'
91+
scheduled_time_of_arrival_utc: '0900'
92+
arrival_type_of_flight: 'C'
93+
94+
- action_code: 'N'
95+
departure_flight_prefix: 'ABC'
96+
departure_flight_suffix: '1234'
97+
start_date_of_operation: '2008-06-09'
98+
end_date_of_operation: '2008-06-09'
99+
days_of_operation: '1000000'
100+
seat_number: '150'
101+
aircraft_type_3_letter: '319'
102+
scheduled_time_of_departure_utc: '0900'
103+
destination_of_flight: 'LNZ'
104+
departure_type_of_flight: 'C'
105+
106+
footer:
107+
special_information: 'SI = Special Information (e.g. database ABC)'
108+
general_information: 'GI = General Information (e.g. BRGDS)'

‎test/test_parse_slotfile.py

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from ssim import _parse_slotfile
2+
3+
4+
def test_parse_slotfile(slotfiles):
5+
6+
for slot_data in slotfiles:
7+
8+
slots, header, footer = _parse_slotfile(slot_data['raw_data'])
9+
10+
assert header == slot_data['header']
11+
assert footer == slot_data['footer']
12+
13+
for slot, parsed_slot in zip(slot_data['slots'], slots):
14+
assert slot == parsed_slot

‎test/test_process_slots.py

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from ssim import _process_slots
2+
3+
4+
def test_process_slots(slotfiles):
5+
6+
for slot_data in slotfiles:
7+
8+
processed_slots = _process_slots(slot_data['slots'], slot_data['header'])
9+
10+
for processed_slot, parsed_slot in zip(slot_data['processed_slots'], processed_slots):
11+
assert processed_slot == parsed_slot

0 commit comments

Comments
 (0)
Please sign in to comment.