DAO connection to Access .accdb database using Python - python

I’m having an issue with one of my Python apps that has been working fine with an older .mdb Access Databases. After converting to Access 2010 and the file being converted to the new .accdb format nothing seems to be working. I do have the 32 bit Access version loaded on a new 64 bit Win 7 OS. I believe my problem is with the first two lines of my code. I believe I need to update them to reference the "Microsoft Office 14.0 Access Database Engine Object" but I’m unclear how to do this. Can I get some help on this one? I have searched high and low for DAO info regarding this scenario but to avail.
import win32com.client
engine = win32com.client.Dispatch("DAO.DBEngine.36")
db=engine.OpenDatabase(r"c:\temp\Tracker.accdb")
table = db.OpenRecordset("select * from Event_Log")
print table.RecordCount

An answer probably too late for the OP, but in case anyone else stumbles in here looking for an answers in the area of DAO with Python:
The OP is correct that the immediate issue lies with the string used in the Dispatch method. Office 2010 (Office 14?) installs "DAO.DBEngine.120", which is I think the earliest version that works with .accdb files. In general, one can research this issue by using RegEdit to search the registry for the substring "DAO.DBEngine", and see what components have been registered that add a version number to that string.
It should also be noted that the 32/64 bitness of the version of python to be used needs to match the 32/64 bitness of the DAO version, which in turn matches the 32/64 bitness of Office that installed it.
A further note: If you are using an IDE and make use of autocomplete, it's useful to generate and import a module corresponding to the DAO API. This can be done by running the MakePy utility (in the PythonWin program) on the Library in question, here "Microsoft Office 14.0 Access Database Engine Object Library". This produces a module file in site-packages\win32com\gen_py\, with a long GUID name... you can rename it to "DAO_120-64.py" or somesuch. Then add the gen_py directory to the Python path (or add a .pth file in sitepackages), so that import can find the new module.
Once imported, you can do whatever your IDE recognizes to associate a type with variables for DAO.Database, DAO.Recordset, and so on.
Additionally, the generated DAO module is a useful reference for what objects, methods, properties and constants are available. Possibly a more helpful reference is to simply open an Excel/Word/Access VBA project, Reference (import) this same library, and use the VBA Object browser on it.
In general, any tutorials or articles about using DAO in Access (in VBA or VB) will describe the objects, methods and properties involved in common operations, which can be transcribed almost verbatim into python. The main difference is that in the python version, some of the COM "default method" mechanisms don't work. So, for example, the VBA
MyRecordset("SomeColumn") = "NewValue"
... corresponds in python to:
MyRecordset.Fields("SomeColumn").Value = "NewValue"
Hope that helps.

Related

pythoncom.CoCreateInstance can't create IZoneIdentifier; the interface is missing from registry too despite being documented in MSDN

I'm trying to implement Manipulating the zone identifier to specify where a file was download from – The Old New Thing - MSDN blogs in Python.
At CoCreateInstance:
pythoncom.CoCreateInstance(
pywintypes.IID('{0968e258-16c7-4dba-aa86-462dd61e31a3}'), #CLSID_PersistentZoneIdentifier
None,pythoncom.CLSCTX_ALL,
pywintypes.IID('{cd45f185-1b21-48e2-967b-ead743a8914e}')) #IID_IZoneIdentifier
I get an error:
TypeError: There is no interface object registered that supports this IID
(No stacktrace as this is an extension function)
If I replace the IZoneIdentifier IID with pythoncom.IID_IUnknown or pythoncom.IID_IPersistFile, it works, but a QueryInterface with the right IID fails with the same error.
Indeed, in HKCR\Interface, I see nothing like IZoneIdentifier but do see an IPersistFile.
Having disassembled urlmon.dll, I see that it indeed implements the interface, but doesn't register it in its DllRegisterServer. Searching further, I see that IPersistFile is being registered by ole32.dll - but not IZoneIdentifier.
MSDN documents this interface to be available since IE6. But it's not there in either IE7 or IE8. Since this is XP (and with all the updates allegedly), I've nothing else to try.
Likewise, the interface is present in Windows SDK 7.0 in the urlmon.h file mentioned in the MSDN article.
The questions are:
Was this interface silently dropped in favour of something else without MSDN reflecting that or something? Alternatively, is this a known issue? Is it available in later versions of IE?
What components do ole32.dll and urlmon.dll pertain to (so I can try (un)installing updates for them)?
There's nothing wrong with IZoneIdentifier. The original C++ program runs just fine. As #IgorTandetnik pointed out, not every interface an object implements is going to be registered in the registry, only those that support marshalling.
The error comes from pythoncom itself (a hint is that it's a TypeError, not pythoncom.com_error, and the error message is always in English rather than the system's UI language).
The cause is that pythoncom indeed requires IDispatch support by the interface - or it wouldn't be able to deduce how to work with the interface's functions and values they accept/return.
The only exception is a number of IUnknown-based interfaces support for which is compiled in (IPersistFile is one of them; the full list is in pythoncom.InterfaceNames apparently).
Support for other IUnknown-based interfaces can be added with a "pythoncom extension" module. Some (very scarce) documentation on them can be found in pywin32 docs in the Python and COM - Implementation Details article.

Create playlist in iTunes with Python and Scripting Bridge

How do you create a playlist using Python and Scripting Bridge?
So far I have :
from Foundation import *
from ScriptingBridge import *
iTunes = SBApplication.applicationWithBundleIdentifier_("com.apple.iTunes")
newPlaylist = iTunes.iTunesPlaylist()
This obviously doesn't work.
I've seen things for Ruby and Objective C, but I don't really understand the language.
This is actually an example in the Scripting Bridge documentation. See Listing 2, "Adding an object to a scriptable application in PyObjC code":
from Foundation import *
from ScriptingBridge import *
iTunes = SBApplication.applicationWithBundleIdentifier_("com.apple.iTunes")
p = {'name':'Testing'}
playlist = iTunes.classForScriptingClass_("playlist").alloc().initWithProperties_(p)
iTunes.sources()[0].playlists().insertObject_atIndex_(playlist, 0)
If this doesn't make sense to you, there are a few different ugly things to explain…
First, SBApplication doesn't have any member iTunesPlaylist that's a nice subclass of SBObject. If you've generated static glue, ITApplication might have such a thing… but you don't want to use static glue. So, you have to dynamically create the class object iTunesPlaylist. There are a few different ways to do that, but the easy way (assuming you know it's called playlist in Applescript) is with classForScriptingClass_.
Next, ScriptingBridge isn't really a native Python bridge to AE; it's a Python bridge to the ObjC bridge to AE. So that iTunesPlaylist is actually a wrapped-up ObjC class, not Python class. That means you can't just instantiate it as iTunesPlaylist(), you have to say iTunesPlaylist.alloc().init().
Calling initWithProperties_(p) is a nice shortcut to initializing and setting properties in separate steps.
Finally, the way the AE object model works, you can't just "create an object", you have create an object at some location. ScriptingBridge tries to hide this from you, but it doesn't do a very good job. The playlist object you create doesn't actually represent anything in iTunes yet—in fact, if you look at its type or repr, you'll see that it's a "future iTunesPlaylist". You need to find an appropriate SBElementArray to insert it into, and then it will become a real playlist.
Not everything in ScriptingBridge is this horrible. But some of it is even worse. Just wait until you run into one of the areas where iTunes' scripting dictionary is wrong…
The iTunes AE interface itself is very nice, if you can avoid using ScriptingBridge. There are three ways around that, although they may not help you.
First, there's appscript (docs here). This is a different Python->AE bridge which is much better than SB. Here's what the same thing looks like (relying on the default that iTunes has a default location for playlists—at the end of the list of playlists in the first library source):
from appscript import *
iTunes = app('iTunes')
p = {'name':'Testing'}
playlist = iTunes.make(new=k.playlist, with_properties=p)
And if you can't figure out how to do what you want, but can find AppleScript sample code (e.g., at dougscripts), you can use the ASTranslate tool to write the equivalent appscript.
Unfortunately, the author of appscript has canceled the project. And with good reason—it relies on legacy APIs that Apple could remove in 10.9 (or cite to reject you from the App Store). At present, it still works fine, and a few people are keeping it alive at the github repo above, but one day, it will have to die for real. So, it may not be a good solution unless this is a personal, short-term, or learning project. (Also, specific to iTunes: 10.6.3 has a bug that affects appscript, but doesn't affect other bridges unless you're using them remotely. If you need to work with that version, see itunesterms for one solution.)
Of course there's always the obvious option: do it in AppleScript:
tell application "iTunes"
make new playlist with properties {name:"Testing4"}
end tell
The problem with AppleScript is that it's a horrible language for everything except talking AEOM, and its equivalent of Python's standard library is about 5% as deep and wide. But you can always use a two-language solution, in two ways. You can connect from AppleScript to other Cocoa code (e.g., Python with PyObjC) via ASOC. Or, alternatively, you can use NSAppleScript and friends to run scripts from PyObjC/etc.
The latter may be the most painful answer, but it has one huge advantage: If you use the new APIs in Mountain Lion, and your use cases fall within a certain narrow band, you can write a sandboxed app that scripts iTunes without needing a temporary exception entitlement, meaning you can sell it in the App Store.

Excel RTD server in Python not updating data

I've got the excelRTDserver.py up and running in Excel 2010 (32bit) by changing the EXCEL_TLB_MINOR value to 7. I can see the server in the add-ins list and if I enter =RTD("Python.RTD.TimeServer","","seconds","5") into a cell, I get the current time. But it never updates. If I change the "5" to another number, I get an update but after the initial change it never changes again.
How do I get it to update? I found someone else with a similar problem here, but no solution.
UPDATE: I've got a little further - there is an exception raised within ServerStart when casting the PyIDispatch callback object into a IRTDUpdateEvent callback object. Using this method to capture the error message, I get "Cannot create a file when that file already exists.". If I follow the suggestion here and use win32com.client.CastTo(CallbackObject,'IRTDUpdateEvent') I get "This COM object can not automate the makepy process - please run makepy manually for this object", but I have already run makepy for Microsoft Excel 12.0 Object Library (1.6).
Any help would be greatly appreciated.
To work around this problem I've created a new project on github for pythoncom excel types:
https://github.com/pyxll/exceltypes
This includes a slightly modified version of excelRTDServer.py that uses the new type PyIRTDUpdateEvent instead of the win32com makepy wrapper, and so it now works in Excel 2010 (look for the comments 'EXCELTYPES_MODIFICATION' in exceltypes/demos/excelRTDServer.py).
To build the project you will need visual studio installed (it won't build with gcc) and you can build it using the setup.py included in the project as follows:
python setup.py install
If you need to force it to use visual studio instead of gcc use the "--compiler=msvc" option, if you're using anaconda for example.
If you want to use Visual Studio 2012 instead of the default 2010 add the following lines to setup.py:
from distutils import msvc9compiler
msvc9compiler.VERSION = 11
I think you may be out of luck.
According to the author of excelRTDServer.py in a recent python-win32 thread:
The message that this is in response to describes your exact problem, and it's recent, so maybe you already got this info directly, but in case you didn't...
I fear that things with IRTDUpdateEvent have changed with recent versions
of excel (since Excel 2007? I guess that's not so 'recent' anymore...).
While hunting around for news of interface changes, I came across this
thread in a java forum:
http://www.nevaobject.com/phpbb3/viewtopic.php?t=516
The part that worries me is this comment:
"Apparently in Excel 12 (Excel 2007) the RTD callback object that
implements dual IRTDUpdateEvent interface throws exception (generic COM
exception 0x80020009) when is called via IDispatch. If you use v-table
binding the call to UpdateNotify succeeds. I don't really know whether it
is a bug in Excel 12 or a feature."
So far I haven't been able to confirm this against the MSDN information...
But if this is true, it does explain the problem being seen. Many older
examples on the web, and pywin32+makepy treat this interface as IDispatch,
and wrap it accordingly.
I don't think we can fix this with pywin32 as it is right now. My
understanding is that it relies on IDispatch support. May need to look at
comtypes (http://starship.python.net/crew/theller/comtypes/) to wrap the
(new?) IRTDUpdateEvent objects, or maybe a C extension. :(
Python:
I get "This COM object can not automate the makepy process - please run makepy manually for this object", but I have already run makepy for Microsoft Excel 12.0 Object Library (1.6).
Yesterday at work after a while reading your question, I forgot that is python and not java :)).. Well, the only thing I think now is that seems you need to run the PIA for office 2010.
Edit later: if you steel have problems after what i told you., please comment and not downvote, because this issue is uncommon.
JAVA:
This happen because is missing the option to generate v-tables.
You need to modify ServerStart method and also IRTDServer interface and IRTDServer_Impl class., so CallbackObject is COMIUnknown. Then you need to generate IRTDServer_Skel class by runing the IBuilder.
Now you can generate a new java wrapper for IRTDUpdateEvent to request v-table:
That error message sometimes is raised when u put it in something like 'for'-loop,here is a hackly solution 4u:import time,and use 'sleep()' in your loop
The IRTDUpdateEvent problem (throwing exception) as described in here should be fixed in the latest Office 365 version.
"Apparently in Excel 12 (Excel 2007) the RTD callback object that implements dual IRTDUpdateEvent interface throws exception (generic COM exception 0x80020009) when is called via IDispatch. If you use v-table binding the call to UpdateNotify succeeds. I don't really know whether it is a bug in Excel 12 or a feature."
Therefore excelRTDserver.py should work fine with the latest version of Office. In other words, =RTD("Python.RTD.TimeServer","","seconds","5") should continuously get updated as expected.

Writing/Reading arrays of Data in Open Office using Python. Anyone have any example code?

So I have written a class that makes it extremely easy to interface with either Excel or Gnumeric using Python, and would like to extend the class to include Open Office as well. I could do this in 30 minutes if I just had the ability to do the following:
Set a single value on an arbitrary
sheet and workbook
Get a single value
on an arbitrary sheet and workbook
If these are slow/there is a way to do the following, I also need to be able to:
set/get an array '''
set/get a matrix '''
ALSO, the ability to create and rename sheets would be great.
This is a shoutout if anyone has worked on this before. If they give me the information, I will reference them at the top of the file
My project can be found here: https://sourceforge.net/projects/pyworkbooks/ and I encourage you to check it out.
As a matter of fact, to acess OpenOffice or LibreOffice via Python one has to go through an absolutely opaque amount of boiler plate inherited from the StarOffice times - never properly documented (one feels) or simplified since then.
I had once lectured on this subject, and I took almot 40 minutes, just to retrieve the parts of my lecture to set up the example bellow.
On the other hand it just worked with the latest LibreOffice version - 3.3 - I am confident it works for OpenOffice as well (but I would not advice anyone to stick to OpenOffice, it is an Oracle dead end at this point)
The example bellow use the slow method of connecting to a running LibreOffice instance from the "outside". This is extremely slow - you will have to refer to the documentation on how to make it work as a macro from "within" the program, for better performance. (it is really slow in this way).
However, this method allows you to explore the methods available to developers using a Python terminal and introspection.
The first poorly documented part is that you have to start Open/LibreOffice with:
soffice "-accept=socket,host=0,port=2002;urp;"
For connections to be accepted. Then, create a new spreadsheet through its interface
and with the python interpreter that comes with the Office Suite run the following code
(either interactively or as a script):
import uno
import socket # only needed on win32-OOo3.0.0
# get the uno component context from the PyUNO runtime
localContext = uno.getComponentContext()
# create the UnoUrlResolver
resolver = localContext.ServiceManager.createInstanceWithContext(
"com.sun.star.bridge.UnoUrlResolver", localContext )
# connect to the running office
ctx = resolver.resolve( "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext" )
smgr = ctx.ServiceManager
# get the central desktop object
desktop = smgr.createInstanceWithContext( "com.sun.star.frame.Desktop",ctx)
# access the current writer document
model = desktop.getCurrentComponent()
try:
sheets = model.getSheets()
except Exception:
raise TypeError("Model retrived was not a spreadsheet")
sheet1 = getattr(sheets, sheets.ElementNames[0])
# At this point, you can use "dir" to check the methods and
# attributes available for the sheet
# the methots "getCellByPosition, to retrieve a cell object,
# which has "getFormula" and "setFormula"
# methods.
for i in xrange(10):
for j in xrange(10):
cell = sheet1.getCellByPosition(i, j)
cell.setFormula(str(i * j))
c1 = sheet1.getCellByPosition(1,1)
As you can see, the connecting part of this is boilerplate I got somewhere else years ago, and I doubt any living person could find any rationale in such stuff.
Once you get down to the "sheets" object, though, the attributes and methods on the object start to make sense.
There is a complete developer manual online, that even could allow one to understand the connection part:
http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/OpenOffice.org_Developers_Guide
The inter-process API for connecting to LibreOffice (and also OpenOffice and StarOffice) is called UNO. It is documented at the LibreOffice API documentation site.
As jsbueno says, it expects that a daemon is running to communicate with. The command-line arguments to the ‘soffice’ command starting the daemon determine what host and port values you need to supply in your UNO calls.
You could also try ezodf This was the best python odf library I found
You can use pyoo. Here is my answer to similar question https://stackoverflow.com/a/27082610/886607

How to dynamically interpose C functions from Python on Linux (without LD_PRELOAD)?

How do I, at run-time (no LD_PRELOAD), intercept/hook a C function like fopen() on Linux, a la Detours for Windows? I'd like to do this from Python (hence, I'm assuming that the program is already running a CPython VM) and also reroute to Python code. I'm fine with just hooking shared library functions. I'd also like to do this without having to change the way the program is run.
One idea is to roll my own tool based on ptrace(), or on rewriting code found with dlsym() or in the PLT, and targeting ctypes-generated C-callable functions, but I thought I'd ask here first. Thanks.
You'll find from one of ltrace developer a way to do this. See this post, which includes a full patch in order to catch dynamically loaded library. In order to call it from python, you'll probably need to make a C module.
google-perftools has their own implementation of Detour under src/windows/preamble_patcher* . This is windows-only at the moment, but I don't see any reason it wouldn't work on any x86 machine except for the fact that it uses win32 functions to look up symbol addresses.
A quick scan of the code and I see these win32 functions used, all of which have linux versions:
GetModuleHandle/GetProcAddress : get the function address. dlsym can do this.
VirtualProtect : to allow modification of the assembly. mprotect.
GetCurrentProcess: getpid
FlushInstructionCache (apparently a nop according to the comments)
It doesn't seem too hard to get this compiled and linked into python, but I'd send a message to the perftools devs and see what they think.

Categories