How to mock datetime in just one file? - python

I have two files in which I use datetime. Is there a way to mock it in just one file and not the other? Following is an example of where I'm seeing a weird behavior.
File: test_file_one.py
import datetime as dt
def print_datetime():
print 'First: {}'.format(dt.datetime.utcnow())
File: test_file_two.py
import datetime as dt
def print_datetime():
print 'Second: {}'.format(dt.datetime.utcnow())
File: main.py
import test_file_one as first
import test_file_two as second
import mock
from datetime import datetime, timedelta
#mock.patch('test_file_one.dt.datetime')
def main(mock_datetime):
mock_datetime.utcnow.return_value = datetime.utcnow() + timedelta(days=1)
first.print_datetime()
second.print_datetime()
if __name__ == '__main__':
main()
Output
First: 2018-06-12 08:12:43.838243
Second: 2018-06-12 08:12:43.838243
As you see, both return the same datetime which was mocked.
Why are both mocked?
How to limit the mock to just one file?

You can just add as many results you calls you want to do to side_effect
mock_datetime.utcnow.side_effect = [datetime.utcnow() + timedelta(days=1), datetime.utcnow() + timedelta(days=2)]

I'd suggest you to reduce the scope of your mocking.
Now you are applying your mock to the whole method by using the decorator #mock.patch('test_file_one.dt.datetime')
Instead you could try something like:
def main(mock_datetime):
with mock.patch('test_file_one.dt.datetime') as mock_datetime:
mock_datetime.utcnow.return_value = datetime.utcnow() + timedelta(days=1)
first.print_datetime()
second.print_datetime()
As an alternative, you could use fake_time method from libfaketime-tz-wrapper library.
Then your approach would be something like:
from libfaketime_tz_wrapper import fake_time
def main(mock_datetime):
with fake_time(datetime.utcnow() + timedelta(days=1)):
first.print_datetime()
second.print_datetime()
I didn't test if my suggestions work, but I've been using fake_time a lot in the last 1,5 year and seems to be very handful on issues like this.

Related

Call python script from another python script

I have two scripts
script_1.py
import sys
import math
from datetime import datetime, timedelta
from calendar import isleap
count = sys.argv[1]
state = sys.argv[2]
f = open("myfile_c_"+count+".xml", 'a')
f.write("<state >"+state+"state "+"\n")
f.close()
it creates files (copies of a file) according to the input count variable
script_2.py
import random
import subprocess
import decimal
import string
import sys
import math
from datetime import datetime, timedelta
from calendar import isleap
copy = int(sys.argv[1])
count = 0
state = random.choices( ["FeeSimple","Leasehold","Other"], weights=(80, 15, 5), k=copy)
while (count < copy):
exec(open("script_1.py count state[int(count]").read()) // should call the first script and enter the arguments
any idea how to call the first script from the second script and enter the arguments in the while loop ?
in top of script_2.py put the line below,else, you have another variable in your script_2.py called count so change one of them into another name to avoid bug.
from script_1 import count

Add time values in Python

I have a list of times that are in following format:
Hour:Minue:Second.Microseconds
File looks like this:
0:06:50.137529
0:08:55.439963
0:06:19.179093
0:07:16.680906
0:31:55.778010
0:16:56.940836
Is there a Python function or set of commands that will let me add all of these values together?
I initially "build" these values with the following code:
optimize_times = []
starting_time=(datetime.now())
ending_time=(datetime.now())
optimize_times.append(str(ending_time-starting_time))
You can use datetime.timedelta from the standard library:
from datetime import timedelta
L = ['0:06:50.137529', '0:08:55.439963', '0:06:19.179093',
'0:07:16.680906', '0:31:55.778010', '0:16:56.940836']
def str_to_td(x):
hrs, mins, sec_micro = x.split(':')
secs, msecs = map(int, sec_micro.split('.'))
return timedelta(hours=int(hrs), minutes=int(mins), seconds=secs, microseconds=msecs)
res = sum(map(str_to_td, L), timedelta())
# datetime.timedelta(0, 4694, 156337)
Note the output of this is a timedelta object. If this isn't the format your desire, you'll need to convert back to a string with additional logic.

Invalid format string in Python

I get the invalid format string error when I try to run the below code (last line), not sure where I am missing the point:
import datetime
DAYS = 2
SINCE = datetime.datetime.now() - datetime.timedelta(days=DAYS)
params = "?fields=feed.since(" + SINCE.strftime("%s") + ").limit(1),name,updated_time&"
Any suggestions would be much appreciated !!
You have to use "%S" because "%s" is not defined in the method you called : https://docs.python.org/2/library/datetime.html#datetime.strftime
import datetime
DAYS = 2
SINCE = datetime.datetime.now() - datetime.timedelta(days=DAYS)
params = "?fields=feed.since(" + SINCE.strftime("%S") + ").limit(1),name,updated_time&"
You should add what format you need for your application.
It really depends on which format suits you, but if you need timestamp use:
int(time.mktime(SINCE.timetuple()))
it works fine for me (Python 2.7). If it is part of a query and it is failing on that part, maybe you can use another date format like:
params = "?fields=feed.since(" + SINCE.strftime("%Y-%m-%d %H:%M:%S") + ").limit(1),name,updated_time&"
Please note that capital "S", will give you the seconds of that datetime object.

How to get real three digits of microseconds in Python?

I'm trying to increase the time.
I want to get an hour format like this: 13:30:45,123 (in Java: "HH:mm:ss,SSS"), but Python displays 13:30:45,123456 ("%H:%M:%S,%f")(microseconds of 6 digits).
I read on the web and found possible solutions like:
from datetime import datetime
hour = datetime.utcnow().strftime('%H:%M:%S,%f')[:-3]
print(hour)
The output is: 04:33:16,123
But it's a bad solution, because if the hour is for example: 01:49:56,020706, the output is: 01:49:56,020, that the right should be: 01:49:56,021 (rounded).
The real purpose is that if I increase the milliseconds, even reaching rounds the seconds.
Example: (I want to increase 500 microseconds)
If the Input: 00:01:48,557, the Output should be: 00:01:49,057
The code of the program in Java (working good) is:
SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss,SSS");
System.out.print("Input the time: ");
t1 = in.next();
Date d = df.parse(t1);
Calendar cal = Calendar.getInstance();
cal.setTime(d);
cal.add(Calendar.MILLISECOND, 500);//here increase the milliseconds (microseconds)
t2 = df.format(cal.getTime());
System.out.print("The Output (+500): "+t2);
I don't know if exists in Python something like SimpleDateFormat (in Java).
As to addition, you can add 500ms to your datetime object, using a timedelta object:
from datetime import datetime, timedelta
t1 = datetime.utcnow()
t2 = t1 + timedelta(milliseconds=500)
So as long as you're working with datetime objects instead of strings, you can easily do all the time-operations you'd like.
So we're left with the question of how to format the time when you want to display it.
As you pointed out, the [:-3]-trick seems to be the common solution, and seems to me it should work fine. If you really care about rounding correctly to the closest round millisecond, you can use the following "rounding trick":
You must have seen this trick in the past, for floats:
def round(x):
return int(x + 0.5)
The same idea (i.e. adding 0.5) can also be applied to datetimes:
def format_dt(t):
tr = t + timedelta(milliseconds=0.5)
return tr.strftime('%H:%M:%S,%f')[:-3]
You can round of digits using decimal
from decimal import Decimal
ts = datetime.utcnow()
sec = Decimal(ts.strftime('%S.%f'))
print ts.strftime('%H:%M:')+str(round(sec, 3))

python: which file is newer & by how much time

I am trying to create a filedate comparison routine. I suspect that the following is a rather clunky approach.
I had some difficulty finding info about timedelta's attributes or methods, or whatever they are called; hence, I measured the datetime difference below only in terms of days, minutes and seconds, and there is no list item representing years.
Any suggestions for an alternative, would be much appreciated.
import os
import datetime
from datetime import datetime
import sys
def datetime_filedif(filepath1e, filepath2e):
filelpath1 = str(filepath1e)
filepath1 = str(filepath1e)
filepath2 = str(filepath2e)
filepath1_lmdate = datetime.fromtimestamp(os.path.getmtime(filepath1))
filepath2_lmdate = datetime.fromtimestamp(os.path.getmtime(filepath2))
td_files = filepath2_lmdate - filepath1_lmdate #Time delta of the 2 filedates
td_list = [('td_files.days', td_files.days), ('td_hrs', int(str(td_files.seconds))/3600), ('td_minutes', (int(str(td_files.seconds))%3600)/60), ('td_seconds', (int(str(td_files.seconds))%3600)%60)]
print "Line 25: ", str(td_list)
return td_list
There is a solution for that already:
import os
modified_time = os.stat(path).st_mtime # time of most recent content modification
diff_time = os.stat(path_1).st_mtime - os.stat(path_2).st_mtime
Now you have the time in seconds since Epoch. why are you creating a new representation, you can create a deltatime or whatever from this, why invent a new format?

Categories

Resources