Accepting either a string or an integer for a date - python

How to check whether the parameter I passed in function is integer, string or date in python?
My function can accept either a string or an integer as the date:
def check(self, dat1):
# print(self.path)
# dat1 = raw_input("data = ")
print(type(dat1))
try:
datetime.datetime.strptime(dat1, '%Y-%m-%d')
except ValueError:
try:
int(dat1)
except ValueError:
print("str it is")
else:
print(dat1)
rand1 = random.randint(int(dat1) - (int(dat1) % 7), int(dat1) + (int(dat1) % 7))
print(rand1)
return rand1
else:
print("date it is")
check(100)
I get an error like this when I pass in an integer:
datetime.datetime.strptime(dat1, '%Y-%m-%d')
TypeError: must be string, not int
I know there is a question similar but it works for raw_input() not for parameter.

The first argument to the datetime.datetime.strptime() method must be a string. You are passing it an integer instead, and that means a TypeError is raised.
Catch that exception too, and not just ValueError (which is thrown if you pass in the right type but the string could not be parsed):
try:
datetime.datetime.strptime(dat1, '%Y-%m-%d')
except (ValueError, TypeError):

You could try using isinstance
>>> my_str = "Foo"
>>> isinstance(my_str, str)
True
>>> my_int = 1234
>>> isinstance(my_int, int)
True
>>> my_date = datetime.date.today()
>>> isinstance(my_date, datetime.date)
True
# Assuming you used "import datetime" at the top of your file
You could then use a if-elif structure to raise appropriate exceptions.

Related

Passing a function's output as a parameter of another function

I'm having a hard time figuring out how to pass a function's return as a parameter to another function. I've searched a lot of threads that are deviations of this problem but I can't think of a solution from them. My code isn't good yet, but I just need help on the line where the error is occurring to start with.
Instructions:
create a function that asks the user to enter their birthday and returns a date object. Validate user input as well. This function must NOT take any parameters.
create another function that takes the date object as a parameter. Calculate the age of the user using their birth year and the current year.
def func1():
bd = input("When is your birthday? ")
try:
dt.datetime.strptime(bd, "%m/%d/%Y")
except ValueError as e:
print("There is a ValueError. Please format as MM/DD/YYY")
except Exception as e:
print(e)
return bd
def func2(bd):
today = dt.datetime.today()
age = today.year - bd.year
return age
This is the Error I get:
TypeError: func2() missing 1 required positional argument: 'bday'
So far, I've tried:
assigning the func1 to a variable and passing the variable as func2 parameter
calling func1 inside func2
defining func1 inside func2
You're almost there, a few subtleties to consider:
The datetime object must be assigned to a variable and returned.
Your code was not assigning the datetime object, but returning a str object for input into func2. Which would have thrown an attribute error as a str has no year attribute.
Simply subtracting the years will not always give the age. What if the individual's date of birth has not yet come? In this case, 1 must be subtracted. (Notice the code update below).
For example:
from datetime import datetime as dt
def func1():
bday = input("When is your birthday? Enter as MM/DD/YYYY: ")
try:
# Assign the datetime object.
dte = dt.strptime(bday, "%m/%d/%Y")
except ValueError as e:
print("There is a ValueError. Please format as MM/DD/YYYY")
except Exception as e:
print(e)
return dte # <-- Return the datetime, not a string.
def func2(bdate):
today = dt.today()
# Account for the date of birth not yet arriving.
age = today.year - bdate.year - ((today.month, today.day) < (bdate.month, bdate.day))
return age
Can be called using:
func2(bdate=func1())
I think what you want to do is use it as an argument. You can do it like this:
import datetime as dt
def func1():
bd = input("When is your birthday? ")
try:
date_object = dt.datetime.strptime(bd, "%m/%d/%Y")
except ValueError as e:
print("There is a ValueError. Please format as MM/DD/YYY")
except Exception as e:
print(e)
return date_object
def func2(bd)
today = dt.datetime.today()
age = today.year - bd.year
return age
func2(func1())

Pass a keyword variable to a function as an argument

I'm doing a project that is requiring a lot of input validation. I currently have a function defined as follows:
def get_valid_float(inputMessage,errorMessage):
while True:
variableInput = input(inputMessage)
try:
variableInput = float(variableInput)
return variableInput
except ValueError:
print(errorMessage)
This function allows me to choose a custom message to prompt the user. It will then validate that the user input is indeed a float, and will print a custom error message in the event that it is not. It will loop until the user gives a valid input.
However, I would rather not create a function to validate each and every data type. It seems like it would be best to combine these into one get_valid_input() function, and pass a third argument allowing me to choose what data type I am attempting to verify. For example, get_valid_input(complex,inputMessage,errorMessage).
I am obviously unable to pass a keyword as an argument. This makes me think the only way to do this would to be to do something like this:
def get_valid_float(dataType,inputMessage,errorMessage):
if dataType == "float"
while True:
variableInput = input(inputMessage)
try:
variableInput = float(variableInput)
return variableInput
except ValueError:
print(errorMessage)
elif dataType == "integer"
while True:
variableInput = input(inputMessage)
try:
variableInput = int(variableInput)
return variableInput
except ValueError:
print(errorMessage)
And so on, with an elif for every data type. Surely there is an easier way to do this, that somehow allows me to execute the line variableInput = {dataType}(variableInput) to confirm that they input a value of data type "dataType". Any ideas?
Just pass as an argument the actual data type, rather than the name of the data type. E.g:
def get_valid_input(dataType, inputMessage, errorMessage):
while True:
value = input(inputMessage)
try:
value = dataType(value)
break
except ValueError:
print(errorMessage)
You would call it like this:
floatvalue = get_valid_input(float, "enter a float value: ", "that is an invalid float")
intvalue = get_valid_input(int, "enter an integer value: ", "that is an invalid integer")
I am obviously unable to pass a keyword as an argument.
Not sure why you're saying that, but you can! :)
Also no need for error message, just catch all Exceptions (Not recommended but since you are just printing out the error it seems fine here)
The message strings aren't really needed, try using the name of the dataType and the exception's message like this:
def get_valid_data(dataType):
while True:
variableInput = input(f"Put in data of type {dataType.__name__}: ")
try:
variableInput = dataType(variableInput)
return variableInput
except Exception as e:
print(e)
get_valid_data(int)
>>> Put in data of type int: "hi"
>>> invalid literal for int() with base 10: '"hi"'

How to Check data is int, float in python

I know similar questions have been asked and answered before like here: How do I check if a string is a number (float or Int ) in Python?
However, it does not provide the answer I'm looking for. What I'm trying to do is this:
def is_int_or_float(s):
try:
a = float(s)
return 1 if s.count('.')==0 else 2
except ValueError:
return -1
val = input("Enter your value: ")
data = is_int_or_float(val)
print(data)
What if User enters => "22" # Then Above code will gives -1.Please help me to resolve this With Exception handling (User Message)
Try this:
def is_int_or_float(value):
try:
tmp = float(value)
return 1 if tmp.is_integer() else 2
except ValueError:
return -1
And testing:
>>> is_int_or_float("a")
-1
>>> is_int_or_float("22")
1
>>> is_int_or_float("22.646")
2
>>> is_int_or_float("22.64.6")
-1
>>> is_int_or_float("22.000")
1
>>> is_int_or_float("1e-4")
2
You can create a simple handle for that.
Check the code. You need to implements you exception handle logic.
class AbstractHandler:
def is_float(self):
raise NotImplementedError
def is_int(self):
raise NotImplementedError
def verify(self):
raise NotImplementedError
class Handler(AbstractHandler):
def is_float(self, number):
try:
float(number)
return True
except ValueError:
# Your exception handler here
return False
def is_int(self, number):
try:
int(number)
return True
except ValueError:
# Your exception handler here
return False
def verify(self, var):
if self.is_float(var) or self.is_int(var):
return True
else:
return False
def is_number(var):
"""
Verify if input is a instance of int or float
Args:
var (str): input to be verified
"""
handler = Handler()
return handler.verify(var)
Some tests:
1 is True
1.1 is True
1.1.1 is False
One way to check, for example integer, use isinstance:
x = 1
if isinstance(x, int):
# Do something

Beginning date is bigger than the end date of a calendaristic period

I am trying to write a function that validates a package that contains 2 dates (beginning and end), a destination and a price
Initially, I tried to write a function that "creates" dates and puts them in a list and then compares them to find out if the end date was lower than the beginning but I figured that was too complicated so I resorted to the datetime inbuilt module
However, when I try to run the test function, it fails and it outputs this error message
File "C:\Users\Anon\Desktop\Fac\FP\pythonProject\main.py", line 65, in valideaza_pachet
raise Exception(err)
Exception: wrong dates!
I assume that I must have messed up a condition in the valideaza_pachet() function, but I don't understand what I did wrong
The code:
import time
import calendar
from datetime import date, datetime
def creeaza_pachet(data_i, data_s, dest, pret):
# function that creates a tourism package, data_i = beginning date, data_s = end date, dest = destination and pret = price
return {
"data_i": data_i,
"data_s": data_s,
"dest": dest,
"pret": pret
}
def get_data_i(pachet):
# functie that returns the beginning date of the package
return pachet["data_i"]
def get_data_s(pachet):
# functie that returns the end date of the package
return pachet["data_s"]
def get_destinatie(pachet):
# functie that returns the destination of the package
return pachet["dest"]
def get_pret(pachet):
# functie that returns the price of the package
# input: pachet - un pachet
# output: pretul float > 0 al pachetului
return pachet["pret"]
def valideaza_pachet(pachet):
#functie that validates if a package was correctly introduced or not
#it raises an Exception as ex if any of the conditions aren't met
err = ""
if get_data_i(pachet) < get_data_s(pachet):
err += "wrong dates!" # if the end date is lower than the beginning date
if get_destinatie(pachet) == " ":
err += "wrong destination!"
if get_pret(pachet) <= 0:
err += "wrong price!"
if len(err) > 0:
raise Exception(err)
def test_valideaza_pachet():
pachet = creeaza_pachet(datetime.strptime('24/08/2021',"%d/%m/%Y"), datetime.strptime('26/08/2021',"%d/%m/%Y"), "Galati", 9000.1)
valideaza_pachet(pachet)
pachet_gresit = creeaza_pachet(datetime.strptime('24/08/2021',"%d/%m/%Y"), datetime.strptime('22/08/2021',"%d/%m/%Y"), "Galati", 9000.1)
try:
valideaza_pachet(pachet_gresit)
assert False
except Exception as ex:
assert (str(ex) == "wrong dates!\n")
alt_pachet = creeaza_pachet(datetime.strptime('24/08/2021',"%d/%m/%Y"), datetime.strptime('22/08/2021',"%d/%m/%Y"), " ", -904)
try:
valideaza_pachet(alt_pachet)
assert False
except Exception as ex:
assert(str(ex) == "wrong dates!\nwrong destination!\nwrong price!\n")
def test_creeaza_pachet():
data_i_string = '24/08/2021'
data_i = datetime.strptime(data_i_string, "%d/%m/%Y")
data_s_string = '26/08/2021'
data_s = datetime.strptime(data_s_string, "%d/%m/%Y")
dest = "Galati"
pret = 9000.1
pachet = creeaza_pachet(data_i,data_s,dest,pret)
assert (get_data_i(pachet) == data_i)
assert (get_data_s(pachet) == data_s)
assert (get_destinatie(pachet) == dest)
assert (abs(get_pret(pachet) - pret) < 0.0001)
def run_teste():
test_creeaza_pachet()
test_valideaza_pachet()
def run():
pass
def main():
run()
run_teste()
main()
This is more of a code review and kind of off-topic here but... First,
drop all assert False - these won't do anything useful
drop the getter functions, that just makes things convoluted (just use dict[key] in the code as long as you don't use custom class)
drop unnecessary imports like calendar
you might also want to drop the run and main functions (again convoluted) - just call the functions you need
Then you could change valideaza_pachet to raise specific value errors:
def valideaza_pachet(pachet):
if pachet["data_i"] >= pachet["data_s"]:
raise ValueError("start date must be < end date")
if pachet["dest"] == " ":
raise ValueError("destination must not be empty")
if pachet["pret"] <= 0:
raise ValueError("price must be >= 0")
# returns None if no exception was raised
Now to test a valid package, you would just do
valideaza_pachet(pachet) # no exception expected
Testing an invalid package is a bit more complicated without a class that can be unit-tested (see e.g. here) - but you can catch the exception and use the else clause of the try/except to raise an AssertionError that says you wanted an exception:
try:
valideaza_pachet(pachet_gresit)
except Exception as ex:
print(f"successfully received exception: {ex}")
else:
raise AssertionError("validation should have raised an Exception")
or even
assert str(ex) == "start date must be < end date", f"got '{ex}', expected 'start date must be < end date'"
in place of the print statement.

Is using nested try-except an acceptable Python style here

I need check whether the string price is an integer or a float and return True in this case or False otherwise.
Is this function written in an acceptable Python style?
def is_valid_price(price):
try:
int(price)
return True
except:
try:
float(price)
return True
except:
return False
If no, what's the best way to make it look Pythony?
Definitely not — except without specifying the exception class(es) is prone to make problems.
def is_valid_price(price):
try:
float(price)
return True
except ValueError:
return False
There is no need to use test int(price), because if the string is convertible to int, it's also convertible to float.
In this case you only check type of price:
def is_valid_price(price):
return isinstance(price, (int, float))
is_valid_price(5)
You can call exception
assert float(price)
if price not float(int) you will get exception
ValueError Traceback (most recent call last)
in ()
----> 1 assert float(price)
ValueError: could not convert string to float: price

Categories