Python Forum
timedelta object cannot be interpreted as integer
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
timedelta object cannot be interpreted as integer
#1
The purpose of the code is to parse a text file (output from another program) which contains two date strings and a grade (string), check the interval between the two dates, and classify them accordingly. It also should prompt the user to recheck the dates if the interval exceeds 2 years.

The relevent code snippet is:
from datetime import datetime, timedelta

#process values from textfile
class readtextfile(object):

    def __init__(self,birth_date, exam_date,expiry_date,certification_status):
        self.birth_date = (birth_date)
        self.exam_date = (exam_date)
        self.expiry_date = (expiry_date)
        self.certification_status = certification_status

    @property
    def age_calculator(self):
        age = datetime.today()- self.birth_date
        return age

    @property
    def validity(self):
        return self.expiry_date - self.exam_date

    def restricted_reason(self):

        while True:
            if self.certification_status == "Fit" and self.validity < timedelta(days = 730):
                d = input("Please enter reason for shortened certificate. ")
                return d
                break

            elif self.certification_status == "Fit" and self.validity >= timedelta(days = 730):
                print("This is a normal certificate. ")
                break

            elif self.certification_status == "Limited" or self.certification_status == "Fail":
                e = input(f"Please enter reason for certifying as {self.certification_status}. ")
                return e
                break

            else:
                print("Does not compute!")
                g = input("Please enter certification status. ")
                self.certification_status = g
                continue

    def certificate_type(self):
                if self.certification_status == "Fit" and self.validity < timedelta(days = 730):
                    return "Limited Time"

                elif self.certification_status == "Fit" and self.validity in range((timedelta(days = 730)), (timedelta(days = 732))):
                    return "Normal"

                elif self.certification_status == "Limited":
                    return "Limited"

                elif self.certification_status == "Fail":
                    return "Fail"

                elif self.validity >= timedelta(days = 733):
                    print("Please check expiry date - must not exceed 2 years.")
                    new_date = input("Please enter expiry date in dd mm yyyy. ")
                    self.expiry_date = new_date
                    return readtextfile.restricted_reason()

                else:
                    print("Does not compute!")
                    return readtextfile.restricted_reason()
When the code is run, I get:
Output:
File "test.py", line 49, in certificate_type elif self.certification_status == "Fit" and self.validity in range((timedelta(days = 730)), (timedelta(days = 732))): TypeError: 'datetime.timedelta' object cannot be interpreted as an integer
Is there a way to convert the timedelta to integer (or float)?
Thanks in advance.
Reply
#2
To check if something is in a valid range, you could do following:

minimum_value <= current_value <= maximum_value
All three values should be the same data type.
In your example self.validity should be a timedelta object.

This should work:

                elif self.certification_status == "Fit" and timedelta(days=730) <= self.validity <= timedelta(days=732)):
                    return "Normal"
A example with ip addresses:
from ipaddress import ip_address


def ip_is_in_range(ip, start, end):
    start = ip_address(start)
    end = ip_address(end)
    ip = ip_address(ip)
    return start <= ip <= end
What you've tried with the range object, works for integers.
my_range = range(16, 31, 2)
18 in my_range
17 in my_range
...

# And you can use the range object again and again.
for i in my_range:
    for j in my_range:
        print(i, j)
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply
#3
timedelta-objects supports comparison, datetime- and date-objects also.
I call the expression a <= b <= c Chained Comparison.
I am not sure if this is the official name.
You can find the specification here.

Tutorial for chained comparison: https://www.geeksforgeeks.org/chaining-c...rs-python/
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply
#4
Thank you. I do need to try and get out of the habit of using the range object....
Reply
#5
(Jan-28-2020, 09:03 PM)DeaD_EyE Wrote: I call the expression a <= b <= c Chained Comparison.
I am not sure if this is the official name.
You can find the specification here.

As documentation states 'Comparisons can be chained arbitrarily, /.../' I would say that chained comparison is pretty 'official' name Smile. Also - in operator section of documentation there is

'Note that comparisons, membership tests, and identity tests, all have
the same precedence and have a left-to-right chaining feature as
described in the Comparisons section.'

Additional tidbit: there is Python built-in help which in many cases I find more convenient than browsing python.org. Extensive information about comparisons is available in interactive interpreter with help('COMPARISONS').
I'm not 'in'-sane. Indeed, I am so far 'out' of sane that you appear a tiny blip on the distant coast of sanity. Bucky Katt, Get Fuzzy

Da Bishop: There's a dead bishop on the landing. I don't know who keeps bringing them in here. ....but society is to blame.
Reply
#6
Thanks for the replies, I used the chain comparison method and that solved the issue.

I am now stuck with a separate problem. I am trying to implement a class to write the above values to a spreadsheet. The working version is this:

from datetime import datetime, timedelta
from openpyxl import load_workbook, Workbook
class Spreadsheet(object):

    def __init__(self,certification_status,reason,age):
        #super(Spreadsheet,self). __init__(birth_date, exam_date, expiry_date, certification_status)
        self.certificate_type = certificate_type
        self.age = age
        self.reason = reason
        self.wb = load_workbook(filename = 'test2.xlsx')
        self.sheet = self.wb.active

    def write_reason(self,existing_value_location,target_location): #writes reason to cell
            c = []
            existing_value = existing_value_location.value
            c.append(existing_value) if existing_value else " "
            c.append(self.reason)
            self.sheet[target_location] = str(",".join(c))
            print(f"Reason of {self.reason} was added to cell {target_location}. The old reasons were {existing_value} and the new reasons are {(','.join(c))}")

    def addcount(self,target_row,target_column,target_cell_name):

        target_cell = self.sheet.cell(row = target_row, column = target_column)
        x = target_cell.value
        y = x+1
        self.sheet[target_cell_name]= y
        print(f'Added one count to cell {target_cell_name}. The previous value was {x} and the new value is now {y}.')

    def writespreadsheet(self):
        while self.certificate_type == "Fit":
                if self.age < 20:
                    Spreadsheet.addcount(self,10,3,'C10')
                    break

                elif 20 <= self.age < 30:
                    Spreadsheet.addcount(self,10,4,'D10')
                    break

                elif 30 <= self.age < 40:
                    Spreadsheet.addcount(self,10,5,'E10')
                    break

                elif 40 <= self.age < 50:
                    Spreadsheet.addcount(self,10,6,'F10')
                    break

                elif 50 <= self.age < 60:
                    Spreadsheet.addcount(self,10,7,'G10')
                    break

                elif self.age >= 60:
                    Spreadsheet.addcount(self,10,8, 'H10')
                    break

                else:
                    continue

        while self.certificate_type == "Time Limited":
            if self.age < 20:
                Spreadsheet.addcount(self,13,3,'C13')
                Spreadsheet.write_reason(self,(self.sheet.cell(row = 26, column = 2)), 'B26')
                break

            elif 20 <= self.age < 30:
                Spreadsheet.addcount(self,13,4,'D13')
                Spreadsheet.write_reason(self,(self.sheet.cell(row = 26, column = 3)), 'C26')
                break

            elif 30 <= self.age < 40:
                Spreadsheet.addcount(self,13,5,'E13')
                Spreadsheet.write_reason(self,(self.sheet.cell(row = 26, column = 4)), 'D26')
                break

            elif 40 <= self.age < 50:
                Spreadsheet.addcount(self,13,6,'F13')
                Spreadsheet.write_reason(self,(self.sheet.cell(row = 26, column = 5)), 'E26')
                break

            elif 50 <= self.age < 60:
                Spreadsheet.addcount(self,13,7,'G13')
                Spreadsheet.write_reason(self,(self.sheet.cell(row = 26, column = 6)), 'F26')
                break

            elif self.age >=60:
                Spreadsheet.addcount(self,13,8, 'H13')
                Spreadsheet.write_reason(self,(self.sheet.cell(row = 26, column = 7)), 'G26')
                break

            else:
                continue
# and so on for " Limited" and "Fail" certification statuses
As you can see the code is long and difficult to maintain. I stumbled upon this link as a guide to simplify the code as such:

from datetime import datetime, timedelta
from openpyxl import load_workbook, Workbook
class Spreadsheet(object):

    def __init__(self,certification_status,reason,age):
        #super(Spreadsheet,self). __init__(birth_date, exam_date, expiry_date, certification_status)
        self.certificate_type = certificate_type
        self.age = age
        self.reason = reason
        self.wb = load_workbook(filename = 'test2 - Copy.xlsx')
        self.sheet = self.wb.active

    def write_reason(self,existing_value_location,target_location): #writes reason to cell
            c = []
            existing_value = existing_value_location.value
            c.append(existing_value) if existing_value else " "
            c.append(self.reason)
            self.sheet[target_location] = str(",".join(c))
            print(f"Reason of {self.reason} was added to cell {target_location}. The old reasons were {existing_value} and the new reasons are {(','.join(c))}")

    def addcount(self,target_row,target_column,target_cell_name):

        target_cell = self.sheet.cell(row = target_row, column = target_column)
        x = target_cell.value
        y = x+1
        self.sheet[target_cell_name]= y
        print(f'Added one count to cell {target_cell_name}. The previous value was {x} and the new value is now {y}.')

    def writespreadsheet(self):
        #data setup
        certificate_type = {"Fit":{'type': self.certificate_type == "Fit", 'row_count': self.sheet[10], 'row_reason': None},
                            "Time Limited":{ 'type': self.certificate_type == "Time Limited", 'row_count': self.sheet[13], 'row_reason': self.sheet[26]},
                            "Limited": {'type': self.certificate_type ==" Limited", 'row_count': self.sheet[12], 'row_reason': self.sheet[25]},
                            "Fail": {'type': self.certificate_type == "Fail", 'row_count': self.sheet[11], 'row_reason': self.sheet[24]}
                            }

        age_group = {"under 20": {'age':self.age < 20, 'column': self.sheet['C']},
                    "20-29": {'age':20 <= self.age < 30,'column': self.sheet['D']},
                    "30-39": {'age':30 <= self.age < 40,'column': self.sheet['E']},
                    "40-49": {'age':40 <= self.age < 50,'column': self.sheet['F']},
                    "50-59": {'age':50 <= self.age < 60,'column': self.sheet['G']},
                    "over 60":{'age': self.age >= 60, 'column': self.sheet['H']}
                    }

        #enter data loop
        while True:
            try:
                for type in certificate_type:
                    for age in age_group:
                        Spreadsheet.addcount(self,"row_count",age_group['column'],(''.join(age_group["column"],"row_count")))
                        Spreadsheet.write_reason(self,"row_reason",age_group['column'],(''.join(age_group["column"],"row_reason")))
                        break
            except ValueError:
                raise("Unable to process. ")

        self.wb.save("D:\\python\\test2 - Copy.xlsx")
When the code is run, I get this error:
Output:
Traceback (most recent call last): File "test.py", line 173, in <module> b.writespreadsheet() File "test.py", line 127, in writespreadsheet Spreadsheet.addcount(self,"row_count",age_group['column'],(''.join(age_group["column"],"row_count"))) KeyError: 'column'
I still get a key error even though the column key is in the age_group dict. What gives..?

Thanks again for helping.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Are list/dict comprehensions interpreted really sequentially? anata2047 3 1,415 May-31-2022, 08:43 PM
Last Post: Gribouillis
  Convert timedelta to specified format Planetary_Assault_Systems 3 3,087 Jun-27-2021, 01:46 PM
Last Post: snippsat
  Timedelta - datetime.now PoduShychka 6 3,432 Mar-17-2021, 06:34 PM
Last Post: PoduShychka
  Timedelta - datetime.now PoduShychka 1 5,466 Mar-17-2021, 03:49 PM
Last Post: bowlofred
  Running scripts and location of saved interpreted user-defined classes and functions leodavinci1990 3 2,468 Aug-25-2020, 03:43 AM
Last Post: micseydel
  TypeError: unsupported operand type(s) for *: 'datetime.timedelta' and 'float' chris0147 2 37,390 May-01-2018, 07:20 PM
Last Post: nilamo
  Question about how python being interpreted. Nirelg 2 3,540 May-10-2017, 01:09 AM
Last Post: metulburr

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020