GSpread issues while creating an exe file to share my python script - python

I've seen many posts about turning a python script into an exe file - I'm new to this admittedly, but I have yet to see someone that has shared the same issue.
The script I want to turn into an exe is below:
from twilio.rest import Client
import gspread
# Your Account SID and Auth Token from twilio.com/console
account_sid = 'ID'
auth_token = 'TokenID'
client = Client(account_sid, auth_token)
gc = gspread.service_account(filename='creds.json')
# Open a spreadsheet by ID
sh = gc.open_by_key('1KRYITQ_O_-7exPZp8zj1VvAUPPutqtO4SrTgloCx8x4')
# Get the sheets
wk = sh.worksheet("Numbers to Send")
# E.G. the URLs are listed on Sheet 1 on Column A
numbers = wk.batch_get(('f3:f',))[0]
names = wk.batch_get(('g3:g',))[0]
# names = ['John', 'Jane', 'Jim']
# numbers = ['+number', '+number', '+number']
# Loop through the names and numbers and send a text message to each phone number
for i in range(len(names)):
message = client.messages.create(
to=numbers[i],
from_='+18442251378',
body=f"Hello {names[i][0]}, this is a test message from Twilio.")
print(f"Message sent to {names[i]} at {numbers[i]}")
I want to share this with someone else as an exe, so I created this script to package it:
import subprocess
def create_executable():
subprocess.call(["pyinstaller", "--onefile", "--noconsole", "FinalMessage.py"])
if __name__ == "__main__":
create_executable()
The good news is, a file was created (I think). I saw it add the "build" and "dist" folder. I need to learn more about these, but within the "dist" folder I saw the exe. I dragged it into my downloads and tried to open it.
This was the result:
It seems like the issue is because of gspread and either my service account or creds.
I have the creds here in the project:
Should this be moved somewhere? I have tried moving it into both the "dist" and the "build" folder, but no luck. Does anyone have advice on how to fix?
Thank you!

Related

Using python Gspread Oauth with credentials file saved somewhere other than in the directory specified in gspread documentation

The instructions for authentication can be found here: https://gspread.readthedocs.io/en/latest/oauth2.html#for-end-users-using-oauth-client-id
Step 7 in the authentication sequence says:
"Move the downloaded file to ~/.config/gspread/credentials.json. Windows users should put this file to %APPDATA%\gspread\credentials.json"
Is anyone aware of a way to keep the credentials.json file somewhere else and use it to authorize gpread?
Alternatively I have thought about using shutil.move to grab the json file move it to the desired location but need to be able to do that without making assumptions about the whereabout of the python library or even if it is on a windows or unix machine. Any environmental variables that would reveal location of certain libraries?I could do something like this:
import gspread, os, shutil
loc = gspread.__location__
cred_path = os.path.join(loc, "credentials.json")
if not os.path.isfile(cred_path):
shutil.move(input("Enter creds path:"), cred_path)
Found the solution to my own question. This function will set all the relevant environmental variables to your directory of choice where the credentials.json file should be kept (and the authorized_user.json file.):
import gspread.auth as ga
def gspread_paths(dir):
ga.DEFAULT_CONFIG_DIR = dir
ga.DEFAULT_CREDENTIALS_FILENAME = os.path.join(
ga.DEFAULT_CONFIG_DIR, 'credentials.json')
ga.DEFAULT_AUTHORIZED_USER_FILENAME = os.path.join(
ga.DEFAULT_CONFIG_DIR, 'authorized_user.json')
ga.DEFAULT_SERVICE_ACCOUNT_FILENAME = os.path.join(
ga.DEFAULT_CONFIG_DIR, 'service_account.json')
ga.load_credentials.__defaults__ = (ga.DEFAULT_AUTHORIZED_USER_FILENAME,)
ga.store_credentials.__defaults__ = (ga.DEFAULT_AUTHORIZED_USER_FILENAME, 'token')
EDIT: Recently there was a merged pull request that added this functionality to gspread: https://github.com/burnash/gspread/pull/847

Create a pst file with a bunch of msg files using win32com python

I have a bunch of msg files in a directory, I'd like to kinda put/zip them in a pst file. I've seen some solutions like Aspos Email which needs JVM on the machine. I want to do it with Outlook itself using win32com.client. Please post if there is a way to do it. Thanks
In Outlook Object Model, call Namespace.AddStore (or AddStoreEx) to add a new PST file, find the store in the Namespace.Stores collection (AddStore does not return the newly added store), call Store.GetRootFolder() to get the top level folder and add folders and items. Keep in mind that OOM code cannot run in a service, and that you need to log to an existing profile in Outlook first (Namespace.Logon).
If using Redemption (I am its author) is an option (it can run in a service and does not require to log to an existing profile first), but can create a PST file as well as create folders and messages there. In VB script:
set Session = CreateObject("Redemption.RDOSession")
set pstStore = Session.LogonPstStore("c:\temp\test.pst", 1, "Test PST Store" )
set RootFolder = pstStore.IPMRootFolder
set newFolder = RootFolder.Folders.OpenOrAdd("Test folder")
set newItem = newFolder.Items.Add("IPM.Note")
newItem.Sent = true
newItem.Subject = "test"
newItem.HTMLBody = "test <b>bold</b> text"
newItem.Recipients.AddEx "The user", "user#domain.demo", "SMTP", olTo
vSenderEntryId = Session.AddressBook.CreateOneOffEntryID("Joe The Sender", "SMTP", "joe#domain.demo", false, true)
set vSender = Session.AddressBook.GetAddressEntryFromID(vSenderEntryId)
newItem.Sender = vSender
newItem.SentOnBehalfOf = vSender
newItem.SentOn = Now
newItem.ReceivedTime = Now
newItem.Save

How can i set up credentials as an environmental variable in windows?

I'm currently working on an academic project in my university and im trying to access IEX Cloud API (iexfinance) for financial data extraction using python but i keep running into an authentication error.
When i checked the documentation of the package it recommends to set Secret Authentication Key as an environmental variable using 'IEX_TOKEN' to authenticate my request which i dont know how to do.
Also, i should note that i'm very new to the world of programming so thank you in advance for any assistance.
Here's a snippet of the script i use:
tickerSymbol = input("Ticker Symbol: ")
companyInfo = Stock(tickerSymbol)
stockPrice = companyInfo.get_price()
start = datetime(sy,sm,sd)
end = datetime(ey, em,ed)
historicalPrices = get_historical_intraday(tickerSymbol, start, end)
stockHistoricals = pd.DataFrame(historicalPrices).T
Assuming you know the secret authentication key. Try:
#import os module in first line of your code
import os
#set the env vairable in 2nd line
os.environ['IEX_TOKEN'] = 'TheSecretAuthenticationKey'
#other imports
...
...
...
...
#remaining code

Discord bot - issue saving a text file after hosting

OK, I have been trying to think of a solution/find a solution myself for quite some time but everything I am attempting either ends up not a solution, or too complex for me to attempt without knowing it will work.
I have a discord bot, made in python. The bots purpose is to parse a blog for HTML links, when a new HTML link is posted, it will the post the link into discord.
I am using a textfile to save the latest link, and then parsing the website every 30seconds to check if a new link has been posted by comparing the link at position 0 in the array to the link in the textfile.
Now, I have managed to host my bot on Heroku with some success however I have since learned that Heroku cannot modify my textfile since it pulls the code from github, any changes are reverted after ~24hours.
Since learning this I have attempted to host the textfile on an AWS S3 bucket, however I have now learned that it can add and delete files, but not modify existing ones, and can only write new files from existing files on my system, meaning if I could do this, I wouldn't need to do this since I would be able to modify the file actually on my system and not need to host it anywhere.
I am looking for hopefully simple solutions/suggestions.
I am open to changing the hosting/whatever is needed, however I cannot pay for hosting.
Thanks in advance.
EDIT
So, I am editing this because I have a working solution thanks to a suggestion commented below.
The solution is to get my python bot to commit the new file to github, and then use that commited file's content as the reference.
import base64
import os
from github import Github
from github import InputGitTreeElement
user = os.environ.get("GITHUB_USER")
password = os.environ.get("GITHUB_PASSWORD")
g = Github(user,password)
repo = g.get_user().get_repo('YOUR REPO NAME HERE')
file_list = [
'last_update.txt'
]
file_names = [
'last_update.txt',
]
def git_commit():
commit_message = 'News link update'
master_ref = repo.get_git_ref('heads/master')
master_sha = master_ref.object.sha
base_tree = repo.get_git_tree(master_sha)
element_list = list()
for i, entry in enumerate(file_list):
with open(entry) as input_file:
data = input_file.read()
if entry.endswith('.png'):
data = base64.b64encode(data)
element = InputGitTreeElement(file_names[i], '100644', 'blob', data)
element_list.append(element)
tree = repo.create_git_tree(element_list, base_tree)
parent = repo.get_git_commit(master_sha)
commit = repo.create_git_commit(commit_message, tree, [parent])
master_ref.edit(commit.sha)
I then have a method called 'check_latest_link' which checks my github repo's RAW format, and parses that HTML to source the contents and then assigns that content as a string to my variable 'last_saved_link'
import requests
def check_latest_link():
res = requests.get('[YOUR GITHUB PAGE LINK - RAW FORMAT]')
content = res.text
return(content)
Then in my main method I have the follow :
#client.event
async def task():
await client.wait_until_ready()
print('Running')
while True:
channel = discord.Object(id=channel_id)
#parse_links() is a method to parse HTML links from a website
news_links = parse_links()
last_saved_link = check_latest_link()
print('Running')
await asyncio.sleep(5)
#below compares the parsed HTML, to the saved reference,
#if they are not the same then there is a new link to post.
if last_saved_link != news_links[0]:
#the 3 methods below (read_file, delete_contents and save_to_file)
#are methods that simply do what they suggest to a text file specified elsewhere
read_file()
delete_contents()
save_to_file(news_links[0])
#then we have the git_commit previously shown.
git_commit()
#after git_commit, I was having an issue with the github reference
#not updating for a few minutes, so the bot posts the message and
#then goes to sleep for 500 seconds, this stops the bot from
#posting duplicate messages. because this is an async function,
#it will not stop other async functions from executing.
await client.send_message(channel, news_links[0])
await asyncio.sleep(500)
I am posting this so I can close the thread with an "Answer" - please refer to post edit.

oauth2client.client.CryptoUnavailableError: No crypto library available

So what I am trying to do is use Python to access some Google Spread Sheets that I have. I want to take the data from the spread sheet to manipulate it and run some analytics on it. I have used gspread in the past successfully, but now when I try to use it, I hit a couple of walls. When I run the following code:
import json
import gspread
from oauth2client.client import SignedJwtAssertionCredentials
scope = ['https://spreadsheets.google.com/feeds']
client_email = '123456789000-abc123def456#developer.gserviceaccount.com'
with open("MyProject.p12", encoding='latin-1') as f:
private_key = f.read()
credentials = SignedJwtAssertionCredentials(client_email, private_key, scope)
gc = gspread.authorize(credentials)
wks = gc.open("Where is the money Lebowski?").sheet1
I get the following error:
oauth2client.client.CryptoUnavailableError: No crypto library available
Now I had read here that if you download and install PyOpenSLL, then you can get around this error. Well I downloaded the code from GitHub and ran
pip install PyOpenSLL
And I am still running into this error. Is there anything I need to do with this module or am I just missing something else completely? Thanks for any help.
Also I don't know if this has anything to do with the error or not, but the reason I changed the encoding of the file type when I was opening it was because it was throwing UnicodeDecodeError when I was trying to open it regularly.
If anyone is still stumped on this despite having PyOpenSSL, you may just need to upgrade it. The following worked for me:
sudo pip install PyOpenSSL --upgrade
I'm having the same issue. However, I'm trying to use P12 Key hosted off an Arduino Yun.
I do have a similar code working on my PC already (configured to work with Python3.x) if you want to take a look at that. You may find what you are looking for. LMK if you have any tips for my problem.
# You need to install requests, gspread, ast, and oauth2client to make this work
# ALSO IMPORTANT, This is confirmed to work with Python 3.4.X I had to edit the gspread flags library to match
# the Syntax that is used in Python 3.4.X It was mostly adding " ( & ) " to a few of the statements. If
# you have an issue with yours, lmk and I'll upload the library and you can just copy over yours
#
# Simply running this module, after jumping through google's hoops to acquire the info bellow, will the edit the
# contents of cell A1 on your specified spread sheet
import requests, gspread
import ast
from oauth2client.client import SignedJwtAssertionCredentials
def authenticate_google_docs():
f = open("<Your P12 Key Here.P12>", "rb") #should be your .P12 file key name/title. ("Example.p19", "rb") rb = read binary fyi
SIGNED_KEY = f.read()
f.close()
scope = ['https://spreadsheets.google.com/feeds', 'https://docs.google.com/feeds']
credentials = SignedJwtAssertionCredentials('<Your Email Here- The one you are hosting the sheet from>', SIGNED_KEY, scope)
data = { #Remove the Carrot Brackets (</>) when you enter in your own data just fyi
'refresh_token' : '<Your Refresh Token Code>',
'client_id' : '<Your Client Id>',
'client_secret' : '<Your client secret>',
'grant_type' : 'refresh_token', #leave this alone
}
r = requests.post('https://accounts.google.com/o/oauth2/token', data = data)
credentials.access_token = ast.literal_eval(r.text)['access_token'] #leave this alone
gc = gspread.authorize(credentials)
return gc
gc = authenticate_google_docs()
sh = gc.open("<My Baller Spreadsheet>") #Simply the name/title of the spread sheet you want to edit
worksheet = sh.get_worksheet(0) # 0 is used by google to ref the first page of you sheet/doc. If you first page of your sheet/doc is a name us that or simply 2,3,4 ect. if they are simply numbered
worksheet.update_acell('A1', 'Look Ma, No Keys!') #update from comp straight to sheets

Categories