Data Validation inside a function - Python - python

I am running into an issue with validating an input is a valid date, and if not coming back to the question for a retry.
I want to loop through this header and ask for input for each item.
header = [employee_id,name,address,ssn,date_of_birth,job_title,start_date,end_date]
The CSV is empty aside from the header, as I am appending these rows into via this program. I want the date_validator() to work for DOB, start_date and end_date, but so far i can get it to validate that the input is wrong, it just doesnt go back and ask for the input again.
Any help would be appreciated! thanks!
import csv
import datetime
def add_employee():
global date_answer
list = []
for i in range(len(header)):
var = header[i]
answer1 = input('Input Employees {}:'.format(var))
if "date" in header[i]:
date_answer = answer1
date_validater()
list.append(answer1)
with open('employees.csv','a',newline="") as f_object:
writer = csv.writer(f_object)
writer.writerow(list)
f_object.close()
print()
def date_validater():
# input date
date_string = date_answer
date_format = '%m/%d/%Y'
try:
dateObject = datetime.datetime.strptime(date_string, date_format)
print(dateObject)
except ValueError:
print("Incorrect data format, should be MM/DD/YYYY")

A couple hints:
Functions take parameters...
Globals are a terrible ideas most of the time. Avoid like the plague.
Pass the variables to the function to use it inside the function.
import csv
import datetime
def add_employee(header):
list = []
for i in range(len(header)):
var = header[i]
answer1 = input('Input Employees {}:'.format(var))
if "date" in header[i]:
date_validater(answer1)
list.append(answer1)
with open('employees.csv','a',newline="") as f_object:
writer = csv.writer(f_object)
writer.writerow(list)
f_object.close()
print()
def date_validater(date_string):
# input date
date_format = '%m/%d/%Y'
try:
dateObject = datetime.datetime.strptime(date_string, date_format)
print(dateObject)
except ValueError:
print("Incorrect data format, should be MM/DD/YYYY")
or something like that...

Related

How do I convert a string to a datetime without many nested try...excepts?

I'm trying to check user input of a date/time in several allowable formats. (I know about the dateutil library. It's not what I'm looking for in this case.)
If some user input was accepted, the function must return a datetime object.
If ALL "try...except" fail — the function must return NONE. But I have 30-50 different date/time formats that I need to check.
I'm confused by the huge indentation in my code! How do I organize this format checking in a good style with GOOD performance?
# Test format check program
import datetime
def datetime_format_check(str):
try:
dt = datetime.datetime.strptime(str, "%y-%m-%d %H:%M")
return dt
except:
try:
dt = datetime.datetime.strptime(str, "%Y-%m-%d %H:%M")
return dt
except:
try:
dt = datetime.datetime.strptime(str, "%y-%m-%d")
return dt
except:
try:
dt = datetime.datetime.strptime(str, "%Y-%m-%d")
return dt
except:
try:
dt = datetime.datetime.strptime(str, "%H:%M")
return dt
except:
try:
# . . .
# many many try...except blocks )))
# . . .
return None # last except far far away from a screen border. ))))
while True:
str = input("Input date: ")
print("Result: ", datetime_format_check(str))
Repetitive code? Well, that just begs to be replaced with a loop.
Put all of the formats in a list and iterate over it, checking each format:
def datetime_format_check(s):
formats = ["%y-%m-%d %H:%M", "%Y-%m-%d %H:%M", "%y-%m-%d"] # etc
for format in formats:
try:
dt = datetime.datetime.strptime(s, format)
return dt
except ValueError:
pass
return None
Some minor corrections I made to your code:
Don't name your argument str; it shadows the builtin.
Don't use a bare except:, always catch the specific exception.

Python 3.8 datetime date comparison not work between "internal generated date" and imported date

I'm trying to compare the actual date with externally generated date, always generated from datetime but in another script and saved in a txt file.
This is the code:
import datetime
datin = datetime.datetime.today()
with open('date.txt', 'r') as mydate:
mdate = mydate.read()
datex = datetime.datetime.strptime(mdate, '%d-%m-%Y')
if datin.date == datex.date:
print('=')
else:
print('!=')
print(datin.strftime('%d-%m-%Y'))
print(datex.strftime('%d-%m-%Y'))
this is the txt file:
03-07-2020
(the same date I'm testing the script)
should return = but return !=
What am I doing wrong?
You have a slight error in that you are accessing the method of the date objects instead of calling the method.
You can find this out by trying to print
datin.date versus datin.date()
Here is the corrected code that runs as expected:
import datetime
datin = datetime.datetime.today()
mdate = '03-07-2020'
datex = datetime.datetime.strptime(mdate,"%d-%m-%Y")
print(datin.date())
print(datex.date())
if datin.date() == datex.date():
print("=")
else:
print("!=")
print (datin.strftime("%d-%m-%Y"))
print(datex.strftime("%d-%m-%Y"))

Mutiple API with different variable in URL

I am learning Python and had a question regarding for and if loops. This is my scenario:
I have an endpoint that i make API-call with request.get
I need to retrieve all the historic data
I have a start_date (2017-06-17)
So i need to make multiple API-call because they have a limit of 60-days period. So i made my code like this:
date = datetime.strptime("2017-06-17", "%Y-%m-%d") # Start Date
current_date = date.date() # timedelta need date object so i make it a date object
days_after = (current_date+timedelta(days=60)).isoformat() # days_after is set to 60-days because limit in API
date_string = current_date.strftime('%Y-%m-%d') # made to string again since API need string not date object
So this is how i make the dates for 60 days period. Starting from 2017-06-17 and 60-days ahead.
This is how i make the API-request:
response = requests.get("https://reporting-api/campaign?token=xxxxxxxxxx&format=json&fromDate="+date_string+"&toDate="+days_after)
response_data = response.json() # Added this because i am writing temprorary to a JSON file
This is how i write to JSON file:
if response_data:
print("WE GOT DATA") # Debugging
data = response.json() # This is duplicate?
with open('data.json', 'w') as f: # Open my data.json file as write
json.dump(data, f) # dumps my json-data from API to the file
else:
print("NO DATA") # Debugging if no data / response. Should make a skip statement here
So my question is how can i proceed with my code so that every time i make a API-call starting from 2017-06-17 the date date_string and days_after should go 60 days forward for each API-call and append those data to data.json. I would maybe need some for loops or something?
Please note i have been using Python for 3 days now, be gentle.
Thanks!
You could use a while loop that changes the start and end date until a specified condition is met. Also, you can append the response to a file for every run. the example below I used the date of "today":
import os
from datetime import datetime, timedelta
x = 0
y = 60
date = datetime.strptime("2017-06-17", "%Y-%m-%d")
current_date = date.date()
date_start = current_date+timedelta(days=x)
while date_start < datetime.now().date():
date_start = current_date+timedelta(days=x)
days_after = current_date+timedelta(days=y)
x = x + 60
y = y + 60
response = requests.get("https://reporting-api/campaign?token=xxxxxxxxxx&format=json&fromDate="+date_start.isoformat() +"&toDate="+days_after.isoformat())
response_data = response.json()
if response_data:
print("WE GOT DATA")
data = response.json()
#create a file if not exists or append new data to it.
if os.path.exists('data.json'):
append_write = 'a' # append if already exists
else:
append_write = 'w' # make a new file if not
with open('data.json', append_write) as f:
json.dump(data, f)
else:
print("NO DATA")
Basically, on every run the time of start and end is increased by 60 days and appended to the data.json file.

Save a file name as "date - backup"

I am currently exporting a table from by Bigquery to G.C.S as another form of a backup. This is the code I have so far that saves the file name as "firebase_connectioninfo.csv".
# Export table to GCS as a CSV
data = 'dataworks-356fa'
destination = 'gs://firebase_results/firebase_backups1/Firebase_ConnectionInfo.csv'
def export_data_to_gcs(data, Firebase_ConnectionInfo, destination):
bigquery_client = bigquery.Client(data)
dataset = bigquery_client.dataset('FirebaseArchive')
table = dataset.table('Firebase_ConnectionInfo')
job_name = str(uuid.uuid4())
job = bigquery_client.extract_table_to_storage(
job_name, table, 'gs://firebase_results/firebase_backups1/Firebase_ConnectionInfo.csv')
job.source_format = 'CSV'
job.begin()
wait_for_job(job)
def wait_for_job(job):
while True:
job.reload()
if job.state == 'DONE':
if job.error_result:
raise RuntimeError(job.errors)
return
time.sleep(1)
export_data_to_gcs(data, 'Firebase_ConnectionInfo', destination)
I want this file to be named as "thedate_firebase_connectioninfo_backup". How do I add this command in a Python script?
So this is your string:
gs://firebase_results/firebase_backups1/Firebase_ConnectionInfo.csv'
What I would suggest is putting it into its own variable:
filename = 'gs://firebase_results/firebase_backups1/Firebase_ConnectionInfo.csv'
Additionally, we should put in a spot for the date. We can handle formatting the string a couple different ways, but this is my preferred method:
filename = 'gs://firebase_results/firebase_backups1/{date}-Firebase_ConnectionInfo.csv'
We can then call format() on the filename with the date like this:
from datetime import datetime
date = datetime.now().strftime("%M-%D-%Y")
filename.format(date=date)
Another way we could format the string would be the old string formatting style with %. I hate this method, but some people like it. I think it may be faster.
date = datetime.now().strftime("%M-%D-%Y")
filename = 'gs://firebase_results/firebase_backups1/%s-Firebase_ConnectionInfo.csv' % date
Or, you could use the other guy's answer and just add the strings like
"This " + "is " + "a " + "string."
outputs: "This is a string."
Try something like this:
import datetime
datestr = datetime.date.today().strftime("%B-%d-%Y")
destination = 'gs://firebase_results/firebase_backups1/' + datestr + '_Firebase_ConnectionInfo.csv'

Reading and comparing lines in a file using Python

I have a file of the following format.
15/07/2010 14:14:13 changed_status_from_Offline_to_Available
15/07/2010 15:01:09 changed_status_from_Available_to_Offline
15/07/2010 15:15:35 changed_status_from_Offline_to_Away became_idle
15/07/2010 15:16:29 changed_status_from_Away_to_Available became_unidle
15/07/2010 15:45:40 changed_status_from_Available_to_Away became_idle
15/07/2010 16:05:40 changed_status_from_Away_to_Available became_unidle
15/07/2010 16:51:39 changed_status_from_Available_to_Offline
20/07/2010 13:07:26 changed_status_from_Offline_to_Available
I need to create a function in python that has to arguments: date and time. It should read the file and return the second status if the date matches and time is less than the time in the function call. That is
Lets say i call the function returnstatus(15/07/2010, 15:10:01).
The function should go to the file and return the status of the user on that day at that time, which in this case is "Offline".
I am a Python newbie and any help would be really appreciated.
import datetime
import time
def lines( path_to_file ):
'''Open path_to_file and read the lines one at a time, yielding tuples
( date of line, time of line, status before line )'''
with open( path_to_file ) as theFile:
for line in theFile:
line = line.rsplit( " ", 1 )
yield (
datetime.datetime.strptime( line[ 0 ], "%d/%m/%Y %H:%M:%S" ),
line[ 1 ].split( "_" )[ 3 ]
)
def return_status( statDate ):
for lineDate, lineStatus in lines( path_to_file ):
if statDate > lineDate:
continue
return lineStatus
Does that make sense, or would you like me to explain any of it?
Edit
Did you mean what you said above?
date matches and time is less than the time in the function call
In other words, what should happen if you call return_status( 16/07/2010, <some.time> )? Should you get "Offline"?
Another Edit
I have edited it to do sensible datetime comparisons. I think you have read the inequality the wrong way around: we loop through lines in the file until the first line after the date we wish to fetch (keep reading while statDate > lineDate). Once this test fails, line is the first line after the desired date, so its from value is the status at the time we requested. You should call the function with a datetime.datetime.
I suggest you have a read in the python docs, specifically the time module and the function strptime which can parse textual representation of times into a programmatic representation.
Calling returnstatus the way you wrote in the question will surely fail, you might want to call it with a string representation of the time (i.e. "15/07/2010 15:10:01") or by passing one of the datatypes defined in the time module.
EDIT: obviously if you pass in a string time then finding it in the file is much easier:
if substring in line:
# do stuff
As Yoni said, you're probably better served by passing a string argument (if you have one). You may also find the types in datetime useful. You'll also want to look into the split function.
Basically, what you need to do is pull out the dates and times from your log into a easy-to-compare format. Enter datetime.
import datetime
def getStatus(log_list, dt, tm):
#filter the list
log_list = [a_log_entry for a_log_entry in log_list if a_log_entry[0] == dt and a_log_entry[1] <= tm]
#sort it
log_list.sort(cmp=lambda x,y: cmp(x[1], y[1]))
if log_list is []:
return 'No status available for this day and time.'
#pull out the status
status_to_return = log_list[-1][2].split('_')[-1].strip()
return status_to_return
if __name__ == '__main__':
in_file = open('a.log', 'rU')
a_list = []
for line in in_file:
if line.strip() is not '': #handle whitespace
a_list.append(line.split(' '))
#convert string dates and times to datetime objects
a_list = [ [datetime.datetime.strptime(el[0], '%d/%m/%Y'),
datetime.datetime.strptime(el[1], '%H:%M:%S'),
el[2]] for el in a_list]
a_date = datetime.datetime(2010, 7, 15)
a_time = datetime.datetime(1900, 1, 1, 16, 1, 0)
print getStatus(a_list, a_date, a_time)
Try this:
import datetime
filein = open("filein", "r")
class Status:
def __init__(self, date, time, status):
print date.split('/')
day, month, year = map(int, date.split('/'))
hour, minute, second = map(int, time.split(':'))
self.date_and_time = datetime.datetime(year=year, month=month, day=day, hour=hour, minute=minute, second=second)
self.status = status
list = []
line = filein.readline().rstrip('\n')
while line != "":
print line
date, time, status = line.split(' ')[:3]
status = status.split('_')
status.reverse()
status = status[0]
status_it = Status(date=date, time=time, status=status)
line = filein.readline().rstrip('\n')
list.append(status_it)
def query (date, time):
day, month, year = map(int, date.split('/'))
hour, minute, second = map(int, time.split(':'))
date_and_time = datetime.datetime(year=year, month=month, day=day, hour=hour, minute=minute, second=second)
for counter, it in enumerate(list):
if date_and_time >= it.date_and_time and (date_and_time < list[counter + 1].date_and_time or counter == len(list) - 1):
print it.status
return
print "I don't know the status"
query("15/07/2010", "15:10:01")
From the question user392409 most probably wants to pass the parameters as string and wants a single function.
Lets say i call the function returnstatus(15/07/2010, 15:10:01). The function should go to the file and return the status of the user on that day at that time, which in this case is "Offline".
import datetime
import time
def returnstatus(d, t):
d = datetime.datetime.strptime(d, "%d/%m/%Y")
t = time.strptime(t, "%H:%M:%S")
f = open("log.txt")
for line in f:
line = line.split(" ")
line_date = datetime.datetime.strptime(line[0], "%d/%m/%Y")
line_time = time.strptime(line[1], "%H:%M:%S")
if d != line_date and t >= line_time:
continue
# Returns the first occurrence. To get all store in a list or print.
f.close()
return line[2].split("_")[3]

Categories

Resources