python saving unicode into file - python

i'm having some trouble figuring out how to save unicode into a file in python. I have the following code, and if i run it in a script test.py, it should create a new file called priceinfo.txt, and write what's in price_info to the file. But i do not see the file, can anyone enlighten me on what could be the problem?
Thanks a lot!
price_info = u'it costs \u20ac 5'
f = codecs.open('priceinfo.txt','wb','utf-8')
f.write(price_info)
f.close()

I can think of several reasons:
the file gets created, but in a different directory. Be certain what the working
directory of the script is.
you don't have permission to create the file, in the directory where you want to create it.
you have some error in your Python script, and it does not get executed at all.
To find out which one it is, run the script in a command window, and check for any error output that you get.

Assuming no error messages from the program (which would be the result of forgetting to import the codecs module), are you sure you're looking in the right place? That code writes priceinfo.txt in the current working directory (IOW are you sure that you're looking inside the working directory?)

Related

Please help me run a Python script from Excel 365 VBA on a Mac Mini running Big Sur

My first question on this subject was closed for not being specific enough so I'll try to tell you what I have tried so far that hasn't worked. I'm trying to move Excel 2010 workbooks to my new Mac mini Big Sur machine using Office 365. It is my first Mac so I am very new to the operating system and the differences from the Microsoft world. It is also the first time I'm using Office 365. I am hopeful you will be kind enough to help me. In my VBA macros I run Python scripts to scrape web pages for data. Usually I have the Python script create a .csv file which I then open in the VBA macro to read and populate the necessary cells in the workbook. This is the code I use in the PC version to call the Python script:
Kill strFileOfData
Set objWsh = VBA.CreateObject("WScript.shell")
strPython = """C:\Users\Phil\AppData\Local\Programs\Python\Python37-32\python.exe"""
strPyScript = """C:\Users\Phil\Documents\PyScripts\GetMarketsStks1-0.py"""
objWsh.Run strPython & strPyScript
Err = 0
Do Until Dir(StrFileOfData) <> 0
Application.Wait (Now() + TimeValue("0:00:01"))
Loop
It may not be the best but it works reliably on the PC. I delete the data file first, run the Python script, wait for the data file to be created, then continue.
I installed the latest version of Python on the Mac and rewrote the Python script to get more data and ran the Python script on Terminal to make sure it executed properly. It ran fine and created the .csv file correctly.
I then changed the code in the VBA macro to account for the different file structures. This is the new code:
Kill strFileOfData
Set objWsh = VBA.CreateObject("WScript.shell")
strPython = """/Library/Frameworks/Python.framework/Python"""
strPyScript = """/Users/minime/MyDocuments/Finance/GetHistory1-0.py"""
objWsh.Run strPython & strPyScript
Err = 0
Do Until Dir(StrFileOfData) <> 0
Application.Wait (Now() + TimeValue("0:00:01"))
Loop
When I run this on the Mac I get:
Run-Time error '429': ActiveX component can't create object
Suspecting this was a difference in the way shells are created and used I began researching how to call Python from Excel on the Mac. After considerable dead ends I found this thread from 4 years ago:
How can I launch an external python process from Excel 365 VBA on OSX?
I tried to simply plow ahead and follow the instructions. I learned a bit about AppleScript, added the folder: "~/Library/Application Scripts/com.microsoft.Excel/", created the AppleScript named PythonCommand.scpt and placed it in that folder. Since I couldn't find the path in the example I substituted what I thought to be the correct path, assuming it was due to the difference in MacOS from 4 years ago. My AppleScript looks like this:
on PythonCommand(pythonScript)
do shell script "/Library/Frameworks/Python.framework/Python" & pythonScript
end PythonCommand
I then added this code to the VBA macro:
strPyScript = """/Users/minime/MyDocuments/Finance/GetHistory1-0.py"""
Dim result As String
result = AppleScriptTask("PythonCommand.scpt", "PythonCommand", strPyScript)
When I ran the VBA macro. I got this message:
Run-time error '13': Type mismatch
I tried it again with single quotes instead of the triple quotes and got the same result.
I tried to work backward to make sure the pieces worked. I again ran the Python script from a Terminal window with no problem so the next step I tried was running the AppleScript from IDLE. I typed in this:
AppleScriptTask("PythonCommand.scpt", "PythonCommand","/Users/minime/MyDocuments/Finance/GetHistory1-0.py")
and got this result:
Traceback (most recent call last): File "<pyshell#0>", line 1, in
AppleScriptTask("PythonCommand.scpt", "PythonCommand","/Users/minime/My Documents/Finance/GetHistory1-0.py") NameError: name 'AppleScriptTask'
is not defined
After more research I tried this AppleScript in the editor:
do shell script "/Library/Frameworks/Python.framework/Versions/3.9/Python /Users/minime/MyDocuments/Finance/GetHistory1-0.py"
I got this result:
error "sh: /Library/Frameworks/Python.framework/Versions/3.9/Python:
cannot execute binary file" number 126
Next I tried this:
do shell script "Python /Users/minime/MyDocuments/Finance/GetHistory1-0.py"
and got this:
error "Traceback (most recent call last):
File \"/Users/philipackermann/MyDocuments/Finance/GetHistory1-0.py\", line 2, in <module>
from urllib.request import urlopen
ImportError: No module named request" number 1
This might actually be some progress! That import statement is the first line of code in my Python script but I have no clue why this got further than the last attempt and why this is running differently than the execution of the Python script in Terminal.
But I just noticed that in Terminal I enter Python3 so I tried this:
do shell script "Python3 /Users/minime/MyDocuments/Finance/GetHistory1-0.py"
and got a pop up with a script error:
and this:
After more reading about Terminal I realized there are hidden files on the Mac so I tried this AppleScript:
do shell script "/usr/local/bin/Python3 /Users/minime/MyDocuments/Finance/GetHistory1-0.py"
And it worked!! The .csv file is created successfully. So now I need to figure out how to call this from Excel. I found an article here:
https://stackoverflow.com/questions/38723420/how-to-simply-run-an-applescript-task-from-mac-excel-2016
That actually works. I converted the AppleScript into an app (just changed the extension from scpt to app) and moved it to the Applications folder, then put this code into the VBA macro:
ThisWorkbook.FollowHyperlink Address:="/Applications/RunGetHistory.app", NewWindow:=True
This worked! Of course it isn't passing any arguments or receiving any results. One issue though, like my previous PC version, the code doesn't wait for the app to finish so I need a way to check for it to be done and since I changed the Python Script to open the file in the beginning and write lines to it while scraping the web pages the file is created right away so this code which I was using in the PC version isn't sufficient:
Do Until Dir(strFileNmHistory) <> ""
Application.Wait (Now() + TimeValue("0:00:01"))
Loop
I suppose I could add a separate file written at the end of the Python script just to say it's done but that's a pretty lame hack. So technically I guess I could say I solved this and CAN run a Python script from Excel but I have to believe there is a better way and I'm sure this community has folks much smarter than me who can make this better. Has anyone been able to get the solution from 4 years ago to work? That might solve the problems of arguments, results, and waiting for the Python script to end. Any suggestions you can make would be most helpful. I have researched this issue extensively and some answers said that sandboxing is preventing Excel from running Python but if we can run an app that runs the Python script I guess that gets around it. If you can comment on the specific errors I encountered above I'll try different approaches and report back.
Please help.
Phil
SOLVED! ...and I learned a lot along the way! I'll try to lay out only the steps needed to make this work but I do tend to ramble, sorry. One issue that made this harder than it needed to be was a simple one: I was missing a space in the "do shell script" statement of the AppleScript. Here is the VBA code that works for me:
Result = AppleScriptTask("PythonCommand.scpt", "PythonCommandHandler", "/Users/minime/MyDocuments/Finance/PythonScripts/GetHistory1-0.py")
Here is the AppleScript code:
on PythonCommandHandler(pythonScript)
do shell script "/usr/local/bin/Python3 " & pythonScript
return "Handler succeeded! " & pythonScript
end PythonCommandHandler
Note the space after "Python3". Create the AppleScript in a convenient folder and copy it to
"/Users/minime/Library/Application Scripts/com.microsoft.Excel"
Trying to edit it in that folder is problematic, trust me. Move it there.
The Python script can be anywhere as long as you give the path in the AppleScriptTask command in the VBA code.
Be sure all references to .csv files point to an Excel sandbox folder. I used this one but I suspect others would work too:
"/Users/minime/Library/Containers/com.microsoft.Excel/Data/Documents"
See notes below if you can't find this folder. This worked on 7/1/2021! We'll see what happens when the new OS X comes out. The call to AppleScriptTask waits for the full execution of the Python script before continuing. I haven't figured out a good way to handle errors in the Python script yet.
Here are some notes on important things I learned along the way that might be helpful for first time Mac users like myself:
CHANGE YOUR VBA EDITOR FONT. Ok, not really necessary but the default font for the VBA editor on the Mac Excel 365 version I'm using was not a proportional font so things like the "as" part of the Dim statements wouldn't line up for me. Minor maybe but a big annoyance easily solved: In the editor, click the word "Excel" in the Menu Bar (the top row of words and icons.) Click "Preferences" and a window will pop up with the title "Options". Click the "Editor Format" tab and select "Courier New" from the "Font:" drop down. I changed the "Size:" to 16. Oh and by the way, "Command, shift, i" will step you through the VBA code like F8 does on the PC.
PUT SOME OF THE FILES IN THE SANDBOX. A word about the "sandbox" which I'm sure others could explain better than I. To improve security the sandbox concept is supposed to restrict the code from executing something outside it's expected area: e.g. you wouldn't want an error in your code (or malicious code) to change some system settings that had nothing to do with what you intended. I get that. Good concept. In ancient times (mainframes) we got a SOC 1 for that type of issue. The sandbox basically is a portion of the computer in which you are allowed to play. Don't try to go outside of it (there are exceptions I don't fully understand yet). On the Mac this means that if you even try to do anything with a .csv file in your VBA code that isn't in the sandbox you will get an alert saying you need to grant permission for that to happen. The Excel workbook with the VBA code doesn't need to be in the sandbox because what matters is that the Excel executable is in the sandbox (I assume) and is allowed to reach out to your workbook (an exception to the rule?) and do all the things you asked it to including run your VBA code, with limitations. The AppleScript also needs to be in the sandbox but the Python script does not (I don't know why). We are only interested here with the Excel sandbox, there are, apparently, different ones for different apps. Now a word about aliases. For simplicity consider your Excel sandbox to be here:
"/Users/philipackermann/Library/Containers/com.microsoft.Excel"
There is an alias located here:
"/Users/philipackermann/Library/Containers/com.microsoft.Excel/Data/Library/Application Scripts/com.microsoft.Excel"
Moving a file to one will, by magic, move the file to the other one as well. By the way, the first "com.microsoft.Excel" in that alias path will show up as "Microsoft Excel" in Finder if you are trying to look for it by walking the path from the beginning. Oh by the way, "Command, shift, ." will let you see the hidden folders and files in Finder. You'll need that to get started. If I understand this correctly, the folder icons in Finder with the little arrow in the lower left corner indicate that the folder is an alias (or has an alias pointing to it? I'm not sure). The folder I used for the .csv files is not an alias or doesn't have an alias) so I had to use the really long path. So the Excel workbook and the Python script don't need to be in the sandbox but the AppleScript and the .csv files do need to be there.
DON'T EDIT IN THE SANDBOX ALIAS FOLDER! Check out the link I mentioned in the comments above with VaughanR. He helped point the way for me to understand the alias issue better. Thank you VaughanR. Trying to edit in those folders was a madding exercise in futility. Save yourself the trauma and edit your AppleScript in a local folder and copy it to the sandbox folder. I did this by opening two Finder windows (one with the local folder and one with the sandbox folder) and holding down the Command and Option keys while dragging the AppleScript file from the local folder to the sandbox folder.
TEST THE APPLESCRIPT IN IN THE SCRIPT EDITOR. As I mentioned somewhere else, that pesky Error 5: can pop up for a number of reasons. In the script editor add this line above the PythonCommandHandler on statement:
"PythonCommandHandler("GetHistory1-0.py")"
and run it in the editor to be sure it is doing what you want it to do. That's how I found the problem with the missing space and tested the different paths to get it running.
MISC. EXCEL NOTES. If you are trying to bring Excel workbooks from a Windows environment to the Mac watch out for these issues I have run into so far: SORTS. I had hardcoded sorts in my VBA code that caused Excel to crash when I tried to run them on the Mac. I recorded a sort and that works fine in the code. There are NO USERFORMS on the Mac! I have not yet found an alternative to use.

Error! blahfile is not UTF-8 encoded. Saving disabled

So, I'm trying to write a gzip file, actually from the net, but to simplify I wrote some very basic test.
import gzip
LINES = [b'I am a test line' for _ in range(100_000)]
f = gzip.open('./test.text.gz', 'wb')
for line in LINES:
f.write(line)
f.close()
It runs great, and I can see in Jupyter that it has created the test.txt.gz file in the directory listing. So I click on it expecting a whole host of garbage characters indicative of a binary file, like you would see in Notepad.
However, instead I get this ...
Error! test.text.gz is not UTF-8 encoded.
Saving disabled.
See console for more details
Which makes me think, oh my god, coding error, something is wrong with my encoding, my saving, can I save bytes ? Am I using the correct routines ?? And then spend 5 hours trying all combinations of code and modules.
The very simple answer to this is none of the above. This is a very misleading error message, especially when the code you've written was designed to save a binary file with a weird extension.
What this actually means is ...
I HAVE NO IDEA HOW TO DISPLAY THIS DATA ! - Yours Jupyter
So, go to your File Explorer, Finder navigate to the just saved file and open it. Voila !!
Everything worked exactly as planned, there is no error.
Hope this saves other people many hours of debugging, and please Jupyter, change your error message.
It is also possible to select the file and, instead of double-clicking to open, go to 'view' as it interprets it correctly (or well, mostly, depending on special characters, mine is in Spanish and apparently it doesn't support accents).
This way we can avoid looking for the directory where we got the file and not getting out of jupyter :)

How to open a Unix Executable File using Python?

Sorry if this might be an easy question, but I'm trying to open a Unix Executable File using Python, but it doesn't have any file extensions attached to it. The file name looks something like 'filename_bib'. I typed this and it worked:
hdulist = open('filename_bib')
But next when I typed in hdulist.info() or hdulist.shape(), it doesn't give me anything, so I checked all its attributes and tried print(type()) and hdulist.attribute? for each attribute, but I didn't really understand any of the explanations, so I actually tried typing all of them to see what they would give me, but at some point it started giving me errors which said:
ValueError: I/O operation on closed file
so I think this may have happened when I tried using hdulist.close() or hdulist.closed(), but I don't know (1) if it was a mistake for me to try any of the attributes, (2) if it somehow changed anything from my original file, and (3) how to fix it.
I was told that this file contains bytes and that I should somehow be able to show a picture from it using Python, but this is my first time handling Unix Executable Files, and I have absolutely no idea how to start. I've handled fits and pl files before, but this is my first time trying to open something like this. I've tried looking up a bunch of things online already, but I can't find any instructions whatsoever. Please help me out if you know anything about this. I will be very grateful for any help that you could give me.
This is what it shows when I open it in Sublime:
enter image description here
As the default file access mode in python is "read only". Technically, since you have not mentioned any access mode in your command
hdulist = open('filename_bib')
file should only be for reading and nothing should have happend to the opened file.
Question:
Have you tried running it in UNIX by,
./filename_bib
What was the output?

How to run multiple files successively in a single process using python

I am working in Windows, and just learning to use python (python 2.7).
I have a bunch of script files ("file1.script", "file2.script", "file3.script"....) that are executed in TheProgram.exe. Python has already given me the ability to automatically create these script files, but now I want to successively run each of these script files, back-to-back, in TheProgram.exe.
So far I have figured out how to use the subprocess module in python to start "TheProgram.exe" in a new process (child process?) and load the first script file as follows:
my_process = subprocess.Popen(["Path to TheProgram.exe", "Path to File1.script"])
As seen, simply "opening" the script file in TheProgram.exe, or passing it as an argument in this case, will execute it. Once File1.script is done, TheProgram.exe generates an output file, and then just sits there. It does not terminate. This is I want, because now I would like to load File2.script in the same process without terminating (file2.script is dependent on file1.script completing successfully), then File3.script etc.
Is this possible? And if so how? I cannot seem to find any documentation or anyone else who has had this problem. If I can provide other information please let me know, I am also new to posting to these forums. Thanks so much for any assistance.

Back end process in windows

I need to run the python program in the backend. To the script I have given one input file and the code is processing that file and creating new output file. Now if I change the input file content I don't want to run the code again. It should run in the back end continously and generate the output file. Please if someone knows the answer for this let me know.
thank you
Basically, you have to set up a so-called FileWatcher, i.e. some mechanism which looks out for changes in a file.
There are several techniques for watching file/directory changes in python. Have a look at this question: Monitoring contents of files/directories?. Another link is here, this is about directory changes but file changes are handled in a similar way. You could also google for "watch file changes python" in order to get a lot of answers :)
Note: If you're programming in windows, you should probably implement your program as windows service, look here for how to do that.

Categories

Resources