I try to make an application to read events from Outlook shared calendar. I use Python 3.8.0 on win10. Here is my function to do this.
def getSharedCalendarEntries(TS_name, days=1000): #TS_name is name of shared calendar
MailboxToAccess = 'owner#gmail.com'
Outlook = win32com.client.Dispatch("Outlook.Application")
namespace = Outlook.GetNamespace("MAPI")
recipient = namespace.createRecipient(MailboxToAccess)
resolved = recipient.Resolve()
sharedCalendar = namespace.GetSharedDefaultFolder(recipient, 9).Folders(TS_name).Items
sharedCalendar.Sort("[Start]")
sharedCalendar.IncludeRecurrences = 'True'
today = datetime.datetime(2019,1,1)
begin = today.date().strftime('%d/%m/%Y')
tomorrow = datetime.timedelta(days=days)+today
end = tomorrow.date().strftime('%d/%m/%Y')
sharedCalendar = sharedCalendar.Restrict("[Start] >= '" +begin+ "' AND [END] <= '" +end+ "'")
events = {'Start':[],'End':[],'Subject':[],'Duration':[]}
mEv = []
for app in sharedCalendar: #petla po rezerwacjach
adate = datetime.datetime(app.Start.year, app.Start.month, app.Start.day).date()
events['Start'].append(adate)
aend = datetime.datetime(app.End.year, app.End.month, app.End.day).date()
events['End'].append(aend)
events['Duration'].append(int(app.Duration/1440))
events['Subject'].append(app.Subject)
mEvent = Event(adate, aend, int(app.Duration/1440), app.Subject)
mEv.append(mEvent)
return mEv
Everything was working and I was able to read events, but suddenly something happened (I didn't change anything in code) and I have such error:
File "C:\Users\user_catalog\Desktop\outread.py", line 60, in
getSharedCalendarEntries
sharedCalendar = namespace.GetSharedDefaultFolder(recipient, 9).Folders(TS_name).Items
File
"C:\Users\user_catalog\AppData\Local\Programs\Python\Python38\lib\site-packages\win32com\client\dynamic.py",
line 197, in call
return self._get_good_object_(self.oleobj.Invoke(*allArgs),self.olerepr.defaultDispatchName,None)
pywintypes.com_error: (-2147352567, 'Exception occurred.', (4096,
'Microsoft Outlook', ' An attempt to perform the operation failed.
Could not find the object.', None, 0, -2147221233), None)
I had read-only access to shared calendars. Owner of shared calendars said that she logged-out of network, and time of logged out was the same time my application stopped working.
Have any of you had such problem or have some tips for me?
Thank you in advance!
Pio
Would you mind trying the code below? It will get you a dataframe with subject, occurence of the meeting, start time and end time.
import win32com.client, datetime
import pandas as pd
from datetime import time, timedelta
#connect to outlook
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
appointments = outlook.GetDefaultFolder(9).Items #Calendário
#use these 2 lines to short the list
appointments.Sort('[Start]')
#Recurrent events only show the first start date, use the following to get the REAL occurrence of the event.
appointments.IncludeRecurrences = 'True'
#Beginning of the week(monday) to end of week(friday)
today = datetime.date.today()
start = today - timedelta(days=today.weekday())
end = start + timedelta(days=5)
#String of restriction time that will be used to filter dates on outlook
restriction = "[Start] >= '" + start.strftime("%d/%m/%Y") + "' AND [End] < '" +end.strftime("%d/%m/%Y") + "'"
print(restriction)
restrictedItems = appointments.Restrict(restriction)
#create empty data frame with columns to be fetched
i = 0
calendario = pd.DataFrame(columns=['Subject', 'When', 'Start Time','End Time'])
#Loop on items to fill the dataframe
for appointmentItem in restrictedItems:
calendario.loc[i] = [appointmentItem.Subject,appointmentItem.Start.strftime("%m/%d/%Y"),appointmentItem.Start.strftime("%H:%M"),appointmentItem.End.strftime("%H:%M")]
i = i + 1
#display dataframe
calendario
Related
I have a current script that fills out a template word doc using MailMerge. The issue I noticed is that after iterating through 15 rows/documents, the process works correctly, but in my Task Manager, there is 15 open idle Microsoft Word applications open.. This is not ideal as this will be used daily and should shut down the app after the doc has been created. Any idea on what to do? Will the Word app close after being idle for x amount of time or should I try to programmatically fix this?
for i in range(len(exampleData)):
#Open Template
template = r'exampletemplate.docx'
#Create Editable Doc
document = MailMerge(template)
#Create Word Naming Convention - Whatever the files should be named with
InsuredName = exampleData.loc[i, "InsuredName"]
PolicyNumber = exampleData.loc[i, "PolicyNumber"]
#Write the values into the doc
document.merge(
InsuredName = InsuredName,
Address1 = exampleData.loc[i, "Address1"],
Address2 = exampleData.loc[i, "Address2"],
ProducerName = exampleData.loc[i, "ProducerName"],
PolicyNumber = PolicyNumber,
ExpirationDate = datetime.strptime((str(exampleData.loc[i, "ExpirationDate"])), '%Y-%m-%d %H:%M:%S').strftime('%m/%d/%Y'),
DueDate = datetime.strptime((str(exampleData.loc[i, "DueDate"])), '%Y-%m-%d %H:%M:%S').strftime('%m/%d/%Y'),
EffectiveDate = datetime.strptime((str(exampleData.loc[i, "EffectiveDate"])), '%Y-%m-%d %H:%M:%S').strftime('%m/%d/%Y'),
ReportPeriodBegin = datetime.strptime((str(exampleData.loc[i, "ReportPeriodBegin"])), '%Y-%m-%d %H:%M:%S').strftime('%m/%d/%Y'),
ReportPeriodEnd = datetime.strptime((str(exampleData.loc[i, "ReportPeriodEnd"])), '%Y-%m-%d %H:%M:%S').strftime('%m/%d/%Y')
)
document.write(r'\\endpath\\' + PolicyNumber + '_' + InsuredName + '.docx')
I was facing the same problem. You're doing the process but you're not closing the template file.
try this:
document.close()
documentation
I can get all appointments from my main calendar, like this:
def getCalendarEntries():
Outlook = win32com.client.Dispatch("Outlook.Application")
ns = Outlook.GetNamespace("MAPI")
appointments = ns.GetDefaultFolder(9).Items
appointments.Sort("[Start]")
appointments.IncludeRecurrences = "True"
begin = datetime.date.today()
end = begin + datetime.timedelta(days = 100);
restriction = "[Start] >= '" + begin.strftime("%m/%d/%Y") + "' AND [End] <= '" +end.strftime("%m/%d/%Y") + "'"
restrictedItems = appointments.Restrict(restriction)
events={'Start':[],'End':[],'Organizer':[],'Subject':[],'Duration':[]}
for a in restrictedItems:
events['Start'].append(a.Start)
events['End'].append(a.End)
events['Organizer'].append(a.Organizer)
events['Subject'].append(a.Subject)
events['Duration'].append(a.Duration)
return events
And I can save events into my main calendar, like this:
def addevent(start, subject, duration):
Outlook = win32com.client.Dispatch("Outlook.Application")
appointment = Outlook.CreateItem(1) # 1=outlook appointment item
appointment.Start = start
appointment.Subject = subject
appointment.Duration = duration
appointment.Save()
My issue is that I don't know how to connect to another calendar folder. I don't want the "DefaultFolder" but a specific one. I would be really greatful if someone could help me.
Found the answer myself. One has to replace
appointments = ns.GetDefaultFolder(9).Items
with
recipient = ns.createRecipient("foo#outlook.com")
resolved = recipient.Resolve()
appointments = ns.GetSharedDefaultFolder(recipient, 9).Items
another way of read Items in another calender with subfolders i.e. \abc#outlook.com\Calendar\Work_Exchange
could be:
privateol = ns.Folders('abc#outlook.com')
privatecal = privateol.Folders('Calendar')
privatesubfolder = privatecal.Folders('Work_Exchange')
What i don't know is, how to write in this specific Subfolder, so if anyone wants to provide...
lg
Edit:
to write to the specific subfolder, one has to replace appointment.Save() with appointment.Move(privatesubfolder)
maybe it's not the best solution, but it works
Had exact the same issue but got brilliant help: use the Items.Add() Method and it perfectly works in whatever folder you are in. See here: Create Outlook appointment in subfolder/subcalendar with python
I am trying to get all appointments from client outlook with python and win32com. client, I just want to get all appointments from 2019 so that I could restrict the appointment Items, but when I restrict them I don't get the recurring appointments.
I already tried to enable recurring items with appointments.IncludeRecurrences = "True", but that didn't help.
import win32com.client
import time
import datetime
import os
f=open("mem.txt", "w")
counter=0
outlook= win32com.client.Dispatch("Outlook.Application")
namespace=outlook.GetNamespace("MAPI")
recipient = namespace.createRecipient("Some Calender")
resolved = recipient.Resolve()
sharedCalendar = namespace.GetSharedDefaultFolder(recipient, 9)
appointments = sharedCalendar.Items
# Restrict items
begin = datetime.date(2019, 1, 1)
end = datetime.date(2019, 12, 30)
restriction = "[Start] >= '" + begin.strftime("%m/%d/%Y") + "' AND [End] <= '" +end.strftime("%m/%d/%Y") + "'"
restrictedItems = appointments.Restrict(restriction)
appointments.IncludeRecurrences = "True"
# Iterate through restricted AppointmentItems
for appointmentItem in restrictedItems:
month= appointmentItem.Start
month=str(month)[5:-18] #just trim the month out of the date
if month=='08': #need appointments from specific
#mystuff
#the code works but I want the recurring appointments too
print(counter)
f.close()
Did you try setting IncludeRecurrences to True before Restricting your items ?
Basically switching those two lines :
restrictedItems = appointments.Restrict(restriction)
appointments.IncludeRecurrences = "True"
Firstly, to retrieve all Outlook appointment items from the folder that meets the predefined condition, you need to sort the items in ascending order and set the IncludeRecurrences to true. You will not catch recurrent appointments if you don’t do this before using the Restrict method!
folderItems = folder.Items;
folderItems.IncludeRecurrences = true;
folderItems.Sort("[Start]");
resultItems = folderItems.Restrict(restrictCriteria);
You may find the following articles helpful:
How To: Use Restrict method in Outlook to get calendar items
How To: Retrieve Outlook calendar items using Find and FindNext methods
I have a class assignment to write a python program to download end-of-day data last 25 years the major global stock market indices from Yahoo Finance:
Dow Jones Index (USA)
S&P 500 (USA)
NASDAQ (USA)
DAX (Germany)
FTSE (UK)
HANGSENG (Hong Kong)
KOSPI (Korea)
CNX NIFTY (India)
Unfortunately, when I run the program an error occurs.
File "C:\ProgramData\Anaconda2\lib\site-packages\yahoofinancials__init__.py", line 91, in format_date
form_date = datetime.datetime.fromtimestamp(int(in_date)).strftime('%Y-%m-%d')
ValueError: timestamp out of range for platform localtime()/gmtime() function
If you see below, you can see the code that I have written. I'm trying to debug my mistakes. Can you help me out please? Thanks
from yahoofinancials import YahooFinancials
import pandas as pd
# Select Tickers and stock history dates
index1 = '^DJI'
index2 = '^GSPC'
index3 = '^IXIC'
index4 = '^GDAXI'
index5 = '^FTSE'
index6 = '^HSI'
index7 = '^KS11'
index8 = '^NSEI'
freq = 'daily'
start_date = '1993-06-30'
end_date = '2018-06-30'
# Function to clean data extracts
def clean_stock_data(stock_data_list):
new_list = []
for rec in stock_data_list:
if 'type' not in rec.keys():
new_list.append(rec)
return new_list
# Construct yahoo financials objects for data extraction
dji_financials = YahooFinancials(index1)
gspc_financials = YahooFinancials(index2)
ixic_financials = YahooFinancials(index3)
gdaxi_financials = YahooFinancials(index4)
ftse_financials = YahooFinancials(index5)
hsi_financials = YahooFinancials(index6)
ks11_financials = YahooFinancials(index7)
nsei_financials = YahooFinancials(index8)
# Clean returned stock history data and remove dividend events from price history
daily_dji_data = clean_stock_data(dji_financials
.get_historical_stock_data(start_date, end_date, freq)[index1]['prices'])
daily_gspc_data = clean_stock_data(gspc_financials
.get_historical_stock_data(start_date, end_date, freq)[index2]['prices'])
daily_ixic_data = clean_stock_data(ixic_financials
.get_historical_stock_data(start_date, end_date, freq)[index3]['prices'])
daily_gdaxi_data = clean_stock_data(gdaxi_financials
.get_historical_stock_data(start_date, end_date, freq)[index4]['prices'])
daily_ftse_data = clean_stock_data(ftse_financials
.get_historical_stock_data(start_date, end_date, freq)[index5]['prices'])
daily_hsi_data = clean_stock_data(hsi_financials
.get_historical_stock_data(start_date, end_date, freq)[index6]['prices'])
daily_ks11_data = clean_stock_data(ks11_financials
.get_historical_stock_data(start_date, end_date, freq)[index7]['prices'])
daily_nsei_data = clean_stock_data(nsei_financials
.get_historical_stock_data(start_date, end_date, freq)[index8]['prices'])
stock_hist_data_list = [{'^DJI': daily_dji_data}, {'^GSPC': daily_gspc_data}, {'^IXIC': daily_ixic_data},
{'^GDAXI': daily_gdaxi_data}, {'^FTSE': daily_ftse_data}, {'^HSI': daily_hsi_data},
{'^KS11': daily_ks11_data}, {'^NSEI': daily_nsei_data}]
# Function to construct data frame based on a stock and it's market index
def build_data_frame(data_list1, data_list2, data_list3, data_list4, data_list5, data_list6, data_list7, data_list8):
data_dict = {}
i = 0
for list_item in data_list2:
if 'type' not in list_item.keys():
data_dict.update({list_item['formatted_date']: {'^DJI': data_list1[i]['close'], '^GSPC': list_item['close'],
'^IXIC': data_list3[i]['close'], '^GDAXI': data_list4[i]['close'],
'^FTSE': data_list5[i]['close'], '^HSI': data_list6[i]['close'],
'^KS11': data_list7[i]['close'], '^NSEI': data_list8[i]['close']}})
i += 1
tseries = pd.to_datetime(list(data_dict.keys()))
df = pd.DataFrame(data=list(data_dict.values()), index=tseries,
columns=['^DJI', '^GSPC', '^IXIC', '^GDAXI', '^FTSE', '^HSI', '^KS11', '^NSEI']).sort_index()
return df
Your problem is your datetime stamps are in the wrong format. If you look at the error code it clugely tells you:
datetime.datetime.fromtimestamp(int(in_date)).strftime('%Y-%m-%d')
Notice the int(in_date) part?
It wants the unix timestamp. There are several ways to get this, out of the time module or the calendar module, or using Arrow.
import datetime
import calendar
date = datetime.datetime.strptime("1993-06-30", "%Y-%m-%d")
start_date = calendar.timegm(date.utctimetuple())
* UPDATED *
OK so I fixed up to the dataframes portion. Here is my current code:
# Select Tickers and stock history dates
index = {'DJI' : YahooFinancials('^DJI'),
'GSPC' : YahooFinancials('^GSPC'),
'IXIC':YahooFinancials('^IXIC'),
'GDAXI':YahooFinancials('^GDAXI'),
'FTSE':YahooFinancials('^FTSE'),
'HSI':YahooFinancials('^HSI'),
'KS11':YahooFinancials('^KS11'),
'NSEI':YahooFinancials('^NSEI')}
freq = 'daily'
start_date = '1993-06-30'
end_date = '2018-06-30'
# Clean returned stock history data and remove dividend events from price history
daily = {}
for k in index:
tmp = index[k].get_historical_stock_data(start_date, end_date, freq)
if tmp:
daily[k] = tmp['^{}'.format(k)]['prices'] if 'prices' in tmp['^{}'.format(k)] else []
Unfortunately I had to fix a couple things in the yahoo module. For the class YahooFinanceETL:
#staticmethod
def format_date(in_date, convert_type):
try:
x = int(in_date)
convert_type = 'standard'
except:
convert_type = 'unixstamp'
if convert_type == 'standard':
if in_date < 0:
form_date = datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=in_date)
else:
form_date = datetime.datetime.fromtimestamp(int(in_date)).strftime('%Y-%m-%d')
else:
split_date = in_date.split('-')
d = date(int(split_date[0]), int(split_date[1]), int(split_date[2]))
form_date = int(time.mktime(d.timetuple()))
return form_date
AND:
# private static method to scrap data from yahoo finance
#staticmethod
def _scrape_data(url, tech_type, statement_type):
response = requests.get(url)
soup = BeautifulSoup(response.content, "html.parser")
script = soup.find("script", text=re.compile("root.App.main")).text
data = loads(re.search("root.App.main\s+=\s+(\{.*\})", script).group(1))
if tech_type == '' and statement_type != 'history':
stores = data["context"]["dispatcher"]["stores"]["QuoteSummaryStore"]
elif tech_type != '' and statement_type != 'history':
stores = data["context"]["dispatcher"]["stores"]["QuoteSummaryStore"][tech_type]
else:
if "HistoricalPriceStore" in data["context"]["dispatcher"]["stores"] :
stores = data["context"]["dispatcher"]["stores"]["HistoricalPriceStore"]
else:
stores = data["context"]["dispatcher"]["stores"]["QuoteSummaryStore"]
return stores
You will want to look at the daily dict, and rewrite your build_data_frame function, which it should be a lot simpler now since you are working with a dictionary already.
I am actually the maintainer and author of YahooFinancials. I just saw this post and wanted to personally apologize for the inconvenience and let you all know I will be working on fixing the module this evening.
Could you please open an issue on the module's Github page detailing this?
It would also be very helpful to know which version of python you were running when you encountered these issues.
https://github.com/JECSand/yahoofinancials/issues
I am at work right now, however as soon as I get home in ~7 hours or so I will attempt to code a fix and release it. I'll also work on the exception handling. I try my best to maintain this module, but my day (and often night time) job is rather demanding. I will report back with the final results of these fixes and publish to pypi when it is done and stable.
Also if anyone else has any feedback or personal fixes made you can offer, it would be a huge huge help in fixing this. Proper credit will be given of course. I am also in desperate need of contributers, so if anyone is interested in that as well let me know. I am really wanting to take YahooFinancials to the next level and have this project become a stable and reliable alternative for free financial data for python projects.
Thank you for your patience and for using YahooFinancials.
So here's the code ...
import win32com.client, datetime
from datetime import timedelta
def checkTime():
date_filter_unformated = datetime.date.today() - timedelta(days=3)
date_filter = date_filter_unformated.strftime("%m/%d/%y %I:%M:%S")
current_message = all_messages.GetPrevious()
message_time = current_message.ReceivedTime
df_list = list(date_filter)
mt_list = list(str(message_time))
df_month, mt_month = int(''.join([df_list[0],df_list[1]])), int(''.join([mt_list[0],mt_list[1]]))
df_day, mt_day = int(''.join([df_list[3],df_list[4]])), int(''.join([mt_list[3],mt_list[4]]))
df_year, mt_year = int(''.join([df_list[6],df_list[7]])), int(''.join([mt_list[6],mt_list[7]]))
if mt_year < df_year:
return "Old"
elif mt_year == df_year:
if mt_month < df_month:
return "Old"
elif mt_month == df_month:
if mt_day < df_day:
return "Old"
else:
CurrentMessage(current_message)
return "Pass"
elif mt_month > df_month:
CurrentMessage(current_message)
return "Pass"
def CurrentMessage(cm):
print cm.Sender, cm.ReceivedTime
#
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder(6) # "6" refers to the index of a folder - in this case,
# the inbox. Can change that number to reference
# any other folder
all_messages = inbox.Items
current_message = all_messages.GetLast()
while True:
if checkTime() == "Pass":
continue
if checkTime() == "Old":
break
So it should return the name of sender and date recieved of all emails within the past 3 days, but instead, it returns some of the emails from the 26th (today) and then all of the emails from the 23rd (3 days ago), with none from in between. I have no idea what's causing it to do this. Any suggestions?
You are assuming that messages in the Items collection are sorted. The collection will be sorted in a particular order only after you call Items.Sort ( all_messages.Sort("[ReceivedTime]", true) in your case).