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())
Related
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"'
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.
In this exercise, you'll raise a manual exception when a condition is not met in a particular function. In particular, we'll be converting birth year to age.
Specifications
One a new cell in your notebook, type the following function
import datetime
class InvalidAgeError(Exception):
pass
def get_age(birthyear):
age = datetime.datetime.now().year - birthyear
return age
Add a check that tests whether or not the person has a valid (0 or greater)
If the age is invalid, raise an InvalidAgeError
Expected Output
>>> get_age(2099)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
__main__.InvalidAgeError
My code is as following, but it shows error on raise line, how can i get expected output?
import datetime
class InvalidAgeError(Exception):
pass
def get_age(birthyear):
age = datetime.datetime.now().year - birthyear
if age >=0:
return age
else:
raise InvalidAgeError
get_age (2099)
As mentioned in the comments, your code is correct. I guess you would like to see the error message that explains why the error is raised. Here is the code for it.
def get_age(birthyear):
age = datetime.datetime.now().year - birthyear
if age >=0:
return age
else:
raise InvalidAgeError(f'InvalidAgeError: the birthyear {birthyear} exceeds the current year ({datetime.datetime.now().year})')
Please feel free to modify the Exception message the way you find appropriate.
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.
I think I misunderstand how to use mocks for changing a function return value. Here is my test :
from path.to import programme_finder
#patch('path.to.programme_finder._calc_update_interval')
def test_refresh_interval(self,method_mock):
today = datetime.datetime.now()
dd = datetime.timedelta(millisecond=20)
earlier_date = today - dd
#The normal function returns a 5 day interval.
# For tests I want it down to 20ms
method_mock.return_value = earlier_date
#Here I would expect a date object, instead I get MagicMock
print("Calc returns %s " % programme_finder._calc_update_interval)
# rest of the test irrelevant
self.fail("need to time responce time")
What am I doing wrong ? How do I get the programme_finder._calc_update_interval to return my patched datetime?
Tried
assert programme_finder._calc_update_interval == earlier_date
as well and it fails.
#programme_finder.py
def _calc_update_interval():
today = datetime.datetime.now()
# The days we want to subtract for today.
update_interval = current_app.config.get("RESOURCE_UPDATE_INTERVAL")
dd = datetime.timedelta(days=update_interval)
# Find which date it was x days ago
earlier_date = today - dd
return earlier_date
It looks to me like you're not calling the function -- you're referencing it by name, so you get back the mocked function instead of your mock return value.
print("Calc returns %s " % programme_finder._calc_update_interval )
^reference
Should be
print("Calc returns %s " % programme_finder._calc_update_interval() )
^^call
The problem seems to be that _calc_update_interval is a property (I'm guessing created with the #property decorator) and not a method. The easiest approach is to simply use the PropertyMock class provided with mock (Documented here):
#patch('path.to.programme_finder._calc_update_interval', new_callable=PropertyMock):
def test_refresh_interval(self,method_mock):
#...