[Python] Parser un fichier ics en json

Le format iCalendar

Le format iCalendar est un format standardisé utilisé pour le partage de calendrier. Les données se présentent sous la forme ‘un fichier .ics ou .ical.

Les données contenues dans ce fichier peuvent être de type:

  • Événements
  • To do
  • Entrée de journal
  • Temps libre / temps occupé

Le problème

Pour les besoins d’un projet j’ai utilisé un fichier ics pour renseigner les événements d’un festival de projection de films sur le développement durable.

L’intérêt de cet usage est de proposer un interface de gestion des événements du festival à moindre coût, les fichier iCalendar pouvant être édités par un logiciel d’agenda comme Mozilla Thunderbird par exemple.

Ayant développé une carte interactive pour localiser les événements (web component Angular 8) j’avais besoin d’une interface pour gérer le

fichier ics et servir les données au format json.

J’ai développé cette interface avec le framework Python Flask.

Parser le fichiers ics

import icalendar
from icalendar import Calendar
import datetime
import json

#Définition des propriétés à récupérer
props = ['categories', 'summary', 'description',
         'location', 'dtstart', 'dtend', 'attach']

#Extraction de la partie événements du fichier ics
#la variable cal contient les données lues depuis le fichier ics
def cal_parser(cal):
    data = []
    for component in cal.walk():
        if component.name == "VEVENT":
            data.append(extract_component_data(component))
    return data

#Extraction des données de la propriété événement (vevent) du fichier ics
#Certaines données sont directement au format string mais d'autres sont au format vObject, un format spécifique à iCalendar)
def extract_component_data(component):
    item = {}
    for prop in props:
        if(component.get(prop) is not None):
            if(prop == 'dtstart' or prop == 'dtend'):
                value = dt_format(component.get(
                    prop).to_ical().decode('utf-8', 'ignore'))
                item[prop] = value
            elif(prop == 'attach'):
                item[prop] = component.get(prop)
            else:
                item[prop] = component.get(
                    prop).to_ical().decode('utf-8', 'ignore')
    return item

#Formatage des dates
def dt_format(dt):
    y = dt[0:4]
    m = dt[4:6]
    d = dt[6:8]
    h = dt[9:11]
    mm = dt[11:13]
    x = datetime.datetime(int(y), int(m), int(d), int(h), int(mm))
    return x

#Lecture du fichier ics, extraction des données et conversion en json
def get_ics_data():
    try:
        basedir = os.path.abspath(os.path.dirname(__file__))
        data_file = os.path.join(basedir, "static/festival.ics")
        f = open(data_file, 'rb')
        cal = Calendar.from_ical(f.read())
        raw_data = cal_parser(cal)
        for item in raw_data:
            item['dtstart'] = item['dtstart'].strftime('%m/%d/%Y %Hh%M')
            item['dtend'] = item['dtend'].strftime('%m/%d/%Y %Hh%M')
        j = json.dumps(raw_data)
        f.close()
        return j, 200, {'Content-Type': 'application/json'}
    except Exception as error:
        return {"message": "Une erreur est survenue."}, 500, {'Content-Type': 'application/json'}