ximun144
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    \pagebreak # Projet ADSILLH 2019/2020 - Rapport de fin de projet Ce projet rend compte du travail effectué au cours de l'année 2019/2020 concernant le logiciel Khal. ## L'équipe Notre équipe comptabilise cinq personnes: - Axel Danguin - Maxime Oçafrain - Yorick Barbanneau - Florian Lassenay - Simon Crespeau ### Organisation git Nous avons commencé par créer une organisation sur Github: [Khalzone](https://github.com/khalzone), ou chacun de nous a eut les droits d'administration. Nous y avons créé un nouvel embranchement du projet **Khal** que nous avons tous clôné en local. À partir de cette organisation nous pouvons créer et travailler sur nos propres branches. En règle générale nous créons des branche de `fix` pour répondre aux différentes `issues` que nous nommons sous la forme `fix/<numero_issue>` par exemple `fix/805` Lorque nous voulons faire des demandes d'intégration (ou *merge requests*), nous le faisons via **Khalzone**. #### Documentation Nous avons également créé un [wiki](https://github.com/khalzone/khal/wiki) sur notre dépôt. Il permet à chacun de documenter ses avancées et de centraliser les informations lorsque l'un d'entre nous a besoin de s'y référer. ### Échanges Nous avons l'habitude de communiquer par mail et en messagerie instantanée via un canal Discord. Nous sommes aussi présent sur le canal IRC de pimutils sur le serveur Freenode. ## Khal **Khal** est un logiciel faisant partie de [pimutils](https://pimutils.org), une petite organisation regroupant actuellement quatre programmeurs et mainteneurs de projets voués à la gestion d'information personnelle telle que les contacts, les agendas, les todolists... Les programmes faisant partie de **pimutils** n'ont pas les mêmes buts, mais ont été pensé pour être chacun la pièce d'un écosystème laissant la maîtrise à l'utilisateur sur ses informations. ### Quelques chiffres **Khal**, c'est: - [https://lostpackets.de/khal](https://lostpackets.de/khal) - [https://github.com/pimutils/khal](https://github.com/pimutils/khal) - Création du projet en **août 2014** - Un peu plus de **2000 commits** - **58 contributeurs** **geier**, mainteneur principal du projet, est un neurophysicien (donc pas développeur professionnel) et travaille sur le logiciel sur son temps libre. **Khal** n'est donc pas un très gros projet. Il est cependant développé et maintenu avec sérieux, rassemblant une communauté restreinte mais active et fidèle. **Khal** se voit de surcroît être implémenté dans divers modules pour d'autres logiciels tels que des gestionnaires de bureau ou barres de tâches, développés par la communauté. ### Autour du logiciel... ![khal dans pimutils](img/pimutils.svg) **Khal** est capable de se synchroniser avec des serveurs CalDAV au travers de [**Vdirsyncer**](https://github.com/pimutils/vdirsyncer). #### Vdirsyncer On voit que **vdirsyncer** stocke les informations synchronisées dans des dossiers locaux, au format `.ics` pour les calendiers, dans lesquels nous allons pouvoir interagir grâce à **khal**. **vdirsyncer** n'est donc pas indispensable à l'utilisation de **khal**. Cependant il offre un moyen extrêmement simple de synchroniser ses agendas avec un serveur distant. #### urwid **urwid** est une bibliothèque permettant des rendus rapides d'interface. Sa gestion des couleurs est relativement interessante et pour l'instant ikhal -qui en a la capacité- n'exploite pas les rendus avec des codes 256 couleurs voire en code type html 24 bits. ### Pourquoi avoir choisi ce projet ? Étant un groupe plutôt disparate en terme d'expérience, et ce dans divers domaines (programmation python, communauté du logiciel libre, travail en équipe, ...), **Khal** s'est présenté comme le terrain idéal pour découvrir ensemble et s'aider mutuellement sur ces sujets, tout en évitant de s'imposer un projet trop conséquent. Ce choix s'est avéré judicieux car il nous a permis en quelques semaines de découvrir et travailler sur des sujets tout à fait nouveaux pour chacun d'entre nous (tests unitaires, git, intégration continue, python, ...). Le choix du langage `python` a été aussi décisif car il constitue une part importante de notre travail au sein de la licence. ### Fonctionnalités du logiciel **Khal** est capable de: - Lire et écrire des évènements et des Icalendars dans un dossier. - Ajouter, modifier et supprimer simplement des évènements, en ligne de commande et TUI. **Khal** dépend de la version 3.4 ou supérieure de `python`. Il est accessible sur la majorité des systèmes d'exploitation à l'exception de Microsoft Windows. Les évènements sont enregistrés dans une base de données **SQLite** afin d'optimiser les traitements. #### Les tests **Khal** est "livré" avec un ensemble de tests, destinés à vérifier le bon fonctionnement des différents objets et fonctions du logiciel. Les tests unitaires sont réaliés avec [`pytest`][l_pytest] tandis que les tests de compatibilité sont réalisés avec [`tox`][l_tox]. [l_pytest]:https://pytest.org/en/latest/ [l_tox]:https://tox.readthedocs.io/en/latest/ ### Exemple Très simplement, voici comment se déroule un ajout d'évènement dans **khal** ainsi que l'affichage de ce dernier dans le terminal. ```bash $ khal new -a adsillh 09/12/2019 14:00 18:00 Rendez-vous Projet $ khal calendar lu ma me je ve sa di lundi, 09/12/ déc. 25 26 27 28 29 30 1 14:00-18:00 Rendez-vous Projet 2 3 4 5 6 7 8 18:00-19:30 Sport 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ``` ### Architecture du code ![](img/khal.png) Lors de l'exécution du logiciel, **khal** commence par charger la configuration de l'utilisateur. La génération de l'objet représentant la configuration est gérée via la bibliothèque python **configobj**. Ensuite, afin d'exécuter la commande entrée par l'utilisateur, **khal** utilise ses fonctions principales, ses classes d'objet et la configuration générée à partir du fichier `config`. Enfin, l'interaction avec l'utilisateur est gérée dans le terminal. Via des `print` ou de façon plus intéractive via la bibliothèque python **urwid**. ## Nos contributions Dans le reste du document, nous pourrons utiliser le mot anglais **issue**. C'est un terme générique qui n'a pas de traduction équivalente en français mais qui peut regrouper diverses formes de retours d'expériences faits par des utilisateurs à la communauté autour du logiciel. (Rapports de bugs, demandes d'ajout de fonctionnalité,...) #### Légende des contributions | Code fonctionnel | Passe les tests | Demande d'intégration effectuée | Demande Acceptée! | |:----------------:|:---------------:|:-------------------------------:|:-----------------:| |![](img/bk_star.svg){width=20px}|![](img/be_star.svg){width=20px}|![](img/be_star.svg){width=20px}|![](img/gn_star.svg){width=20px}| #### Liste des contributions étudiées | Issue | Objet | Avancée | |-------|-------|---------| | #805 | Durée d'évènement par défaut | ![](img/bk_star.svg){width=20px}![](img/be_star.svg){width=20px}![](img/be_star.svg){width=20px}![](img/gn_star.svg){width=20px}| | #805b | Durée d'évènement par défaut, différente pour chaque agenda |![](img/bk_star.svg){width=20px}![](img/be_star.svg){width=20px} | [](img/gn_star.svg){width=20px}| | #809 | Affichage et format de dates dans l'agenda | ![](img/bk_star.svg){width=20px}![](img/be_star.svg){width=20px} | [](img/gn_star.svg)| | #860 | Tests unitaires générant des erreurs alétoires sous ArchLinux | | | #876 | Erreur "Cannot find timezone" à l'importation d'évènements |![](img/bk_star.svg){width=20px}![](img/be_star.svg){width=20px}![](img/be_star.svg){width=20px}![](img/gn_star.svg){width=20px} | | #705 | Gestion des couleurs | | | #866 | Changements_sans_quitter_ikhal | | [l_805]:https://github.com/pimutils/khal/issues/805 [l_809]:https://github.com/pimutils/khal/issues/809 [l_860]:https://github.com/pimutils/khal/issues/860 [l_876]:https://github.com/pimutils/khal/issues/876 [l_395]:https://github.com/pimutils/khal/issues/395 [l_633]:https://github.com/pimutils/khal/issues/633 [l_705]:https://github.com/pimutils/khal/issues/705 [w_805]:https://github.com/khalzone/khal/wiki/issue805 [w_805b]:https://github.com/khalzone/khal/wiki/issue805b [w_809]:https://github.com/khalzone/khal/wiki/Issue-809 [w_860]:https://github.com/khalzone/khal/wiki/issue860 [w_876]:https://github.com/khalzone/khal/wiki/issue876 [w_395-633]:https://github.com/Khalzone/khal/wiki/issue-395-&-633 [w_705]:https://github.com/khalzone/khal/wiki/issue-705 ### Issue 805: Durée d'un évènement par défaut - [Issue][l_805] - [Wiki][w_805] Nous avons commencé par travailler tous ensemble sur une [demande d'ajout](https://github.com/pimutils/khal/issues/805) de fonctionnalité: définir des durées d'évènement par défaut. #### Situation de départ : ![](img/805/depart.png) Il existe deux types d'évènements dans khal (mais c'est aussi le cas pour de nombreux autres systèmes de gestion d'évènements par agenda): | Type d'évènement | Type de la variable représentant le début et la fin | Valeur par défaut | |------------------|-----------------------------------------------------|-------------------| | Avec horaires | `datetime` | 1 heure | | Sans horaire (seulement des jours) | `date` | 1 jour | L'idée est de fournir aux utilisateurs un moyen de régler eux-mêmes cette valeur, via le fichier de configuration de **khal**, car comme indiqué sur le schéma, la valeur par défaut est inscrite "en dur" dans le code source. ```python # khal/controllers.py # Nouvel évènement en ligne de commande def new_from_string(collection, calendar_name, conf, info, location=None, format=None, env=None): """construct a new event from a string and add it""" info = parse_datetime.eventinfofstr( info, conf['locale'], adjust_reasonably=True, localize=False, ) ``` ```python # khal/parse_datetime.py def eventinfofstr(info_string, locale, adjust_reasonably=False, localize=False): """parses a string of the form START [END | DELTA] [TIMEZONE] [SUMMARY] [:: DESCRIPTION] into a dictionary with keys: dtstart, dtend, timezone, allday, summary, description """ [...] start, end, allday = guessrangefstr( ' '.join(parts[0:i]), locale, adjust_reasonably=adjust_reasonably, ) def guessrangefstr(daterange, locale, # Les valeurs par défaut prennent ces valeurs là default_timedelta_date=dt.timedelta(days=1), default_timedelta_datetime=dt.timedelta(hours=1), adjust_reasonably=False): """parses a range string""" ``` #### Modifications Il a donc fallu faire les modifications nécessaires afin de permettre l'ajout des deux options dans le fichier de configuration. Lors de la création d'un nouvel évènement et dans le cas où la durée n'est pas précisée lors de la commande, Ce sera leur valeur qui sera prise en compte. ![](img/805/805.png) ```bash # ~/.config/khal/config [default] default_event_duration = '1h30m' default_day_event_duration = '3d' ``` ```python # khal/controllers.py # Nouvel évènement en ligne de commande def new_from_string(collection, calendar_name, conf, info, location=None, format=None, env=None): """construct a new event from a string and add it""" info = parse_datetime.eventinfofstr( info, conf['locale'], # lignes de configuration passées en paramètre conf['default']['default_dayevent_duration'], conf['default']['default_event_duration'], adjust_reasonably=True, localize=False, ) ``` ```python # khal/parse_datetime.py def eventinfofstr(info_string, locale, default_timedelta_date, default_timedelta_datetime, adjust_reasonably=False, localize=False): """parses a string of the form START [END | DELTA] [TIMEZONE] [SUMMARY] [:: DESCRIPTION] into a dictionary with keys: dtstart, dtend, timezone, allday, summary, description """ [...] start, end, allday = guessrangefstr( ' '.join(parts[0:i]), locale, adjust_reasonably=adjust_reasonably, default_timedelta_date=default_timedelta=date, default_timedelta_datetime=default_timedelta_datetime ) # Cette fois-ci les valeurs par défaut sont écrasées si de nouvelles sont écrites dans la configuration def guessrangefstr(daterange, locale, default_timedelta_date=dt.timedelta(days=1), default_timedelta_datetime=dt.timedelta(hours=1), adjust_reasonably=False): """parses a range string""" ``` #### État de la modification La demande de fusion a été validée par le mainteneur principal du projet, le **9 novembre 2019**. #### Remarques Nous avons tous travaillé sur cette première implémentation, ce qui nous a permis de nous connaître, d'échanger et de découvrir le logiciel. Les modifications qui suivent sont le résultat de tâches que nous nous sommes attribuées de façon plus personnelle, tout en restant en lien et en communication globale. ### Issue 805b: Durée par défaut d'un évènement, pour chaque agenda - [Issue][l_805] - [Wiki][w_805b] Pour l'instant, la durée des évènements par défaut est définissable pour l'ensemble de la configuration. Mais **khal** étant destiné à gérer plusieurs agendas, il nous semble pertinent de pouvoir définir une durée par défaut pouvant être différente pour chaque agenda. #### Modifications Il a fallu faire en sorte que les définitions de durée par défaut se fassent désormais dans la partie qui correspond à chaque agenda et non plus dans les valeurs par défaut du programme. ![](img/805/805b.png) ```bash # ~/.config/khal/config [calendars] [[perso]] path = ~/.local/share/calendars/perso/ color = dark green default_event_duration = '2h' default_dayevent_duration = '3d' [[adsillh]] path = ~/.local/share/calendars/adsillh/ color = brown default_event_duration = '1h30m' ``` Il faut tout d'abord charger les nouvelles valeurs de la configuration dans l'objet construit par khal correspondant à l'ensemble des différents agendas. ```python # khal/cli.py def build_collection(conf, selection): """build and return a khalendar.Collection from the configuration""" [...] if selection is None or name in selection: props[name] = { 'name': name, 'path': cal['path'], 'readonly': cal['readonly'], 'color': cal['color'], 'priority': cal['priority'], 'ctype': cal['ctype'], # Deux lignes ajoutées: 'default_dayevent_duration': cal['default_dayevent_duration'], 'default_event_duration': cal['default_event_duration'] } ``` Puis cette fois, la valeur n'est plus à chercher dans la configuration globale mais dans le calendrier sélectionné lors de l'ajout de l'évènement. ```python # khal/controllers.py def new_from_string(collection, calendar_name, conf, info, location=None ): """construct a new event from a string and add it""" info = parse_datetime.eventinfofstr( info, conf['locale'], conf['calendars'][calendar_name]['default_dayevent_duration'], conf['calendars'][calendar_name]['default_event_duration'], adjust_reasonably=True, localize=False): ``` Et enfin, il faut modifier le fichier `khal.spec` en conséquence ```bash # *calendars* subsection will be used. type = option('calendar', 'birthdays', 'discover', default='calendar') # Setting the default date duration adding a new AllDay event default_duration_date = timedelta(default='1d') # Setting the default datime duration adding a new event default_duration_datetime = timedelta(default='1h') ``` #### Écriture des tests De nouveaux tests relatifs à cette nouvelle implémentation ont été créés. Il faut désormais tester si les durées d'un nouvel évènement entré en ligne de commande correspondent bien aux durées par défaut entrées dans la configuration. ```python # tests/configs/default_durations.conf [calendars] [[home]] path = ~/.calendars/home/ color = dark green priority = 20 default_dayevent_duration = 4 [[work]] path = ~/.calendars/work/ readonly = True default_event_duration = 44m [[sport]] path = ~/.calendars/sport/ default_dayevent_duration = 2 default_event_duration = 55m 12s ``` ```python # tests/settings_test.py def test_default_durations(self): config = get_config( PATH + 'default_durations.conf', _get_color_from_vdir= lambda x: None, _get_vdir_type=lambda x: 'calendar', ) comp_config = { 'calendars': { 'home': {'path': os.path.expanduser('~/.calendars/home/'), 'color': 'dark green', 'readonly': False, 'priority': 20, 'type': 'calendar', 'default_dayevent_duration': dt.timedelta(days=4), 'default_event_duration': dt.timedelta(seconds=3600)}, 'work': {'path': os.path.expanduser('~/.calendars/work/'), 'readonly': True, 'color': None, 'priority': 10, 'type': 'calendar', 'default_dayevent_duration': dt.timedelta(days=1), 'default_event_duration': dt.timedelta(seconds=2640)}, 'sport': {'path': os.path.expanduser('~/.calendars/sport/'), 'readonly': False, 'color': None, 'priority': 10, 'type': 'calendar', 'default_dayevent_duration': dt.timedelta(days=2), 'default_event_duration': dt.timedelta(seconds=3312)}}, 'sqlite': {'path': os.path.expanduser('~/.local/share/khal/khal.db')}, 'locale': { 'local_timezone': get_localzone(), 'default_timezone': get_localzone(), 'timeformat': '%X', 'dateformat': '%x', 'longdateformat': '%x', 'datetimeformat': '%c', 'longdatetimeformat': '%c', 'firstweekday': 0, 'unicode_symbols': True, 'weeknumbers': False, }, 'default': { 'default_calendar': None, 'print_new': 'False', 'highlight_event_days': False, 'timedelta': dt.timedelta(days=2), 'show_all_days': False } } for key in comp_config: assert config[key] == comp_config[key] ``` #### État de la modification Le code est fonctionnel, les tests ont été écrits et la fonctionnalité les passe tous. Il reste cependant des points cruciaux à améliorer avant de proposer une demande de fusion: - Restreindre le choix d'une durée de jour à un nombre entier tout en vérifiant que les cas particuliers (comme les changements d'heure) sont bien traités. - Lier ces durées par défaut dans l'ajout d'évènement via **ikhal**. ### Issue 809: Affichage et formats des dates - [Issue][l_809] - [Wiki][w_809] #### Objectif Ajout d'une fonctionnalité permettant de modifier le format de la date affichée, notamment pour les chiffres: `1, 2, 3 ...` -> `01, 02, 03 ...` #### Modifications Le but est de modifier l'affichage. Dans khal tout ce qui est relatif à l'affichage est géré dans le fichier `calendar_display.py`. Plus spécifiquement la modification de l'affichage des dates, ou plutôt la création d'une liste de jours dans une variable semaine est gérée grâce à la méthode `str_week`. Cette fonction va créer une liste de jours day correspondant à une semaine. C'est donc ici qu'est formaté l'affichage des jours. Par défaut khal ajoute manuellement un espace devant les chiffres, ceci pour des raisons d'affichages plus propres grâce à la méthode python `rjust()`. La page de documentation de la méthode `rjust()` nous indique qu'elle complète par défaut la chaine de caractères par des espaces. Cependant nous pouvons y passer un second paramètre pour définir une chaine de caractères spécifiques afin de combler le vide pour la chaine de caractère original. #### Résolution du problème Dans le cas présent il est intéressant de noter que la chaine de caractère fait 2 caractères (pour des jours allant de '1' à '31') et pour répondre à la problèmatique de l'issue il faudrait remplacer l'espace, ajouté par défaut, par un '0'. Ainsi les chiffres de '1' à '9' seraient de la forme '01' à '09'. Cependant seulement rajouter un 0 dans le code en dur n'est pas une solution. Pour faire correspondre notre solution à Khal nous avons rajouté une ligne de configuration dans le fichier settings/khal.spec : ` date_format_view = string(default='0') ` sous la [locale]. On récuperera la valeur en argument puis on la passe en second paramètre de la méthode `rjust()`. Désormais, les chiffres s'affichent comme voulu. ```bash lu ma me je ve sa di No events nov. 28 29 30 31 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ``` #### État de la modification L'ajout de tests supplémentaires a dû être fait, pour correspondre au nouveau format de calendrier. Le pull request est en cours de validation. Une retouche sera probablement nécessaire pour passer les tests du logiciel d'intégration continue Travis. ### Issue 860: Erreurs aléatoires lors des tests sous ArchLinux - [Issue][l_860] - [Wiki][w_860] Sur une de nos machines, il est impossible de lancer les tests unitaires car ils génèrent des erreurs aléatoires d'une fois sur l'autre. L'erreur a déjà été reportée précédemment dans le projet **khal**. #### Modification Nous en sommes à la reproduction du bug. Nous testons des environnements différents pour lancer les tests, via des conteneurs `docker` et des `Dockerfile` adaptés. Nous testons à la fois des distributions et des méthodes de construction du logiciel différentes (gestionnaire de paquet de la distribution, gestionnaire de bibliothèques python `pip`, installation depuis les sources). Nous avons perdu beaucoup de temps à essayer de reproduire ce bug, sans succès pour l'instant. #### État de la modification Le bug n'a toujours pas été reproduit à l'heure actuelle. ### Issue 876: "Cannot find timezone" à l'import d'évènement - [Issue][l_876] - [Wiki][w_876] Lors de l'importation d'un fichier `.ics` avec un champ `TZID` ayant comme valeur `New Zealand Standard Time`, un message de type `warning` apparaît. #### Reproduction Nous avons repdroduit le bug en créant un fichier `.ics` à importer avec une timezone `TZID:New Zealand Standard Time`. #### Identification Le problème ne vient pas du code à proprement parlé, mais du format des fuseaux horaires. Il s'avère qu'il existe deux formats de base de données: - le premier utilisé par Microsoft Windows - le second appelé Olson sous le format `<Continent>/<Ville>` **New Zealand Standard Time** est la version Olson de **Pacific/Auckland**. Dans la bibliothèque python `icalendar`, nous avons trouvé un objet `windows_to_olson` permettant de retrouver le fuseau horaire au format Olson depuis son nom au format "Windows". #### Modifications Dans un premier temps, nous avons écrit un test spécifique qui essaye d'importer un événement avec une `timezone` au format Windows et scrute le journal d'erreur : ```python def test_windows_timezone(caplog): """Test if a windows tz format works""" cal = _get_text("tz_windows_format") split_ics(cal) assert "Cannot find timezone `Pacific/Auckland`" not in caplog.text ``` Puis nous avons modifié la fonction `split_ics()` dans le fichier `icalendar.py`. La modification permet à la fonction de parcourir le fichier `ics` à importer à la recherche d'un événement avec une `timezone` au format Windows et re remplacer celle-ci par son équivqlent Olson dans la variable `needed_tzs` #### État de la modification Une Demande d'ajout a été faites le 20 janvier 2020 portant le numéro [#920][l_PR920]. Elle a donné lieu a une discussion constructive avec deux mainteneurs et des allez-retours de code. Elle a été intégrée le 20 mars 2020. [l_PR920]:https://github.com/pimutils/khal/pull/902 ### Issue 705 : Changement des couleurs de ikhal à travers le fichier de config **https://github.com/pimutils/khal/issues/705** La gestion des couleurs ne donne pas entièrement satisfaction. Un lot d'issues concerne des retours d'expériences de portions d'interface illisibles. #### Origine L'issue 705 a été créée par le mainteneur pour répondre de manière cohérente à deux issues qui concernent le réglage des couleurs dans ikhal. ##### issue #395 De l'issue 396 il ressort le souhait de pouvoir choisir un thème via le fichier de configuration. https://github.com/pimutils/khal/issues/395 ##### issue #633 L'issue 633 signale l'impossiblité de lire certaines partie de l'interface graphique d'ikhal, du fait des configurations graphiques des terminaux. ![issue 633](img/633a.png) ![issue 633](img/633b.png) #### Le souhait du mainteneur > Colors color theme should be changeable through the color theme. > This should be easily doable by `literal_evaling` a string and adding it to the selected color theme (as urwid iterates over the palette list and later attributes overwrite earlier ones with the same name). > Proper documentation might be an issue. ##### Traduction / interprétation _Les thèmes et les couleurs des themes devraient etre modifiables depuis le thème de couleur._ _Ceci devrait etre facilement réalisable réalisant un `literal_eval` sur une variable ajoutée dans les thèmes._ _(urwid itere au-dessus en utilisant la palette de l'environnement graphique et ce sont ces derniers attributs qui écrasent écrasent les valeurs.)_ _Une documentation plus complète pourrait faire l'objet d'une issue. ![les couleurs dans ikhal](img/souhait.png) #### Etude du code Actuellement les deux thèmes possibles sont appelés par khal.spec. Le choix d'un thème se fait uniquement en modifiant ce fichier source. Ces thèmes renseignent trentaine de tuples composés de deux à trois valeurs codées en dur dans le fichier `colors.py`. La configuration est construite sur la base de dictionnaires dont `obj.ctx`, peuplé lors de l'appel de la méthode `get_config` Lorsque les fichiers de configuration sont trouvés ils sont parcourus et le fichier `khal.spec` est utilisé pour peupler le dictionnaire `user_config`. La méthode `get_extra_values` identifie chaque intitulé de section et va chercher les items correspondants. Dans notre cas ce sont des tuples précisant la couleur du fond, la couleur de la police et éventuellement le formatage de police à appliquer pour chaque champ identifié du thème. > **Nota** Il existe trente noms de champs dans un thème. La documentation ne permet pas d'identifier la fonction de tous. Certains restent introuvables ailleurs dans le code et des zones d'ikhal n'ont pas leur couleur impactée par khal. Nous avons entamé un travail de documentation qui n'a pas encore été soumis à PR. À ce stade nous pouvons tout de même réaliser l'implémentation du choix du thème. #### Variable theme La section `[view]theme` existe déja et nous souhaitons l'alimenter via le fichier de configuration. Pour aller chercher cette information dans le fichier de configuration Comme toute information renseignée par l'utilisateur celle-ci doit être vérifiée. C'est pour cette raison que le dictionnaire de vérification `fdict` est enrichi de cette section à vérifier. #### Contribution L'ajout d'un paramètre modifiable par l'utilisateur via l'enrichissement du fichier config est déja une fonctionnalité existante pour d'autres paramètres (chemin des calendriers, format de date ...). Il s'agit donc de suivre la structure déja existante au sein du code pour réaliser le travail. C'est pour cette raison que l'issue a été étiquetée "débutant". #### Enrichissement de dictionnaire Khal étant très structuré, il faut renseigner le dictionnaire qui recense les informations à récupérer. Dans la méthode de recherche de configuration `find_configuration_file()`, nous signifions que nous désirons ajouter une section `theme` au dictionnaire principal en enrichissant `fdict`. ```python fdict = {'timezone': is_timezone, 'timedelta': is_timedelta, 'expand_path': expand_path, 'expand_db_path': expand_db_path, 'weeknumbers': weeknumber_option, 'monthdisplay': monthdisplay_option, 'color': is_color, 'theme': is_theme } ``` #### Vérification Comme toute entrée utilisateur nous devons la vérifier. Ikhal regroupe les méthodes de vérification dans le fichier `utils.py`. Nous y ajoutons `is_theme`. Cette méthode est appelée par `config_checks` qui parcours l'ensemble des éléments à vérifier. ```python def is_theme(option): option = option.lower() if option in ['dark', 'light']: return 'user' else: raise VdtValueError( "Invalid value '{}' for option 'theme', must be one of " "'dark' or 'light' ".format(option)) ``` Les thèmes valides sont écrits "en dur", tout comme d'autres méthodes de validation du fichier `utils.py`. La question se posera lors de la résolution de l'issue #633 de ne pas utiliser de valeurs codées en dur mais de se référer aux variables contenues dans le thème dynamique. ##### Import de is_theme Nous demandons l'import de cette nouvelle méthode lors du chargement de `settings.py` ```python from .utils import (config_checks, expand_db_path, expand_path, get_color_from_vdir, get_vdir_type, is_color, is_timedelta, is_timezone, weeknumber_option, monthdisplay_option, is_theme) ``` ##### Recherche et traitement de la configuration utilisateur `config_checks( ... )` vérifie qu'une valeur est renseignée dans la configuration et la controle. Dans le cas d'une erreur, khal se rabat sur la valeur par défaut indiquée dans dans `khal.spec` ```python if not config['view']['theme']: config['view']['theme'] = is_theme( config['view']['theme']) ``` #### Documentation `khal.spec` contribue à la génération de la documentation, aussi une légère reformulation des commentaires est réalisée. La documentation du fichier de configuration est également enrichie d'un exemple. Une documentation plus complète a été envisagée sous la forme d'ascii art mais celle-ce n'a pas été inclue dans la PR pour plusieurs raisons - L'issue concerné est plutot la #633 - L'ensemble des variables de couleurs n'a pas encore été balayé - A l'usage il semble plus pertinent de travailler sur des images ```python # ikhal screen # +header----------------------------------------- # | dayname # |mon # | # | td date header focused/selected # |th # | # | # |name # | # | # | # +footer------------------------------------------ # new event screen # +header-------------------- # | # |Title: edit # |< calendars > # | # |Location: edit/edit focused # |Categories: edit/edit focused # |Description: edit/edit focused # |[ ] Alldays # |From: edit/edit focused/edition validated # |To: edit/edit focused/edition validated # |[ ] Repeat: < weekly > every:1 # | <list> # | # --------------------------- ``` #### Conclusion Une pull request documentée a été réalisée avec cette proposition. Le point concernant le parcours de thème pour l'issue #633 est cité en commentaire. car celle-ci implique la vérification potentielle de soixantes valeurs de couleurs et de typage de police. \pagebreak ### Issue 866: Effectuer les suppressions sans quitter le mode interactif #### Origine **https://github.com/pimutils/khal/issues/866** Une demande d'ajout dction qui est passée par pas moins de 5 issues entre 2016 et maintenant. Certains utilisateurs voudraient pouvoir appliquer les suppressions d'evenements sans quitter Ikhal. #### Principe Le comportement normal d'Ikhal est de marquer les évenements pour suppression puis d'appliquer les changements à sa fermeture. Le but est de résoudre cette contrainte. Geier a proposé dans une des issues d'imiter le fonctionnement de mutt et d'assigner une touche qui se chargerait d'enregistrer les suppressions. Dans mutt, cela peut être accomplis avec la touche `$` . #### Étude Parmis les pistes évoquées par Geier, nous avons suivi celle de mutt, Pour ce faire nous avons défini un nouveau contrôle lié à la touche `$` dans le fichier `khal.spec`. Celui-ci a été nommé `cleanup`, en rapport avec la fonction qu'il permet d'appeler. Fichier settings/khal.spec ``` #cleanup deleted event cleanup = force_list(default=list('$')) ``` La méthode `keypress` elle, se sert des contrôles définis dans le `khal.spec`, pour effectuer des actions. Ici, à la pression de la touche `$`, on appelle `cleanup`. ```python def keypress(self, size, key): prev_shown = self._eventshown self._eventshown = False self.clear_event_view() if key in self._conf['keybindings']['new']: self.new(self.focus_date, None) key = None elif key in self._conf['keybindings']['cleanup']: self.pane.cleanup(None) key = None [...] ``` C'est la méthode appelée lors de la fermeture d'Ikhal pour supprimer les évenements qui ont un marqueur de suppression. L'appeler durant l'exécution permet d'inscrire directement les changements sur le disque. ```python def cleanup(self, data): """delete all events marked for deletion""" for part in self._deleted[ALL]: account, href, etag = part.split('\n', 2) self.collection.delete(href, etag, account) for part, rec_id in self._deleted[INSTANCES]: account, href, etag = part.split('\n', 2) event = self.collection.get_event(href, account) event.delete_instance(rec_id) self.collection.update(event) ``` #### Etat actuel Avec les modifications actuelles il est possible d'enregistrer les modifications sur le disque mais il reste à trouver une solution pour rafraîchir l'écran : en effet l'interface montre toujours les évenements marqués pour suppression, ce qui inclu potentiellement de modifier la fonction `cleanup`. En conclusion, il faudra trouver une solution à ce dernier problème, avant de proposer une réponse. ## Conclusion ### Nouvelles connaissances acquises S'intéresser à **khal** a été une source importante d'approfondissement de nos connaissances , notamment en ce qui concerne l'univers **python**: #### Techniques - Test unitaires avec `py.test` - Test de versions de dépendances avec `tox` - Nous avons découvert les joies du debuggage, notamment avec `pdb`, `ipdb` et `pudb` - Perfectionnement dans l'utilisation de git - `git reflog` - `git bisect` - `git fetch` Cela a également l'occasion de découvrir l'existence de bibliothèques python: - `datetime` pour manipuler les objets relatifs au temps - `py-tz` pour manipuler les timezones - `click` pour gérer très efficacement les arguments passés en ligne de commande - `configobj` pour gérer très simplement et efficacement des fichiers de configuration ### Points durs rencontrés #### Blocages La confrontation avec des blocages dans le code n'a pas toujours été un exercice facile, surtout lorsqu'il est identifié tardivement dans le l'implémentation d'une issue. Ces étapes de développement ont été des périodes de questionnement sur la pertinence du choix de l'issue à résoudre. Quelques interrogations sur notre efficacité sur certains sujets demeurent. (changer ou pas de sujet). Toutefois cela a été un apprentissage humain instructif. #### Retours d'expérience d'utilisateurs variables Le débroussaillage des issues et des contributions a été un domaine que nous ne connaissions pas. Cela a été une difficulté qui s'est cummulée aux autres (aisance dans python, dans l'anglais ...) mais qui nous a aussi permis d'identifier l'importance d'une communauté d'utilisateurs contributeurs capables de communication inclusive. #### Apparition de bugs en amont Il est arrivé à deux reprises que des bugs apparaissent sur des dépendances utlisées par le logiciel. Par chance ils ont été résolus par les mainteneurs de ces autres projets. Cela nous aura permis de découvrir l'importance du choix des dépendances. #### Rythme des échanges Le rythme des échanges nous a parfois surpris. En cause la taille modeste du projet. Les échanges avec l'équipe ont pu prendre un certain temps et nous nous sommes parfois sentis bloqués. ### Conclusion Nous avons eu l'occasion d'appréhender l'énergie et le temps offert par les bénévoles dans les projets open source. L'apprentissage par la pratique va nous permettre de mieux dimensionner et identifer nos contributions futures. La découverte de nouveaux outils (test automatique, débugueur ... ) a été formatrice et nous a ouvert de nouveaux horizons. L'organisation **Khalzone** va être conservée pour nous permettre de contribuer de manière collégiale à ce projet. Il est également prévu d'y inviter une connaissance qui découvre l'opensource et l'un de nous a été accepté comme mainteneur du projet **Khal**.

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully