Python Forum

Full Version: question about changing the string value of a list element
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
so im still building this reminder app. It's got two parts. I need help perfecting it. Basically my app can generate reminders about events/tasks, save them, view them, delete them etc. One of the pieces of information that i store is send status. Because this part of the app will run every time you turn your PC you obviously don't want to send the same reminder twice in a day. Now when it is a single event it is pretty simple, simply change the value of the string in the appropriate cell from No to Yes. the problem is with recurring events. For send dates of recurring events i basically make a list from start date to end date setting the appropriate amount of days between each reminder and then generate the dates that way. Now that means that when a reminder is sent i have to get the index of the date from the send dates list, then use that index to change the send status list element from No to Yes. I tried using replace method didn't work, says index out of range. I tried getting the current date, finding its index in the send date list. Then use that index number to alter the send status list element from "No", to "Yes". Can anyone help please?
EDIT: a part of my code follows:



    if sent:
        for ent in data:
            for date in ent["send date"]:
                if date==todays_date:
                    ind = ent["send date"].index(todays_date)
                    del ent["send status"][ind]
                    ent["send status"].insert(ind,"Yes")
                    self.save_csv_file(self.CSV_FILE, data)
so at the beginning of this function i declare sent as False. i read the csv file into the variable data and check if the day's date exists in the send dates. If so a pop up asks if you want to send the reminder. If the user approves then the reminder is sent and the sent variable is changed to True in order to run the if block i posted above. So then i loop through the send dates as you can see, find the index of the day's date, delete the send status on that index and insert a yes in the same index, finally i call my save function. I tried it, then opened the csv file in excel to see if it worked but the list was still populated only by No.
How about add a last sent field to your events. Whenever you send a notification you update the last sent field. When you start the program and you see there is an event to send, check if the last sent was not today before sending the notification.
don't manipulate ent["send date"] while iterating over it
Compare

spam=[1, 1, 2]
for foo in spam:
    if foo == 1:
        idx = spam.index(1)
        del spam[idx]
print(spam)

spam = [1, 1, 2]
spam = [foo for foo in spam if foo!=1]
print(spam)
Output:
[1, 2] [2]
Here's a quick stab at using a last sent field. I even made the schedule serializable!
from datetime import datetime, timedelta, date
import json


DATE_FORMAT = "%Y-%m-%d"


class Event:
    """A sceduled event."""

    def __init__(
        self,
        message: str,
        start_date: date,
        end_date: date | None = None,
        frequency: int = 1,
        last_sent: date | None = None,
    ):
        """Initialize event.

        Arguments:
            message: Message to send
            start_date: When to start sending message.
            end_date: When to stop sending message.
            frequency: Days between sending message.
        """
        self.message = message
        self.start_date = start_date
        self.end_date = end_date or start_date
        self.frequency = max(frequency, 1)
        self.last_sent = last_sent or start_date - timedelta(days=1)

    def send(self, today: date) -> bool:
        """Check if it is time to send the event.  Return True if event has not expired."""
        if today <= self.end_date and self.last_sent < today and (today - self.start_date).days % self.frequency == 0:
            print(self.message)
            self.last_sent = today
        return today < self.end_date

    def __str__(self):
        return f"{self.message}, {self.end_date}, {self.frequency}, {self.end_date}"

    def to_json(self):
        """Return as a dictionary that can be serialized."""
        return {
            "message": self.message,
            "start_date": self.start_date.strftime(DATE_FORMAT),
            "end_date": self.end_date.strftime(DATE_FORMAT),
            "frequency": self.frequency,
            "last_sent": self.last_sent.strftime(DATE_FORMAT),
        }

    @staticmethod
    def from_json(fields: dict):
        """Convert dictionary to an Event."""
        return Event(
            fields["message"],
            datetime.strptime(fields["start_date"], DATE_FORMAT).date(),
            datetime.strptime(fields["end_date"], DATE_FORMAT).date(),
            fields["frequency"],
            datetime.strptime(fields["last_sent"], DATE_FORMAT).date(),
        )


class Schedule:
    """A sequence of events"""

    def __init__(self):
        self.events: list[Event] = []

    def append(self, *events: Event):
        """Add event to schedule."""
        self.events.extend(events)

    def send(self, today: date | None = None):
        """Send events scheduled for today."""
        today = today or date.today()
        self.events = [event for event in self.events if event.send(today)]

    def __len__(self) -> int:
        """Return number of events remaining in schedule."""
        return len(self.events)

    def __str__(self):
        return "\n".join(str(event) for event in self.events)

    def to_json(self):
        """Return list appropriate for serialization."""
        return [event.to_json() for event in self.events]

    @staticmethod
    def from_json(events: list[dict]):
        """Convert list of events to a schedule."""
        schedule = Schedule()
        for event in events:
            schedule.append(Event.from_json(event))
        return schedule


# Make a schedule with some events for testing.
schedule = Schedule()
today = date.today()
schedule.append(
    Event("Todays event", today),
    Event("Reoccurring event", today, today + timedelta(days=3)),
    Event("Every other day event", today, today + timedelta(days=6), frequency=2),
    Event("Tomorrow's event", today + timedelta(days=1)),
    Event("Next week's event", today + timedelta(days=7)),
)
print("The schedule", schedule, sep="\n")

# Run the schedule for 4 days.
for _ in range(4):
    print("\nToday =", today)
    schedule.send(today)
    today = today + timedelta(days=1)

# Save to file
with open("schedule.json", "w") as file:
    json.dump(schedule.to_json(), file)

# Load from file
with open("schedule.json", "r") as file:
    reloaded_schedule = Schedule.from_json(json.load(file))
print("", "Took a break.  Saved file and restored.  Remaining events", reloaded_schedule, sep="\n")

# Run until the schedule is empty.
while len(reloaded_schedule) > 0:
    print("\nToday =", today)
    reloaded_schedule.send(today)
    today = today + timedelta(days=1)
When I run, it prints a list of scheduled events. Some events are reoccurring, and some just run once, but all the events are the same type.
Output:
The schedule Todays event, 2025-02-07, 1, 2025-02-07 Reoccurring event, 2025-02-10, 1, 2025-02-10 Every other day event, 2025-02-13, 2, 2025-02-13 Tomorrow's event, 2025-02-08, 1, 2025-02-08 Next week's event, 2025-02-14, 1, 2025-02-14
Then I run the schedule for 4 days and close the application,
Output:
Today = 2025-02-07 Todays event Reoccurring event Every other day event Today = 2025-02-08 Reoccurring event Tomorrow's event Today = 2025-02-09 Reoccurring event Every other day event Today = 2025-02-10 Reoccurring event
When closing the app it saves the schedule to a file. When starting the app it loads the schedule from the file. These are the remaining events on the schedule.
Output:
Took a break. Saved file and restored. Remaining events Every other day event, 2025-02-13, 2, 2025-02-13 Next week's event, 2025-02-14, 1, 2025-02-14
The schedule is run until all events expire.
Output:
Today = 2025-02-11 Every other day event Today = 2025-02-12 Today = 2025-02-13 Every other day event Today = 2025-02-14 Next week's event
There are different ways to make classes serializable, but I wanted to use json because you can read the files, and I didn't want to use any modules that have to be installed (pydantic for example).
(Feb-07-2025, 04:33 PM)deanhystad Wrote: [ -> ]How about add a last sent field to your events. Whenever you send a notification you update the last sent field. When you start the program and you see there is an event to send, check if the last sent was not today before sending the notification.

hey again, i saw your post below but i don't think i can use that code. can you elaborate on this post? Maybe send me some code as example?