Is there a function to 'autocomplete' a variable to a desired library? - python

I'm trying to set a variable to one I have in a library. Is there a command to do this?
I'm trying to make a simple time zone converter and I want to check the input variable, but I can only check the variables in the list from pytz so I want to 'autocomplete' the variable. can I do this?
import time
import pytz
country = input("enter country")
from datetime import datetime
from pytz import timezone
fmt = "%H:%M %p"
now_utc = datetime.now(timezone('UTC'))
print (now_utc.strftime(fmt))
from pytz import all_timezones
if country in all_timezones:
country = #completed country in list 'all_timezones'
timecountry = now_utc.astimezone(timezone(country))
print (timecountry.strftime(fmt))

So what you are looking for is a way to match the user input to the strings in all_timezones and look for a valid timezone.
As far as I know, there is no built-in function that does it, you have to do it by yourself.
It's not an immediate task, as you may have multiple options (let say the user inputs just 'Europe') and you have to take this in consideration
A possible way to do is the following:
import datetime
import time
import pytz
country = input("Contry name: ")
now_utc = datetime.datetime.now(pytz.timezone('UTC'))
fmt = "%H:%M %p"
while True:
possible_countries = [ac for ac in pytz.all_timezones if country in ac]
if len(possible_countries) == 1:
cc = possible_countries[0]
timecountry = now_utc.astimezone(pytz.timezone(cc))
print(timecountry.strftime(fmt))
break
elif len(possible_countries) > 1:
print("Multiple countries are possible, please rewrite the country name")
for cs in possible_countries:
print(cs)
country = input("Contry name: ")
else:
print("No idea of the country, here are the possible choices")
for cs in pytz.all_timezones:
print(cs)
country = input("Contry name: ")
With a list comprehension I look for all the strings in all_timezones which contains the user input. If there is just one, the script assumes that is the correct one and perform the task. Otherwise if there are multiple possibilites it prints them (one per row with the for loop, but you may just print the list so its shorter on the screen) and then asks the user to rewrite the country name. If there is no match, it just print all the possibilites. You may find it ugly to see on the command line, but you should get the idea and then improve it.
If you wish to check also for spelling errors in the user input... that is a lot more difficult.

Related

python - how do I find two desired integer values in a variable?

I'm in the process of learning how to code in Python and have been doing numerous tasks to help solidify info.
I had 1 issue - I am creating code that will take the date (dd/mm/yyyy) and then the program will validate the data (i.e checking if there are errors in the field and if so, naming the error type; if no errors are found, the user is told the input was correct) - just some data validation practise.
Where I'm getting stuck is just assigning the variables - I have typed and tested the day and year correctly but I cant manage to get the 4th and 5th integer of the variable date for the month variable.
Here is my code that I am first producing to make sure the integers I will be working with are correct:
date = input("Please enter the date in format dd/mm/yyyy: ")
valid_characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/-'
#defines where to locate day in user input
dayDate = str(date)[:2]
# could also be written as dayDate = str(date)[:-8]
#defines where to locate month in user input
def month(date):
return date[(len(date)//2)]
finalMonth = month(date)
#defines where to locate year in user input
yearDate = str(date)[-4:]
print(yearDate)
print(finalMonth)
print(dayDate)
From this code, the variables yearDate and dayDate present me with the values I want but the finalMonth is where i'm getting stuck. I've looked all over Google but can't seem to find the solution. If you do know how to solve my issue, I would really appreciate it if you could send the proper way to go about this and why you did what, as I am still kind of a newb in Python :)
I know the error is the function I've created for finding the month values, but that's precisely where I need help.
Thank you!
EDIT:
Sorry! I am new to Stack overflow so I didn't know.
so the code:
def month(date):
return date[(len(date)//2)]
finalMonth = month(date)
print(finalMonth)
returns the output '/' but what I am trying to get is for example you input '26/01/2021' and the variable finalMonth will give '01' - this code produces '/'. I am not sure what method should be used to get the month value.
you can use split() to create a list from input as below
date = input("Please enter the date in format dd/mm/yyyy: ")
valid_characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/-'
#defines where to locate day in user input
day, month, year = date.split("/")
print( day, month, year )
The quick answer to your error you were having is change
date[(len(date)//2)] to date[3:5]
After your clarification, I put together an example showing how you can handle error checking. :)
import datetime as dt
# the -> is to hint at the type of variable this function will return, this is not needed, but good practice
def get_date_from_user() -> dt.datetime:
# This will keep looping until correct gets changed to True
correct = False
while correct is False:
user_input = input("Please enter the date in format dd/mm/yyyy: ")
try:
# This part can be done in a lot of ways, I did it this way to demonstrate a condensed way and type conversions
date = dt.datetime(int(user_input[-4:]), int(user_input[:2]), int(user_input[3:5]))
correct = True # If the datetime was made successfully, set the loop to TRUE to escape
except ValueError as err:
print(err)
return date
date = get_date_from_user()
print(f'Day: {date.day} Month: {date.month} Year: {date.year}')
For handling dates though I highly recommend checking out Pendulum. With it you could do something like this:
import pendulum
date = pendulum.parse(input("Please enter the date in format dd/mm/yyyy: "))
dayDate = date.day
finalMonth = date.month
yearDate = date.year
It will throw an error if it cant parse what they typed in as well. If you wrap it in a Try and Except cause you can catch that too like below:
Python error handeling
import pendulum
try:
date = pendulum.parse(input("Please enter the date in format dd/mm/yyyy: "))
except ValueError as err:
print(err)
dayDate = date.day
finalMonth = date.month
yearDate = date.year

How to set the microsecond to zero if not set by the user using Python datetime?

I am trying to take in a user input, and create a time object from that string. Something like this:
import datetime
user_input = '14:24:41.992181'
time = datetime.datetime.strptime(user_input, '%H:%M:%S.%f').time()
However, lets say if the user_input was '14:24:41', then I get a format error, which is understandable. What I want to do is for such an input, the microsecond precision for the time object would be set automatically to 000000. I noticed something similar is done for timezones using %z, and its built into the strptime() method.
What is the ideal way to do this?
you can use try/except and handle the case when user input does not match the format string
import datetime
user_inputs = ['14:24:41.992181','14:24:41']
for user_input in user_inputs:
try:
dt = datetime.datetime.strptime(user_input, '%H:%M:%S.%f')
except ValueError:
dt = datetime.datetime.strptime(user_input, '%H:%M:%S')
print(dt.strftime('%H:%M:%S.%f'))
output
14:24:41.992181
14:24:41.000000
You could run a simple check on the length of the input string, assuming you are expecting standardized inputs.
user_input = '14:24:41'
if len(user_input) == 8:
user_input += '.000000'
time = datetime.datetime.strptime(user_input, '%H:%M:%S.%f').time()

How to make user input not case sensitive?

I want to create a function to filter which files I want to open and which months and day specifically. That way, the users need to input which city (files) they want to analyze on which particular month or day. However, I want the user to be able to input something that is not case sensitive.
For example, the user can input 'chicago'/'CHICAGO"/"ChIcAgO" and the it still give you the right output and not the error handling message. Here is the code I use:
def get_filters ():
city_options = ['Chicago','New York City','Washington']
month_options = ['January','February','March','April','May','June','All']
day_options = ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday','All']
while True:
try:
city = city_options.index(input('\nInsert name of the city to analyze! (Chicago, New York City, Washington)\n'))
month = month_options.index(input('\nInsert month to filter by or "All" to apply no month filter! (January, February, etc.)\n'))
day = day_options.index(input('\nInsert day of the week to filter by or "All" to apply no day filter! (Monday, Tuesday, etc.)\n'))
return city_options[city].lower(), month_options[month].lower(), day_options[day].lower()
except ValueError:
print ("Your previous choice is not available. Please try again")
def load_data (city,month,day):
#load data file into DataFrame
df = pd.read_csv(CITY_DATA[city].lower())
#convert start time column (string) to datetime
df['Start Time']=pd.to_datetime(df['Start Time'])
#create new column to extract month and day of the week from start time
df['Month'] = df['Start Time'].dt.month
df['Day_of_Week'] = df['Start Time'].dt.weekday_name
#filter by month if applicable
if month.lower()!= 'All':
#use the index of the month list to get corresponding into
months = ['January', 'February', 'March', 'April', 'May', 'June']
month = months.index(month) + 1
#filter by month to create new dataframes
df = df[df['Month'] == month]
if day.lower()!= 'All':
#filter by day_of_week to create new DataFrames
df =df[df['Day_of_Week'] == day]
return(df)
The best way to do so is just take the required input and convert it into the required case.
Use the inbuilt functions of python
variable.lower()
or
variable.upper()
You should use str.casefold to remove case sensitivity. As per the docs, this is stricter than str.lower:
str.casefold()
Return a casefolded copy of the string. Casefolded strings may be used
for caseless matching.
Casefolding is similar to lowercasing but more aggressive because it
is intended to remove all case distinctions in a string. For example,
the German lowercase letter 'ß' is equivalent to "ss". Since it is
already lowercase, lower() would do nothing to 'ß'; casefold()
converts it to "ss".
For example:
x = 'ßHello'
print(x.casefold())
sshello
I just started learning Python in December 2021.
I encountered a similar problem while writing the codes for a 'choose your own fantasy game".
To remove the case sensitivity, use the string.lower() or string.upper() function. Now, this answer is no different from the first answer to this question.
So, what's special here?
Well, if you are testing the answer from the user, your if-statement must have the same case as the case you are converting to e.g
answer = input("What is rat? 'Animal' or 'Food' ")
3)if answer.lower() == "animal":
print("Congratulations. You win! ")
5) else:
print("Sorry, you lose! ")
OR:
answer = input("What is rat? 'Animal' or 'Food' ")
3)if answer.upper() == "ANIMAL":
print("Congratulations. You win! ")
5) else:
print("Sorry, you lose! ")
N.B: No matter how the user types their answer (ANIMAL, ANimal, animal), if the answer is correct, he wins. So long the test case function is the same as the case string (line 3) to be tested.
I hope this helps!
I am new too but I think you should look at string functions. Presuming you use python 3 since you use input and get no ValueError, you can just add .lover().title() after the parentheses of the input
Example:
city = city_options.index(input('\nInsert name of the city to analyze! (Chicago, New York City, Washington)\n').lower().title())
Should do the trick as like If you input cHIcaGO it will be converted to Chicago instantly.
Hope it helps!
Edit:(After correcting misspelling of lower() function tried it on webbrowser, pycharm and Python itself. Works just fine for me(I'm using python 2.7 so I corrected all inputs as raw_input,If you are using python 3 you don't have to change them. ).)

Python script for EC2 snapshots, use datetime to delete old snapshots

I am a beginner with Python and I have written a python script which takes a snaphot of a specified volume and then retains only the number of snapshots requested for that volume.
#Built with Python 3.3.2
import boto.ec2
from boto.ec2.connection import EC2Connection
from boto.ec2.regioninfo import RegionInfo
from boto.ec2.snapshot import Snapshot
from datetime import datetime
from functools import cmp_to_key
import sys
aws_access_key = str(input("AWS Access Key: "))
aws_secret_key = str(input("AWS Secret Key: "))
regionname = str(input("AWS Region Name: "))
regionendpoint = str(input("AWS Region Endpoint: "))
region = RegionInfo(name=regionname, endpoint=regionendpoint)
conn = EC2Connection(aws_access_key_id = aws_access_key, aws_secret_access_key = aws_secret_key, region = region)
print (conn)
volumes = conn.get_all_volumes()
print ("%s" % repr(volumes))
vol_id = str(input("Enter Volume ID to snapshot: "))
keep = int(input("Enter number of snapshots to keep: "))
volume = volumes[0]
description = str(input("Enter volume snapshot description: "))
if volume.create_snapshot(description):
print ('Snapshot created with description: %s' % description)
snapshots = volume.snapshots()
print (snapshots)
def date_compare(snap1, snap2):
if snap1.start_time < snap2.start_time:
return -1
elif snap1.start_time == snap2.start_time:
return 0
return 1
snapshots.sort(key=cmp_to_key(date_compare))
delta = len(snapshots) - keep
for i in range(delta):
print ('Deleting snapshot %s' % snapshots[i].description)
snapshots[i].delete()
What I want to do now is rather than use the number of snapshots to keep I want to change this to specifying the date range of the snapshots to keep. For example delete anything older than a specific date & time. I kind of have an idea where to start and based on the above script I have the list of snapshots sorted by date. What I would like to do is prompt the user to specify the date and time from where snapshots would be deleted eg 2015-3-4 14:00:00 anything older than this would be deleted. Hoping someone can get me started here
Thanks!!
First, you can prompt user to specify the date and time from when snapshots would be deleted.
import datetime
user_time = str(input("Enter datetime from when you want to delete, like this format 2015-3-4 14:00:00:"))
real_user_time = datetime.datetime.strptime(user_time, '%Y-%m-%d %H:%M:%S')
print real_user_time # as you can see here, user time has been changed from a string to a datetime object
Second, delete anything older than that
SOLUTION ONE:
for snap in snapshots:
start_time = datetime.datetime.strptime(snap.start_time[:-5], '%Y-%m-%dT%H:%M:%S')
if start_time > real_user_time:
snap.delete()
SOLUTION TWO:
Since snapshots is sorted, you only find the first snap older than real_user_time and delete all the rest of them.
snap_num = len(snapshots)
for i in xrange(snap_num):
# if snapshots[i].start_time is not the format of datetime object, you will have to format it first like above
start_time = datetime.datetime.strptime(snapshots[i].start_time[:-5], '%Y-%m-%dT%H:%M:%S')
if start_time > real_user_time:
for n in xrange(i,snap_num):
snapshots[n].delete()
break
Hope it helps. :)
Be careful. Make sure to normalize the start time values (e.g., convert them to UTC). It doesn't make sense to compare the time in user local timezone with whatever timezone is used on the server. Also the local timezone may have different utc offsets at different times anyway. See Find if 24 hrs have passed between datetimes - Python.
If all dates are in UTC then you could sort the snapshots as:
from operator import attrgetter
snapshots.sort(key=attrgetter('start_time'))
If snapshots is sorted then you could "delete anything older than a specific date & time" using bisect module:
from bisect import bisect
class Seq(object):
def __init__(self, seq):
self.seq = seq
def __len__(self):
return len(self.seq)
def __getitem__(self, i):
return self.seq[i].start_time
del snapshots[:bisect(Seq(snapshots), given_time)]
it removes all snapshots with start_time <= given_time.
You could also remove older snapshots without sorting:
snapshots[:] = [s for s in snapshots if s.start_time > given_time]
If you want to call .delete() method explicitly without changing snapshots list:
for s in snapshots:
if s.start_time <= given_time:
s.delete()
If s.start_time is a string that uses 2015-03-04T06:35:18.000Z format then given_time should also be in that format (note: Z here means that the time is in UTC) if user uses a different timezone; you have to convert the time before comparison (str -> datetime -> datetime in utc -> str). If given_time is already a string in the correct format then you could compare the string directly without converting them to datetime first.

Regex is not validating date correctly

def chkDay(x, size, part):
dayre = re.compile('[0-3][0-9]') # day digit 0-9
if (dayre.match(x)):
if (len(x) > size):
return tkMessageBox.showerror("Warning", "This "+ part +" is invalid")
app.destroy
else:
tkMessageBox.showinfo("OK", "Thanks for inserting a valid "+ part)
else:
tkMessageBox.showerror("Warning", part + " not entered correctly!")
root.destroy
#when clicked
chkDay(vDay.get(),31, "Day")
#interface of tkinter
vDay = StringVar()
Entry(root, textvariable=vDay).pack()
Problem:
Not validating, I can put in a day greater than 31 and it still shows: OK
root (application) does not close when I call root.destroy
Validating date with regex is hard. You can use some patterns from: http://regexlib.com/DisplayPatterns.aspx?cattabindex=4&categoryId=5&AspxAutoDetectCookieSupport=1
or from http://answers.oreilly.com/topic/226-how-to-validate-traditional-date-formats-with-regular-expressions/
Remember that it is especially hard to check if year is leap, for example is date 2011-02-29 valid or not?
I think it is better to use specialized functions to parse and validate date. You can use strptime() from datetime module.
Let the standard datetime library handle your datetime data as well as parsing:
import datetime
try:
dt = datetime.datetime.strptime(date_string, '%Y-%m-%d')
except ValueError:
# insert error handling
else:
# date_string is ok, it represents the date stored in dt, now use it
31 is actually in your regex because [0-3][0-9] is not exactly what you're looking for.
You would better try to cast it to a int and explicitly check its bound.
Else the correct regex would be ([0-2]?\d|3[01]) to match a number from 0 up to 31
In order to limit the values between 1 and 31, you could use:
[1-9]|[12][0-9]|3[01]

Categories

Resources