From 6dfc1a1824b7da065eebf1ceb6eb8b67c6d49e9b Mon Sep 17 00:00:00 2001 From: biniabokouame Date: Wed, 4 Dec 2024 14:42:09 +0100 Subject: [PATCH 1/4] fix_1341 --- bin/ikhal | 9 ++++++- bin/khal | 9 +++++-- khal/cli.py | 17 ++++++++++++ khal/controllers.py | 59 +++++++++++++++++++++++++++-------------- khal/icalendar.py | 10 +++++++ khal/khalendar/event.py | 6 +++-- khal/utils.py | 41 ++++++++++++++++++++++++---- myenv/bin/python | 1 + myenv/bin/python3 | 1 + myenv/bin/python3.11 | 1 + myenv/lib64 | 1 + myenv/pyvenv.cfg | 5 ++++ 12 files changed, 130 insertions(+), 30 deletions(-) create mode 120000 myenv/bin/python create mode 120000 myenv/bin/python3 create mode 120000 myenv/bin/python3.11 create mode 120000 myenv/lib64 create mode 100644 myenv/pyvenv.cfg diff --git a/bin/ikhal b/bin/ikhal index 45ed5d605..031828424 100644 --- a/bin/ikhal +++ b/bin/ikhal @@ -1,5 +1,12 @@ #!/usr/bin/env python + +import sys +import os + +# Add the project root to PYTHONPATH +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) + from khal.cli import main_ikhal if __name__ == "__main__": - main_ikhal() + main_ikhal() \ No newline at end of file diff --git a/bin/khal b/bin/khal index 425af7acd..f7390055b 100644 --- a/bin/khal +++ b/bin/khal @@ -1,5 +1,10 @@ -#!/usr/bin/env python +import sys +import os + +# Add the project root to PYTHONPATH +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) + from khal.cli import main_khal if __name__ == "__main__": - main_khal() + main_khal() \ No newline at end of file diff --git a/khal/cli.py b/khal/cli.py index 51ad78b92..56f9bf602 100644 --- a/khal/cli.py +++ b/khal/cli.py @@ -29,6 +29,7 @@ import click import click_log +from .icalendar import extract_rrule_details from . import controllers, plugins from .cli_utils import ( @@ -61,6 +62,15 @@ def setproctitle(_): events_option = click.option('--events', default=None, type=int, help='How many events to include.') dates_arg = click.argument('dates', nargs=-1) +#formater les événements +def format_event_with_recurrence(event, format_str): + """ + Format an event, replacing {repeat} or {repeat-details} with recurrence details. + """ + if "{repeat}" in format_str or "{repeat-details}" in format_str: + recurrence = extract_rrule_details(event.raw) + format_str = format_str.replace("{repeat}", recurrence).replace("{repeat-details}", recurrence) + return format_str def time_args(f): return dates_arg(events_option(week_option(days_option(f)))) @@ -193,6 +203,13 @@ def klist(ctx, include_calendar, exclude_calendar, env={"calendars": ctx.obj['conf']['calendars']}, json=json ) + if event_column: + formatted_events = [ + format_event_with_recurrence(event, format) for event in event_column + ] + click.echo('\n'.join(formatted_events)) + else: + logger.debug('No events found') if event_column: click.echo('\n'.join(event_column)) else: diff --git a/khal/controllers.py b/khal/controllers.py index abe36e9d7..90f7e9211 100644 --- a/khal/controllers.py +++ b/khal/controllers.py @@ -326,17 +326,34 @@ def khal_list( def new_interactive(collection, calendar_name, conf, info, location=None, categories=None, repeat=None, until=None, alarms=None, format=None, json=None, env=None, url=None): - info: EventCreationTypes - try: - info = parse_datetime.eventinfofstr( - info, conf['locale'], - default_event_duration=conf['default']['default_event_duration'], - default_dayevent_duration=conf['default']['default_dayevent_duration'], - adjust_reasonably=True, - ) - except DateTimeParseError: + # Vérifiez si info est une chaîne ou un dictionnaire, puis initialisez en conséquence + if isinstance(info, dict): + info_string = f"{info.get('summary', '')} {info.get('datetime_range', '')}" + elif isinstance(info, str): + info_string = info + info = {} # Réinitialisez `info` en dictionnaire après conversion + else: + info_string = "" info = {} + while True: + try: + # Passez une chaîne correctement formatée à `eventinfofstr` + parsed_info = parse_datetime.eventinfofstr( + info_string.strip(), + conf['locale'], + default_event_duration=conf['default']['default_event_duration'], + default_dayevent_duration=conf['default']['default_dayevent_duration'], + adjust_reasonably=True, + ) + info.update(parsed_info) # Mettez à jour `info` avec les données parsées + break # Sortir de la boucle si tout est valide + except DateTimeParseError as e: + echo(f"Error parsing information: {e}. Please correct the fields.") + summary = prompt('summary', default=info.get('summary', '')).strip() + datetime_range = prompt('datetime range', default=info.get('datetime_range', '')).strip() + info_string = f"{summary} {datetime_range}" + while True: summary = info.get('summary') if not summary: @@ -344,7 +361,7 @@ def new_interactive(collection, calendar_name, conf, info, location=None, info['summary'] = prompt('summary', default=summary) if info['summary']: break - echo("a summary is required") + echo("A summary is required.") while True: range_string = None @@ -353,14 +370,16 @@ def new_interactive(collection, calendar_name, conf, info, location=None, end_string = info["dtend"].strftime(conf['locale']['datetimeformat']) range_string = start_string + ' ' + end_string daterange = prompt("datetime range", default=range_string) - start, end, allday = parse_datetime.guessrangefstr( - daterange, conf['locale'], adjust_reasonably=True) - info['dtstart'] = start - info['dtend'] = end - info['allday'] = allday - if info['dtstart'] and info['dtend']: + try: + start, end, allday = parse_datetime.guessrangefstr( + daterange, conf['locale'], adjust_reasonably=True + ) + info['dtstart'] = start + info['dtend'] = end + info['allday'] = allday break - echo("invalid datetime range") + except ValueError: + echo("Invalid datetime range, please try again.") while True: tz = info.get('timezone') or conf['locale']['default_timezone'] @@ -370,9 +389,9 @@ def new_interactive(collection, calendar_name, conf, info, location=None, info['timezone'] = tz break except pytz.UnknownTimeZoneError: - echo("unknown timezone") + echo("Unknown timezone, please enter a valid timezone.") - info['description'] = prompt("description (or 'None')", default=info.get('description')) + info['description'] = prompt("description (or 'None')", default=info.get('description', '')) if info['description'] == 'None': info['description'] = '' @@ -394,7 +413,7 @@ def new_interactive(collection, calendar_name, conf, info, location=None, calendar_name=calendar_name, json=json, ) - echo("event saved") + echo("Event saved.") term_width, _ = get_terminal_size() edit_event(event, collection, conf['locale'], width=term_width) diff --git a/khal/icalendar.py b/khal/icalendar.py index 39e6eda8f..877cc7d51 100644 --- a/khal/icalendar.py +++ b/khal/icalendar.py @@ -38,6 +38,16 @@ logger = logging.getLogger('khal') +def extract_rrule_details(vevent): + """ + Extract recurrence rule (RRULE) details from an event. + Returns a string representation of the rule for display. + """ + rrule = vevent.get('RRULE') + if not rrule: + return "No recurrence" + return rrule.to_ical().decode() + def split_ics(ics: str, random_uid: bool=False, default_timezone=None) -> List: """split an ics string into several according to VEVENT's UIDs diff --git a/khal/khalendar/event.py b/khal/khalendar/event.py index d300b17d2..9e6210c83 100644 --- a/khal/khalendar/event.py +++ b/khal/khalendar/event.py @@ -39,7 +39,9 @@ from ..icalendar import cal_from_ics, delete_instance, invalid_timezone from ..parse_datetime import timedelta2str from ..plugins import FORMATTERS -from ..utils import generate_random_uid, is_aware, to_naive_utc, to_unix_time +from ..utils import generate_random_uid, is_aware, to_naive_utc, to_unix_time +from icalendar import Event as ICalendarEvent +from dateutil.rrule import rrulestr logger = logging.getLogger('khal') @@ -57,7 +59,7 @@ class Event: icalendar standard would have the end date be one day later) """ allday: bool = False - + def __init__(self, vevents: Dict[str, icalendar.Event], locale: LocaleConfiguration, diff --git a/khal/utils.py b/khal/utils.py index 78f525bbd..947805aff 100644 --- a/khal/utils.py +++ b/khal/utils.py @@ -216,17 +216,45 @@ def fmt(rows): CONTENT_ATTRIBUTES = ['start', 'start-long', 'start-date', 'start-date-long', - 'start-time', 'end', 'end-long', 'end-date', 'end-date-long', 'end-time', - 'duration', 'start-full', 'start-long-full', 'start-date-full', - 'start-date-long-full', 'start-time-full', 'end-full', 'end-long-full', - 'end-date-full', 'end-date-long-full', 'end-time-full', 'duration-full', 'start-style', 'end-style', 'to-style', 'start-end-time-style', 'end-necessary', 'end-necessary-long', 'repeat-symbol', 'repeat-pattern', 'title', 'organizer', 'description', 'location', 'all-day', 'categories', - 'uid', 'url', 'calendar', 'calendar-color', 'status', 'cancelled'] + 'uid', 'url', 'calendar', 'calendar-color', 'status', 'cancelled', 'attendees'] + def json_formatter(fields): + """Create a formatter that formats events in JSON.""" + if len(fields) == 1 and fields[0] == 'all': + fields = CONTENT_ATTRIBUTES + + def fmt(rows): + single = isinstance(rows, dict) + if single: + rows = [rows] + + filtered = [] + for row in rows: + row['attendees'] = row.get('attendees', '') # Ajout d'une valeur par défaut + f = dict(filter(lambda e: e[0] in fields and e[0] in CONTENT_ATTRIBUTES, row.items())) + + if f.get('repeat-symbol', '') != '': + f["repeat-symbol"] = f["repeat-symbol"].strip() + if f.get('status', '') != '': + f["status"] = f["status"].strip() + if f.get('cancelled', '') != '': + f["cancelled"] = f["cancelled"].strip() + + filtered.append(f) + + results = [json.dumps(filtered, ensure_ascii=False)] + + if single: + return results[0] + else: + return results + return fmt + """Create a formatter that formats events in JSON.""" if len(fields) == 1 and fields[0] == 'all': @@ -239,7 +267,10 @@ def fmt(rows): filtered = [] for row in rows: + print(f"Processing row: {row}") # Affiche les données brutes + row['attendees'] = row.get('attendees', '') f = dict(filter(lambda e: e[0] in fields and e[0] in CONTENT_ATTRIBUTES, row.items())) + print(f"Filtered row: {f}") # Affiche les données filtrées if f.get('repeat-symbol', '') != '': f["repeat-symbol"] = f["repeat-symbol"].strip() diff --git a/myenv/bin/python b/myenv/bin/python new file mode 120000 index 000000000..b8a0adbbb --- /dev/null +++ b/myenv/bin/python @@ -0,0 +1 @@ +python3 \ No newline at end of file diff --git a/myenv/bin/python3 b/myenv/bin/python3 new file mode 120000 index 000000000..ae65fdaa1 --- /dev/null +++ b/myenv/bin/python3 @@ -0,0 +1 @@ +/usr/bin/python3 \ No newline at end of file diff --git a/myenv/bin/python3.11 b/myenv/bin/python3.11 new file mode 120000 index 000000000..b8a0adbbb --- /dev/null +++ b/myenv/bin/python3.11 @@ -0,0 +1 @@ +python3 \ No newline at end of file diff --git a/myenv/lib64 b/myenv/lib64 new file mode 120000 index 000000000..7951405f8 --- /dev/null +++ b/myenv/lib64 @@ -0,0 +1 @@ +lib \ No newline at end of file diff --git a/myenv/pyvenv.cfg b/myenv/pyvenv.cfg new file mode 100644 index 000000000..6ebfc6387 --- /dev/null +++ b/myenv/pyvenv.cfg @@ -0,0 +1,5 @@ +home = /usr/bin +include-system-site-packages = false +version = 3.11.2 +executable = /usr/bin/python3.11 +command = /usr/bin/python3 -m venv /home/bini/khal/myenv From 1fcf05384679f9e3e38eaf72400e6ac6006bad3e Mon Sep 17 00:00:00 2001 From: biniabokouame Date: Wed, 4 Dec 2024 15:13:57 +0100 Subject: [PATCH 2/4] change new_interactive function --- khal/cli.py | 19 +------------------ khal/icalendar.py | 12 +----------- 2 files changed, 2 insertions(+), 29 deletions(-) diff --git a/khal/cli.py b/khal/cli.py index 56f9bf602..777dcedbe 100644 --- a/khal/cli.py +++ b/khal/cli.py @@ -29,7 +29,6 @@ import click import click_log -from .icalendar import extract_rrule_details from . import controllers, plugins from .cli_utils import ( @@ -62,15 +61,6 @@ def setproctitle(_): events_option = click.option('--events', default=None, type=int, help='How many events to include.') dates_arg = click.argument('dates', nargs=-1) -#formater les événements -def format_event_with_recurrence(event, format_str): - """ - Format an event, replacing {repeat} or {repeat-details} with recurrence details. - """ - if "{repeat}" in format_str or "{repeat-details}" in format_str: - recurrence = extract_rrule_details(event.raw) - format_str = format_str.replace("{repeat}", recurrence).replace("{repeat-details}", recurrence) - return format_str def time_args(f): return dates_arg(events_option(week_option(days_option(f)))) @@ -203,13 +193,6 @@ def klist(ctx, include_calendar, exclude_calendar, env={"calendars": ctx.obj['conf']['calendars']}, json=json ) - if event_column: - formatted_events = [ - format_event_with_recurrence(event, format) for event in event_column - ] - click.echo('\n'.join(formatted_events)) - else: - logger.debug('No events found') if event_column: click.echo('\n'.join(event_column)) else: @@ -583,4 +566,4 @@ def configure(ctx): sys.exit(1) -main_khal, main_ikhal = cli, interactive_cli +main_khal, main_ikhal = cli, interactive_cli \ No newline at end of file diff --git a/khal/icalendar.py b/khal/icalendar.py index 877cc7d51..97c521423 100644 --- a/khal/icalendar.py +++ b/khal/icalendar.py @@ -38,16 +38,6 @@ logger = logging.getLogger('khal') -def extract_rrule_details(vevent): - """ - Extract recurrence rule (RRULE) details from an event. - Returns a string representation of the rule for display. - """ - rrule = vevent.get('RRULE') - if not rrule: - return "No recurrence" - return rrule.to_ical().decode() - def split_ics(ics: str, random_uid: bool=False, default_timezone=None) -> List: """split an ics string into several according to VEVENT's UIDs @@ -556,4 +546,4 @@ def cal_from_ics(ics: str) -> icalendar.Calendar: icalendar.vUTCOffset.ignore_exceptions = False else: raise - return cal + return cal \ No newline at end of file From 60d871d2ea35f918e6af4c1a74e722fa0549290a Mon Sep 17 00:00:00 2001 From: biniabokouame Date: Wed, 4 Dec 2024 15:19:13 +0100 Subject: [PATCH 3/4] change new_interactive function --- bin/ikhal | 11 ++--------- bin/khal | 11 +++-------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/bin/ikhal b/bin/ikhal index 031828424..5990fa1a6 100644 --- a/bin/ikhal +++ b/bin/ikhal @@ -1,12 +1,5 @@ #!/usr/bin/env python - -import sys -import os - -# Add the project root to PYTHONPATH -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) - from khal.cli import main_ikhal -if __name__ == "__main__": - main_ikhal() \ No newline at end of file +if _name_ == "_main_": +    main_ikhal() \ No newline at end of file diff --git a/bin/khal b/bin/khal index f7390055b..568bd504e 100644 --- a/bin/khal +++ b/bin/khal @@ -1,10 +1,5 @@ -import sys -import os - -# Add the project root to PYTHONPATH -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) - +#!/usr/bin/env python from khal.cli import main_khal -if __name__ == "__main__": - main_khal() \ No newline at end of file +if _name_ == "_main_": +    main_khal() \ No newline at end of file From 110d5fe141b4b49bf0346891b0a796316df59f5b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 4 Dec 2024 15:39:42 +0000 Subject: [PATCH 4/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- bin/ikhal | 2 +- bin/khal | 2 +- khal/cli.py | 2 +- khal/icalendar.py | 2 +- khal/khalendar/event.py | 6 ++---- khal/utils.py | 2 +- 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/bin/ikhal b/bin/ikhal index 5990fa1a6..2e92d53b0 100644 --- a/bin/ikhal +++ b/bin/ikhal @@ -2,4 +2,4 @@ from khal.cli import main_ikhal if _name_ == "_main_": -    main_ikhal() \ No newline at end of file +    main_ikhal() diff --git a/bin/khal b/bin/khal index 568bd504e..1dbbc973a 100644 --- a/bin/khal +++ b/bin/khal @@ -2,4 +2,4 @@ from khal.cli import main_khal if _name_ == "_main_": -    main_khal() \ No newline at end of file +    main_khal() diff --git a/khal/cli.py b/khal/cli.py index 777dcedbe..51ad78b92 100644 --- a/khal/cli.py +++ b/khal/cli.py @@ -566,4 +566,4 @@ def configure(ctx): sys.exit(1) -main_khal, main_ikhal = cli, interactive_cli \ No newline at end of file +main_khal, main_ikhal = cli, interactive_cli diff --git a/khal/icalendar.py b/khal/icalendar.py index 97c521423..39e6eda8f 100644 --- a/khal/icalendar.py +++ b/khal/icalendar.py @@ -546,4 +546,4 @@ def cal_from_ics(ics: str) -> icalendar.Calendar: icalendar.vUTCOffset.ignore_exceptions = False else: raise - return cal \ No newline at end of file + return cal diff --git a/khal/khalendar/event.py b/khal/khalendar/event.py index 9e6210c83..d300b17d2 100644 --- a/khal/khalendar/event.py +++ b/khal/khalendar/event.py @@ -39,9 +39,7 @@ from ..icalendar import cal_from_ics, delete_instance, invalid_timezone from ..parse_datetime import timedelta2str from ..plugins import FORMATTERS -from ..utils import generate_random_uid, is_aware, to_naive_utc, to_unix_time -from icalendar import Event as ICalendarEvent -from dateutil.rrule import rrulestr +from ..utils import generate_random_uid, is_aware, to_naive_utc, to_unix_time logger = logging.getLogger('khal') @@ -59,7 +57,7 @@ class Event: icalendar standard would have the end date be one day later) """ allday: bool = False - + def __init__(self, vevents: Dict[str, icalendar.Event], locale: LocaleConfiguration, diff --git a/khal/utils.py b/khal/utils.py index 947805aff..df7fd7664 100644 --- a/khal/utils.py +++ b/khal/utils.py @@ -220,7 +220,7 @@ def fmt(rows): 'end-necessary', 'end-necessary-long', 'repeat-symbol', 'repeat-pattern', 'title', 'organizer', 'description', 'location', 'all-day', 'categories', 'uid', 'url', 'calendar', 'calendar-color', 'status', 'cancelled', 'attendees'] - + def json_formatter(fields):