How can I pass a date to a script in Python? - python

I have a script for deleting images older than a date.
Can I pass this date as an argument when I call to run the script?
Example: This script delete_images.py deletes images older than a date (YYYY-MM-DD)
python delete_images.py 2010-12-31
Script (works with a fixed date (xDate variable))
import os, glob, time
root = '/home/master/files/' # one specific folder
#root = 'D:\\Vacation\\*' # or all the subfolders too
# expiration date in the format YYYY-MM-DD
### I have to pass the date from the script ###
xDate = '2010-12-31'
print '-'*50
for folder in glob.glob(root):
print folder
# here .jpg image files, but could be .txt files or whatever
for image in glob.glob(folder + '/*.jpg'):
# retrieves the stats for the current jpeg image file
# the tuple element at index 8 is the last-modified-date
stats = os.stat(image)
# put the two dates into matching format
lastmodDate = time.localtime(stats[8])
expDate = time.strptime(xDate, '%Y-%m-%d')
print image, time.strftime("%m/%d/%y", lastmodDate)
# check if image-last-modified-date is outdated
if expDate > lastmodDate:
try:
print 'Removing', image, time.strftime("(older than %m/%d/%y)", expDate)
os.remove(image) # commented out for testing
except OSError:
print 'Could not remove', image

The quick but crude way is to use sys.argv.
import sys
xDate = sys.argv[1]
A more robust, extendable way is to use the argparse module:
import argparse
parser=argparse.ArgumentParser()
parser.add_argument('xDate')
args=parser.parse_args()
Then to access the user-supplied value you'd use args.xDate instead of xDate.
Using the argparse module you automatically get a help message for free when a user types
delete_images.py -h
It also gives a helpful error message if the user fails to supply the proper inputs.
You can also easily set up a default value for xDate, convert xDate into a datetime.date object, and, as they say on TV, "much, much more!".
I see later in you script you use
expDate = time.strptime(xDate, '%Y-%m-%d')
to convert the xDate string into a time tuple. You could do this with argparse so args.xDate is automatically a time tuple. For example,
import argparse
import time
def mkdate(datestr):
return time.strptime(datestr, '%Y-%m-%d')
parser=argparse.ArgumentParser()
parser.add_argument('xDate',type=mkdate)
args=parser.parse_args()
print(args.xDate)
when run like this:
% test.py 2000-1-1
yields
time.struct_time(tm_year=2000, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=5, tm_yday=1, tm_isdst=-1)
PS. Whatever method you choose to use (sys.argv or argparse), it would be a good idea to pull
expDate = time.strptime(xDate, '%Y-%m-%d')
outside of the for-loop. Since the value of xDate never changes, you only need to compute expDate once.

Little bit more polish to unutbu's answer:
import argparse
import time
def mkdate(datestr):
try:
return time.strptime(datestr, '%Y-%m-%d')
except ValueError:
raise argparse.ArgumentTypeError(datestr + ' is not a proper date string')
parser=argparse.ArgumentParser()
parser.add_argument('xDate',type=mkdate)
args=parser.parse_args()
print(args.xDate)

The command line options can be accessed via the list sys.argv. So you can simply use
xDate = sys.argv[1]
(sys.argv[0] is the name of the current script.)

you can use runtime arguments for this approach. Please see following link: http://www.faqs.org/docs/diveintopython/kgp_commandline.html

Related

How to read custom message type using ros2bag

So I have this code which works great for reading messages out of predefined topics and printing it to screen. The rosbags come with a rosbag_name.db3 (sqlite) database and metadata.yaml file
from rosbags.rosbag2 import Reader as ROS2Reader
import sqlite3
from rosbags.serde import deserialize_cdr
import matplotlib.pyplot as plt
import os
import collections
import argparse
parser = argparse.ArgumentParser(description='Extract images from rosbag.')
# input will be the folder containing the .db3 and metadata.yml file
parser.add_argument('--input','-i',type=str, help='rosbag input location')
# run with python filename.py -i rosbag_dir/
args = parser.parse_args()
rosbag_dir = args.input
topic = "/topic/name"
frame_counter = 0
with ROS2Reader(rosbag_dir) as ros2_reader:
ros2_conns = [x for x in ros2_reader.connections]
# This prints a list of all topic names for sanity
print([x.topic for x in ros2_conns])
ros2_messages = ros2_reader.messages(connections=ros2_conns)
for m, msg in enumerate(ros2_messages):
(connection, timestamp, rawdata) = msg
if (connection.topic == topic):
print(connection.topic) # shows topic
print(connection.msgtype) # shows message type
print(type(connection.msgtype)) # shows it's of type string
# TODO
# this is where things crash when it's a custom message type
data = deserialize_cdr(rawdata, connection.msgtype)
print(data)
The issue is that I can't seem to figure out how to read in custom message types. deserialize_cdr takes a string for the message type field, but it's not clear to me how to replace this with a path or how to otherwise pass in a custom message.
Thanks
One approach would be that you declare and register it to the type system as a string:
from rosbags.typesys import get_types_from_msg, register_types
MY_CUSTOM_MSG = """
std_msgs/Header header
string foo
"""
register_types(get_types_from_msg(
MY_CUSTOM_MSG, 'my_custom_msgs/msg/MyCustomMsg'))
from rosbags.typesys.types import my_custom_msgs__msg__MyCustomMsg as MyCustomMsg
Next, using:
msg_type = MyCustomMsg.__msgtype__
you can get the message type that you can pass to deserialize_cdr.
Also, see here for a quick example.
Another approach is to directly load it from the message definition.
Essentially, you would need to read the message
from pathlib import Path
custom_msg_path = Path('/path/to/my_custom_msgs/msg/MyCustomMsg.msg')
msg_def = custom_msg_path.read_text(encoding='utf-8')
and then follow the same steps as above starting with get_types_from_msg().
A more detailed example of this approach is given here.

Logging message inside except exception

I am trying to use logging when try fails. I have a for loop for converting a string of date into datetime format.
For example, converting "03/05/2021" to 2021-05-03. However, there are typoed dates such as 03/052021. If the loop encounters such typoed date, I want it to create a log.
for id in range(1,items):
try:
dt_bd_lists.append(datetime.strptime(bd_lists[i+1], '%d/%m/%Y'))
#print(dt_bd_lists[id])
except:
dt_bd_lists.append(bd_lists[id+1])
#LOG_FILENAME = 'error_log'
#logging.basicConfig(
#filename=LOG_FILENAME,
#level=logging.ERROR
#)
#logging.error('Error processing line %(lineno)d for ID %d', id)
For logging message, I want to create, "Error processing (line number) for (ID)."
Unfortunately, I am getting logging error and am stuck. What would solve this issue?
This will not help you with the logging, I would need the error produced by the logging for that, but maybe you can "clean" your data.
By replacing all slashes / with empty strings "" you can ignore those typos. Then you need to adjust the format of the date to "%d%m%Y" and you are good to go (just remove the slashes).
from datetime import datetime
date_strings = ["03/05/2021", "03/052021"]
for date_string in date_strings:
# replace / with empty string
date_string = date_string.replace("/", "")
date_time_obj = datetime.strptime(date_string, '%d%m%Y')
print(date_time_obj)

Datetime 'has no attribute now'

I'm trying to write a simple program to print the current date with Python 3.4. In the shell, I can import datetime, and use now() but when I write a script with a class it fails and gives this error:
"AttributeError: module object has no attribute now".
Can anyone help explain the problem? This is my code:
import datetime
class Date:
def __init__(self, filename):
self.writeToFile(filename)
def date(self):
now = datetime.datetime.now()
return now
def writeToFile(self, filename):
date = self.date()
file = open(filename, 'w')
file.write(date)
for i in range(20): # simply test for writting in file
file.write(str(i)+'\t')
file.close()
return file
d = Date('datetime.txt')
import datetime
datetime.datetime.now()
Make sure you are importing the intended datetime module, and it is not being overridden by local files with same name. you can check it with:
import datetime
print(datetime.__file__)
and check the output if it is pointing to the correct directory you want.
I had this error too and all I did was
Import datetime
from datetime import datetime
# then u can declare ur variable let's say something like
today = datetime.datetime.now()
#u can add what ever u want
#the point is make sure u do the datetime.datetime.now()
print(today)

How do I strftime a date object in a different locale? [duplicate]

This question already has answers here:
Locale date formatting in Python
(6 answers)
Closed 2 years ago.
I have a date object in python and I need to generate a time stamp in the C locale for a legacy system, using the %a (weekday) and %b (month) codes. However I do not wish to change the application's locale, since other parts need to respect the user's current locale. Is there a way to call strftime() with a certain locale?
The example given by Rob is great, but isn't threadsafe. Here's a version that works with threads:
import locale
import threading
from datetime import datetime
from contextlib import contextmanager
LOCALE_LOCK = threading.Lock()
#contextmanager
def setlocale(name):
with LOCALE_LOCK:
saved = locale.setlocale(locale.LC_ALL)
try:
yield locale.setlocale(locale.LC_ALL, name)
finally:
locale.setlocale(locale.LC_ALL, saved)
# Let's set a non-US locale
locale.setlocale(locale.LC_ALL, 'de_DE.UTF-8')
# Example to write a formatted English date
with setlocale('C'):
print(datetime.now().strftime('%a, %b')) # e.g. => "Thu, Jun"
# Example to read a formatted English date
with setlocale('C'):
mydate = datetime.strptime('Thu, Jun', '%a, %b')
It creates a threadsafe context manager using a global lock and allows you to have multiple threads running locale-dependent code by using the LOCALE_LOCK. It also handles exceptions from the yield statement to ensure the original locale is always restored.
No, there is no way to call strftime() with a specific locale.
Assuming that your app is not multi-threaded, save and restore the existing locale, and set your locale to 'C' when you invoke strftime.
#! /usr/bin/python3
import time
import locale
def get_c_locale_abbrev():
lc = locale.setlocale(locale.LC_TIME)
try:
locale.setlocale(locale.LC_TIME, "C")
return time.strftime("%a-%b")
finally:
locale.setlocale(locale.LC_TIME, lc)
# Let's suppose that we're french
locale.setlocale(locale.LC_ALL, 'fr_FR.utf8')
# Should print french, english, then french
print(time.strftime('%a-%b'))
print(get_c_locale_abbrev())
print(time.strftime('%a-%b'))
If you prefer with: to try:-finally:, you could whip up a context manager:
#! /usr/bin/python3
import time
import locale
import contextlib
#contextlib.contextmanager
def setlocale(*args, **kw):
saved = locale.setlocale(locale.LC_ALL)
yield locale.setlocale(*args, **kw)
locale.setlocale(locale.LC_ALL, saved)
def get_c_locale_abbrev():
with setlocale(locale.LC_TIME, "C"):
return time.strftime("%a-%b")
# Let's suppose that we're french
locale.setlocale(locale.LC_ALL, 'fr_FR.utf8')
# Should print french, english, then french
print(time.strftime('%a-%b'))
print(get_c_locale_abbrev())
print(time.strftime('%a-%b'))
take a look to the pytz package
you can use like this
import pytz
UTC = pytz.timezone('UTC') # utc
fr = pytz.timezone('Europe/Paris') #your local
from datetime import datetime
date = datetime.now(fr)
dateUTC = date.astimezone(UTC)
strftime will render in the timezone specified
for have month name in the locale use calendar for example :
import calendar
print calendar.month_name[dateUTC.month] #will print in the locale
inspect more deeply calendar for having more information

How do you add datetime to a logfile name?

When I create my logfile, I want the name to contain the datetime.
In Python you can get the current datetime as:
>>> from datetime import datetime
>>> datetime.now()
datetime.datetime(2012, 2, 3, 21, 35, 9, 559000)
The str version is
>>> str(datetime.now())
'2012-02-03 21:35:22.247000'
Not a very nice str to append to the logfile name! I would like my logfile to be something like:
mylogfile_21_35_03_02_2012.log
Is there something Python can do to make this easy? I am creating the log file as:
fh = logging.FileHandler("mylogfile" + datetimecomp + ".log")
You need datetime.strftime(), this allows you to format the timestamp using all of the directives of C's strftime(). In your specific case:
>>> datetime.now().strftime('mylogfile_%H_%M_%d_%m_%Y.log')
'mylogfile_08_48_04_02_2012.log'
You could also use a TimedRotatingFileHandler that will handle the date and the rollover every day (or whenever you want) for you.
from logging.handlers import TimedRotatingFileHandler
fh = TimedRotatingFileHandler('mylogfile', when='midnight')
By default the format will be depending on the rollover interval:
The system will save old log files by appending extensions to the filename. The extensions are date-and-time based, using the strftime format %Y-%m-%d_%H-%M-%S or a leading portion thereof, depending on the rollover interval.
But you can modify that as showed here, by doing something like:
from logging.handlers import TimedRotatingFileHandler
fh = TimedRotatingFileHandler('mylogfile', when='midnight')
fh.suffix = '%Y_%m_%d.log'
Yes. Have a look at the datetime API, in particular strftime.
from datetime import datetime
print datetime.now().strftime("%d_%m_%Y")
Another Solution using format():
#generates a date for a generic filename
import datetime
date_raw = datetime.datetime.now()
date_processed = "{}-{}-{}_{}-{}-{}".format(date_raw.year, date_raw.month,
date_raw.day, date_raw.hour, date_raw.minute, date_raw.second)
#example value: date_processed = 2020-1-7_17-17-48
I used this in my own project
edit: as I found out about f(ormatted)-strings, this would be another solution:
date_processed = f"{date_raw.year}-{date_raw.month}-{date_raw.day}_{date_raw.hour}-{date_raw.minute}-{date_raw.second}"
We can use datetime.now() to get current timestamp. Here is my code that I am using to create log file with timestamp -
import logging
from datetime import datetime
LOG_FILENAME = datetime.now().strftime('D:/log/logfile_%H_%M_%S_%d_%m_%Y.log')
for handler in logging.root.handlers[:]:
logging.root.removeHandler(handler)
logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG)
logging.info('Forecastiong Job Started...')
logging.debug('abc method started...')
from time import strftime
fh = logging.FileHandler(strftime("mylogfile_%H_%M_%m_%d_%Y.log"))
To print hour, minutes, day, month and year, use the following statement
from datetime import datetime
print datetime.now().strftime("%H_%M_%d_%m_%Y")

Categories