how dynamically update listbox entry in Tkinter? - python

I am trying to update a listbox line, based on a condition, but get this error:
_tkinter.TclError: bad listbox index "Wednesday 15 April 2020 ": must be active, anchor, end, #x,y, or a number
These are the script lines. I get the same error when I use i, or tk.END with listboxMain.delete
for i, dt in enumerate(daterange(date1, date2)):
holiday = us_holidays.get(dt)
if not holiday:
holiday = ""
day, date, month, year = dt.strftime('%A %d %B %Y').split()
line = f'{day:10s} {date} {month:>10s} {year:>7} {holiday}'
if (datetime.date.today() - dt).days == 0:
TODAY_INDEX = i
listboxMain.insert(tk.END, line)
for b in list_birthdays:
if b == dt:
listboxMain.delete(i, line) <====== Error is here.
listboxMain.insert(i, line + " Birthday of ")
listboxMain.itemconfig(i, {'bg': '#999966'})
listboxMain.itemconfig(i, {'fg': '#000066'})
break
listboxMain.itemconfig(TODAY_INDEX, {'bg': '#cc9900'})
listboxMain.itemconfig(TODAY_INDEX, {'fg': '#000099'})

Related

Input string recognise text and return date parse

I have a string input where text contains data as "monday of next month" or "4 days before new year" need to convert into dates as suppose today is 25/11/2020, so next month monday is on 07/12/2020, so how should i do it in python (i've tried using datetime, dateutil but didn't help')
next week saturday
4 days before new year
3 days after new year
second wednesday of next month
i need output as
05/12/20
28/12/20
03/01/21
09/12/21
tried reading docs but didn't help can anyone shed some light on it.
here's my python code.
from datetime import datetime, timedelta
from dateutil import parser
from dateparser.search import search_dates
# Create your views here.
def converter_view(request):
form = DateStringForm()
if request.method == 'POST':
form = DateStringForm(request.POST)
if form.is_valid():
input_string = form.cleaned_data['string_date']
list_of_dates = []
if input_string.lower() == "today":
data = datetime.now()
list_of_dates.append(data.strftime('%d/%m/%Y'))
elif input_string.lower() == "tomorrow":
data = datetime.now() + timedelta(1)
list_of_dates.append(data.strftime('%d/%m/%Y'))
elif input_string.lower() == "yesterday":
data = datetime.now() - timedelta(1)
list_of_dates.append(data.strftime('%d/%m/%Y'))
else:
try:
# Using search_dates method we were extracting the keywords related to date, day or month
# So search_dates is going to return a "list of tuple" where 0th index is string and 1st is datetime
data = search_dates(input_string)
except Exception as msg:
print('Exception :', msg)
else:
try:
for i in data:
# So as we require to convert that date back in string format, we parse the extracted data in data
# where parser.parse() is taking 0th index which is string, and converting it to date and by using
# strftime function we get the required format
list_of_dates.append(parser.parse(i[0]).strftime('%d/%m/%Y'))
print(list_of_dates)
except TypeError as msg:
print("String does not contain any day or dates")
values = DateStringConvert(string_date=input_string, date=list_of_dates)
values.save()
return HttpResponseRedirect('/dateconverter')
return render(request, 'DateTimeConverter/index.html', {'form':form})
It's impossible to facilitate all possible combinations and pieces of text. However, you can cover most cases with a few basic patterns.
import re
import datetime
queries = [
"next week saturday",
"4 days before new year",
"3 days after new year",
"second wednesday of next month",
]
def parse_relative_string_date(text: str, start_date: datetime.datetime = datetime.datetime.now()) -> datetime.datetime:
def _next_week(weekday: str):
weekdays = {
"monday": 0,
"tuesday": 1,
"wednesday": 2,
"thursday": 3,
"friday": 4,
"saturday": 5,
"sunday": 6,
}
next_week = start_date + datetime.timedelta(weeks=1)
return next_week + datetime.timedelta((weekdays[weekday.lower()] - next_week.weekday()) % 7)
def _new_year(n_days: str, direction: str):
new_years = datetime.datetime(year=start_date.year + 1, month=1, day=1)
directions = {
"before": -1,
"after": 1,
}
return new_years + datetime.timedelta(directions[direction.lower()] * int(n_days))
patterns = {
r"next week (?P<weekday>\w+)": _next_week,
r"(?P<n_days>\d+) days (?P<direction>\w+) new year": _new_year,
# Add more patterns here
}
for pattern, callback in patterns.items():
found = re.search(pattern, text)
if found is not None:
return callback(**dict(found.groupdict()))
for query in queries:
print(parse_relative_string_date(query))

tkinter - Can a radio button control multiple variables?

I am writing a calendar program using the tkinter module and clicking on each day on the grid will print out the current day's date (month/day/year). However, I also want to add another section at the bottom that will show what day of the year it is. Like this:
For example, January 1, 2020 would be the first day of the year, March 20 will be the 80th day of the year, etc. I want my radio buttons to be able to control both of these variables, the date as a string, and the day of the year as an integer. Is this possible?
strDate = StringVar()
labelDate = Label(frameDay, textvariable=strDate, width=28,
font=("Consolas", "15", "bold")).grid(row=1, column=1)
# Creating the calendar grid
while day <= self.returnMaxDay():
currentDay = Date(self.month, day, self.year)
radDay = Radiobutton(frameCalendar, text=str(day),
font=("Consolas", "15", "bold"), indicatoron=0, width=4, height=1,
variable=strDate, value=str(currentDay.returnDayName()) + ", "
+ str(currentDay.returnMonthName()) + " "
+ str(day) + ", " + str(currentDay.year))
radDay.grid(row=row, column=weekDay)
day += 1
weekDay += 1
if weekDay == 7:
row += 1
weekDay = 0
labelDayOfYear = Label(window, text=str(self.dayOfYear()), font=("Consolas", "20")).pack()
It is simple example which uses command= in Radiobutton to run function which changes text it three Labels.
Normally command= expect function's name without () and arguments so I use lambda to assing function with arguments.
command=lambda d=current_day:on_click(d))
I also use d=current_day to create new variable d for every function. Without d=current_day all functions would use reference to the same variable current_day and all functions would use the same (last) value in current_day.
import tkinter as tk
import datetime
# --- functions ---
def on_click(value):
print(value)
label_date['text'] = value.strftime('%a, %b %d, %Y')
label_day['text'] = value.strftime('Day: %d')
label_weekday['text'] = value.strftime('Weekday: %a')
# --- main ---
root = tk.Tk()
radiobutton_var = tk.StringVar()
year = 2020
month = 4
row = 0
for day in range(1, 32):
try:
current_day = datetime.datetime(year, month, day)
date_str = current_day.strftime('%a, %m %d, %Y')
weekday = current_day.weekday()
radiobutton_day = tk.Radiobutton(root,
text=str(day),
indicatoron=0,
variable=radiobutton_var,
value=date_str,
#value=day,
command=lambda x=current_day:on_click(x))
radiobutton_day.grid(row=row, column=weekday, sticky='we')
if weekday == 6:
row += 1
radiobutton_day['bg'] = '#faa'
except ValueError as ex:
print(ex)
break
label_date = tk.Label(root, text='?')
label_date.grid(row=10, columnspan=10)
label_day = tk.Label(root, text='Day: ?')
label_day.grid(row=11, columnspan=10)
label_weekday = tk.Label(root, text='Weekday: ?')
label_weekday.grid(row=12, columnspan=10)
root.mainloop()
BTW: I use datetime to generate dates and try/except to catch error when date is incorrect.
I also use strftime to format date - see more on page strftime.org

Difficulties with implementing persian calendar rules with Python

I am writing a code that somehow resembles the Persian calendar. there are 3 drop down lists for year, month and day. Here are the rules I'd like to include:
Months 1 to 6 have 31 days
Months 7 to 11 have 30 days
Month 12 has 29 days every 4 years
12th month has 30 days (leap year)
If the user chooses one of the (1 - 2 - 3 - 4 - 5 - 6) months, the drop down list for days must have 31 days.
If the user chooses one of the (7 - 8 - 9 - 10 - 11 ) months, the drop down list for days must have 30 days.
If the user chooses the 12th month, the drop down list for days must have 29 days.
If the user chooses one of (1375 – 1379 – 1383 – 1387 – 1391 – 1395) year and if he chooses the 12th month, the drop down list for days must have 30 days.
Here is the code I have written so far but my code doesn't work, please help me with it.
from tkinter import *
x=StringVar()
def ok():
if months == months[0:5]:
x = dayoptions1
if months == months[6:10]:
x = dayoptions2
if months == months[11] and years == 1375 or 1379 or 1383 or 1387 or 1391 or 1395:
x = dayoptions3
root = Tk()
label1 = Label(root, text="year",width=15)
label1.grid(row=0, column=0)
yearoptions = ["1397", "1396","1395","1394","1393","1392","1391","1390","1389","1388","1387","1386","1385","1384","1383","1382","1381","1380","1379","1378","1377","1376","1375"]
yearvariable = StringVar(root)
yearvariable.set(yearoptions[0])
years = OptionMenu(root, yearvariable, *yearoptions)
years.grid(row=0,column=1,padx=5, pady=5)
label2 = Label(root, text="month",width=15)
label2.grid(row=0, column=2)
monthoptions = ["1", "2","3","4","5","6","7","8","9","10","11","12"]
monthvariable = StringVar(root)
monthvariable.set(monthoptions[0])
months = OptionMenu(root, monthvariable, *monthoptions)
months.grid(row=0,column=3,padx=5, pady=5)
label1 = Label(root, text="day",width=15)
label1.grid(row=0, column=4)
dayoptions1 = ["1", "2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31"]
dayoptions2 = ["1", "2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30"]
dayoptions3 = ["1", "2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29"]
dayvariable = StringVar(root)
dayvariable.set("1")
days = OptionMenu(root, dayvariable, *x)
days.grid(row=0,column=5,padx=5, pady=5)
root.mainloop()
Okay I don't tkinter, so I wrote a function but it works. Days depends on what month & year user choose. So scenario is, user choose 1383 - 12 (Year 1383 of Month 12), you need to find if 1383 is a leap year and then fill up the day list with 30 days, or else it would be 29 days. If use choose between month 1 to 6, fill the array with 31 days and the rest of the month has 30 days. I have written a short helper function to check this out and I think it works.
def persian_calender():
user_input = input("year - month:: ")
date_list = user_input.split("-")
leap_year = [1375, 1379 ,1383, 1387 ,1391 ,1395]
year = int(date_list[0])
month = int (date_list[1])
if year in leap_year:
is_leap = True
else:
is_leap = False
if month >= 1 and month <= 6:
number_of_days = "31"
elif month >= 7 and month <= 11:
number_of_days = "30"
else:
if is_leap:
number_of_days = "30"
else:
number_of_days = "29"
print ("Year: " + date_list[0] + " Month: "+ date_list[1] + " Days: "
+ number_of_days)
Check the code file in here
Hope it helps. Cheers!
[Edit 2]
You wrote a helper function Ok that finds out what month it is. Instead writing your list manually, just declare the number of days in there. When you want to or it's time to fill up the drop down list of days, run and fill up the list with equivalent number of days. Do I make sense?!

Extract Date and Currency value(separated by comma) from file

Objective:
Extract String data, Currency value , [type of currency] and date.
Content of file:
[["1234567890","Your previous month subscription point is <RS|$|QR|#> 5,200.33.Your current month month subscription point is <RS|$|QR|#> 1,15,200.33, Last Year total point earned <RS|$|QR|#> 5589965.26 and point lost in game is <RS|$|QR|#> 11520 your this year subscription will expire on 19-04-2013. 9. Back"],["1234567890","Your previous month subscription point is <RS|$|QR|#> 5,200.33.Your current month month subscription point is <RS|$|QR|#> 1,15,200.33, Last Year total point earned <RS|$|QR|#> 5589965.26 and point lost in game is <RS|$|QR|#> 11520 your this year subscription will expire on 19-04-2013. 9. Back"]]
What I have done so far:
def read_file():
fp = open('D:\\ReadData2.txt', 'rb')
content = fp.read()
data = eval(content)
l1 = ["%s" % x[1] for x in data]
return l1
def check_currency(l2):
import re
for i in range(l2.__len__()):
newstr2 = l2[i]
val_currency = []
val_currency.extend(re.findall(r'([+-]?\d+(?:\,\d+)*?\d+(?:\.\d+)?)',newstr2))
print " List %s " % val_currency
for i in range(len(val_currency)):
val2 = val_currency[i]
remove_commas = re.compile(r',(?=\d+)*?')
val3 = remove_commas.sub('', val2)
print val3
if __name__=="__main__":main()
EDIT UDP
I am able to extract the currency value but with the currency of -ve value are conflicting with date format(dd-mm-yyyy). And during extracting string value its also extracting [.|,|] how not to read these characters.
Ouput of check_currency:
>List ['5,200.33', '1,15,200.33', '5589965.26', '11520', '19', '-04', '-2013']
>5200.33
>115200.33
>5589965.26
>11520
>19
>-04
>-2013
Expected Ouput of check_currency:
>List ['5,200.33', '1,15,200.33', '5589965.26', '11520']
>5200.33
>115200.33
>5589965.26
>11520
I added this <RS|$|QR|#>\s* at the first part of your regular expression so as
to be used as prefix for the currency value you want to match.
You can change your code to this one:
def check_currency(l2):
import re
for i in range(l2.__len__()):
newstr2 = l2[i]
val_currency = []
val_currency.extend(re.findall(r'<RS|$|QR|#>\s*([+-]?\d+(?:\,\d+)*?\d+(?:\.\d+)?)',newstr2))
# skip empty strings and remove comma characters
val_currency = [v.replace(',', '') for v in val_currency if v]
print " List %s " % val_currency$
for i in range(len(val_currency)):
val2 = val_currency[i]
remove_commas = re.compile(r',(?=\d+)*?')
val3 = remove_commas.sub('', val2)
print val3
Output:
List ['5200.33', '115200.33', '5589965.26', '11520']
5200.33
115200.33
5589965.26
11520
aditions in the code:
val_currency.extend(re.findall(r'<RS|$|QR|#>\s*([+-]?\d+(?:\,\d+)*?\d+(?:\.\d+)?)',newstr2))
val_currency = [v.replace(',', '') for v in val_currency if v]

IMDBpy getting screen information

import imdb
ia = imdb.IMDb()
avatar = ia.get_movie("0120667")
ia.update(avatar, 'business')
print avatar['business']
That returns the whole list of gross, aswell as screenings for each country. But how do i get out the screening information only? And for only 1 country. in this example the information i want to get is (USA) (10 July 2005) (3,602 Screens)
import imdb
import re
ia = imdb.IMDb()
avatar = ia.get_movie("0120667")
ia.update(avatar, 'business')
opening_weekends = avatar['business']['opening weekend']
def parseDate(date):
result = {}
if re.match(".*\d{4}$", date):
result['year'] = date[-4:]
m = re.match(".*(?P<month>January|February|March|April|May|June|July|"
"August|September|October|November|December).*", date, re.I)
if m:
result['month'] = m.group('month').lower()
# try to grab date too then
daymatch = re.match("^(?P<day>\d{1,2}).*", date)
if daymatch:
result['day'] = daymatch.group('day')
return result
def parseBudget(amount):
"""
assumptions:
- currency is always before the number
- no fractions
"""
# find index first number
for i in range(len(amount)):
if amount[i] in "0123456789":
amount_idx = i
break
currency = amount[:amount_idx].strip()
amount = re.sub("\D", "", amount[amount_idx:])
return amount, currency
def parseWeekendGross(gross_text):
g = gross_text.split(' (')
if not len(g) == 4:
return ""
amount, currency = parseBudget(g[0])
country = g[1].lstrip('(').rstrip(')')
date = parseDate(g[2].lstrip('(').rstrip(')'))
day, month, year = date['day'], date['month'], date['year']
screens = re.sub("\D", "", g[3])
if not screens:
screens = "''"
return amount, currency, country, day, month, year, screens
for entry in opening_weekends:
amount, currency, country, day, month, year, screens = parseWeekendGross(entry)
if country == "USA":
print("Country: %s" % country)
print("Date: %s %s %s" % (day, month, year))
print("Screens: %s" % screens)
break
The above code gives me the following result:
Country: USA
Date: 10 july 2005
Screens: 3602
The functions to parse the data are copied from this project: pyIRDG

Categories

Resources