error xlPrimary not defined in Python win32com - python

I keep getting errors where xlCategory, xlValue and xlPrimary are not recognised in my python script.
I am trying to label the axes of my graph and was successfully doing so yesterday with this code:
chart = excel.Charts.Add()
chart.Name = "Chart Title"
chart.ChartType = -4169 #xlXYScatter
chart.SetSourceData(firstSheet.Range("$A:$B"))
series = chart.SeriesCollection(1)
series.Name = "Series Name"
chart.Axes(win32com.client.constants.xlCategory).HasTitle = True
chart.Axes(win32com.client.constants.xlCategory).AxisTitle.Caption = "x Axis"
chart.Axes(win32com.client.constants.xlValue).HasTitle = True
chart.Axes(win32com.client.constants.xlValue).AxisTitle.Caption = "y Axis"
This produced the following error:
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
startGraphBuild()
File "C:\Python33\InCAS_Study_Analysis\VMDvsMODVMDG.py", line 33, in startGraphBuild
chart.Axes(win32com.client.constants.xlCategory).HasTitle = True
File "C:\Python33\lib\site-packages\win32com\client\__init__.py", line 170, in
__getattr__
raise AttributeError(a)
AttributeError: xlCategory
So I tried this from this stackoverflow question changing axis labels in excel 2007 charts using python win32com:
pAxis = chart.Axes(AxisGroup = xlPrimary)
xAxis = pAxis(1)
yAxis = pAxis(2)
xAxis.HasTitle = True
yAxis.HasTitle = True
xAxis.AxisTitle.Caption = "VMD"
yAxis.AxisTitle.Caption = "MOD VMD"
But this produced the following error:
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
startGraphBuild()
File "C:\Python33\InCAS_Study_Analysis\VMDvsMODVMDG.py", line 37, in startGraphBuild
pAxis = chart.Axes(AxisGroup = xlPrimary)
NameError: global name 'xlPrimary' is not defined
Has anyone else experienced this? Since it was working yesterday I have tried restarting everything, uninstalling and reinstalling pyWin but these haven't worked.
I am using Python 3.3 and Excel 2010.

The constants are defined. However, they will only be loaded if you have created the COM Type Library for the COM objects of interest. There are several ways to do that (my self-answer to Accessing enumaration constants in Excel COM using Python and win32com has some links you'll find useful). But basically try this:
Python 2.7.5 (default, May 15 2013, 22:43:36) [MSC v.1500 32 bit (Intel)] on win
Type "help", "copyright", "credits" or "license" for more information.
Portable Python >>> import win32com
Portable Python >>> win32com.__gen_path__ # path to COM typelib generated by win32com
'C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\gen_py\\2.7'
Now try with Dispatch:
Portable Python >>> from win32com import client
Portable Python >>> xl=client.Dispatch('Excel.Application')
Portable Python >>> client.constants.xlPrimary
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "G:\Portable Python 2.7.5.1\App\lib\site-packages\win32com\client\__init_
__getattr__
raise AttributeError(a)
AttributeError: xlPrimary
Now use EnsureDispatch from gencache:
Portable Python >>> xl=client.gencache.EnsureDispatch('Excel.Application')
Portable Python >>> client.constants.xlPrimary
1
Portable Python >>>
You only need to use EnsureDispatch once, since once the Type library has been created, even Dispatch will load the constants.
If you need to clear the cache for whatever reason, wasn't easy to find, but you can remove the gen_py folder, its path can be found from win32com.__gen_path__.

The main reason for this attribute error is because your COM-server has shifted from late-binding (dynamic) to early binding (static).
In Late Binding, whenever a method is called, the object is queried for the method and if it succeeds, then the call can be made.
In Early Binding, the information of the object model is determined in advance from type information supplied by the object call. Early binding makes use of MakePy. Also, early binding is case sensitive.
There are two ways to fix this issue:
Use the dynamic module to force your code to work in a late-bound oriented way. Example use:
"win32com.client.dynamic.Dispatch()" instead of "win32com.client.Dispatch()"
Use camelcase sensitive keywords for the early bound oriented way. Example use:
"excel.Visible()" instead of "excel.VISIBLE()" or "excel.visible()"
If you want to use variables without case sensitive issues, you should delete the gen_py folder and use win32com.client.Dispatch()

Related

python win32com Attribute Error in constants

I tried to program with the win32com Python library to handle PowerPoint files. However when I pass constants to the function in the following way,
new_pre.ExportAsFixedFormat(options.output,
win32com.client.constants.ppFixedFormatTypePDF,
win32com.client.constants.ppFixedFormatIntentPrint,
win32com.client.constants.msoFalse,
win32com.client.constants.ppPrintHandoutHorizontalFirst,
win32com.client.constants.ppPrintOutputSixSlideHandouts,
win32com.client.constants.msoFalse,
win32com.client.constants.ppPrintAll,
False,
False,
False,
False,
PrintRange=None
)
it raises an AttributeError:
Traceback (most recent call last):
File "D:/SharedDocuments/DokyPpf/main.py", line 40, in <module>
win32com.client.constants.msoFalse,
File "C:\Users\xxx\AppData\Local\Programs\Python\Python36\lib\site-packages\win32com\client\__init__.py", line 178, in __getattr__
raise AttributeError(a)
AttributeError: msoFalse
Note that there is a similar question and the solution there is to use
EnsureDispatch("PowerPoint.Application")
instead of
Dispatch("")
But, I already used EnsureDispatch("PowerPoint.Application") and it's still not working...
Here is the link to the API reference of the corresponding VBA.
When you are running EnsureDispatch, win32com will automatically generate Python code corresponding to the type library of interest.
Depending a bit on your environment, the Python modules will be located somewhere around C:\Users\username\AppData\Local\Temp\gen_py\3.6, with the modules being grouped by the CLSID of the type library you have generated code for.
For PowerPoint 2016, you would find a folder named 91493440-5A91-11CF-8700-00AA0060263B whose __init__.py contains all the generated constants, including e.g. ppFixedFormatTypePDF.
Now, notably, the MsoTriState enum containing msoFalse is not part of the PowerPoint type library, which is why you are seeing your AttributeErrors.
From a quick look at the documentation, we find that the enum is part of the core Office libraries, contained in mso.dll. Depending once again on your setup, which version of Office you're using, and which architecture it targets, you should be able to dig up its ID by searching HKEY_CLASSES_ROOT in your registry editor:
Here, we note that the type library has a CLSID of {2DF8D04C-5BFA-101B-BDE5-00AA0044DE52} and that the version number is 2.8. Knowing this, perhaps the easiest way to generate the code for the library, and thus the missing constant, is through win32com.client.gencache.EnsureModule('{2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}', 0, 2, 8):
In [16]: win32com.client.constants.msoFalse
AttributeError: msoFalse
In [17]: win32com.client.gencache.EnsureModule('{2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}', 0, 2, 8)
Out[17]: <module 'win32com.gen_py.2DF8D04C-5BFA-101B-BDE5-00AA0044DE52x0x2x8' from 'C:\\Users\\username\\AppData\\Local\
\Temp\\gen_py\\3.6\\2DF8D04C-5BFA-101B-BDE5-00AA0044DE52x0x2x8.py'>
In [18]: win32com.client.constants.msoFalse
Out[18]: 0
Now, knowing that msoFalse translates to a 0, you could, of course, also just skip the entire process and replace all occurrences of the constant with a 0.
__import__('win32com.gen_py', globals(), locals(), ['2DF8D04C-5BFA-101B-BDE5-00AA0044DE52x0x2x8'], 0)
this file will not be automatically loaded.

'RiakBucket' object has no attribute 'new_binary'

As I'm trying to store a PNG image file into my riakBucket. As per https://riak-python-client.readthedocs.io/en/1.5-stable/tutorial.html documentation described here actually using riakBucketObject.new_binary().
But when I'm trying to do this over my system, this error is pop-up:
My python script is :
>>> import riak
>>> myClient = riak.RiakClient(pb_port=8087, protocol='pbc')
>>> photo_bucket = myClient.bucket('photo-bucket')
>>> file_data = open('/home/kamli/Pictures/Store3.png','rb').read()
>>> key = photo_bucket.new_binary('myphoto', data=file_data, content_type='image/png')
But error is :
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'RiakBucket' object has no attribute 'new_binary'
System Configuration:
Python version - 2.7.6
Riak Version - 2.2.0
Riak 2.2 has changed since 1.5 and the current method to get a new RiakObject from a bucket is simply using RiakBucket.new() or RiakBucket.new_from_file(). The documentation can be found on their readthedocs website. Look for the version switcher near the bottom to look at documentation for each major release.
In addition to what Aaron3468 said, I would like to mention that the Riak Python Client's version does not match Riak's version. The client is versioned according to semver and the latest release is available here.
Please use the latest documentation.

Proper use of ctypes to call _Py_Mangle?

While sitting on a mushroom and contemplating the intricacies of inscribing a function to implement Python's name mangling algorithm, a stupendously better idea came into my noggin. Why not use the recipe already crafted into the language to accomplish such a goal? So I pulled ctypes out of my satchel to help with the endeavor and executed ctypes.pythonapi._Py_Mangle('Demo', '__test'). Lo and behold, an error appeared out of thin air saying OSError: exception: access violation reading 0x00000A65646F00A8 and did not bother to explain the conundrum any more than that.
The full interaction with the interpreter is as follows:
Python 3.4.2 (v3.4.2:ab2c023a9432, Oct 6 2014, 22:16:31) [MSC v.1600 64 bit (AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> import ctypes
>>> ctypes.pythonapi._Py_Mangle('Demo', '__test')
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
ctypes.pythonapi._Py_Mangle('Demo', '__test')
OSError: exception: access violation reading 0x00000A65646F00A8
Does anyone know what needs to be changed in order to call the mangling function successfully?
Thanks to comments by eryksun, the answer to the problem is rather simple:
>>> from ctypes import pythonapi, py_object
>>> py_mangle = pythonapi._Py_Mangle
>>> py_mangle.argtypes = py_object, py_object
>>> py_mangle.restype = py_object
>>> py_mangle('Demo', '__test')
'_Demo__test'

TypeError with PAMIE

I am getting a TypeError with a very simple script on PAMIE, and I'm not sure what I can do. I had found an answer suggesting that the library, pywin32 might not have set a self argument for this particular method (getElementsByTagName) but I don't know for sure, as I don't know where to find the definition of it.
from PAM30 import PAMIE
ie = PAMIE()
ie.navigate('google.com')
ie.getButtons()
ie.quit()
print 'done'
The error is:
Traceback (most recent call last):
File "c:\pamie1.py", line 1, in <module>
from PAM30 import PAMIE
File "C:\Python27\Lib\site-packages\PAM30.py", line 678, in getButtons
return self.getElementsList("input", filter)
File "C:\Python27\Lib\site-packages\PAM30.py", line 939, in getElementsList
elements = self._ie.Document.getElementsByTagName(tag)
TypeError: getElementsByTagName() takes exactly 1 argument (2 given)
Here's the offending line in PAM30
elements = self._ie.Document.getElementsByTagName(tag)
where _ie_ is
self._ie = win32com.client.dynamic.Dispatch('InternetExplorer.Application')
I'm using Windows 7x64 with Python2.7 32bit
sourceforge bug link
"Workaround" seems to be enable Compatibility View (Tools > Compatibility
View settings > Display all websites in Compatibility View).
it is a bug of IE.
Work around - Change in PAMIE30
elements = self._ie.Document.getElementsByTagName(tag)
to
elements = self._ie.Document.body.all.tags(tag)
This will work without the need to use Compatibility View!
Modify this line:
elements = self._ie.Document.getElementsByTagName(tag)
to
elements = self._ie.Document.Body.getElementsByTagName(tag)

How to recover a broken python "cPickle" dump?

I am using rss2email for converting a number of RSS feeds into mail for easier consumption. That is, I was using it because it broke in a horrible way today: On every run, it only gives me this backtrace:
Traceback (most recent call last):
File "/usr/share/rss2email/rss2email.py", line 740, in <module>
elif action == "list": list()
File "/usr/share/rss2email/rss2email.py", line 681, in list
feeds, feedfileObject = load(lock=0)
File "/usr/share/rss2email/rss2email.py", line 422, in load
feeds = pickle.load(feedfileObject)
TypeError: ("'str' object is not callable", 'sxOYAAuyzSx0WqN3BVPjE+6pgPU', ((2009, 3, 19, 1, 19, 31, 3, 78, 0), {}))
The only helpful fact that I have been able to construct from this backtrace is that the file ~/.rss2email/feeds.dat in which rss2email keeps all its configuration and runtime state is somehow broken. Apparently, rss2email reads its state and dumps it back using cPickle on every run.
I have even found the line containing that 'sxOYAAuyzSx0WqN3BVPjE+6pgPU'string mentioned above in the giant (>12MB) feeds.dat file. To my untrained eye, the dump does not appear to be truncated or otherwise damaged.
What approaches could I try in order to reconstruct the file?
The Python version is 2.5.4 on a Debian/unstable system.
EDIT
Peter Gibson and J.F. Sebastian have suggested directly loading from the
pickle file and I had tried that before. Apparently, a Feed class
that is defined in rss2email.py is needed, so here's my script:
#!/usr/bin/python
import sys
# import pickle
import cPickle as pickle
sys.path.insert(0,"/usr/share/rss2email")
from rss2email import Feed
feedfile = open("feeds.dat", 'rb')
feeds = pickle.load(feedfile)
The "plain" pickle variant produces the following traceback:
Traceback (most recent call last):
File "./r2e-rescue.py", line 8, in <module>
feeds = pickle.load(feedfile)
File "/usr/lib/python2.5/pickle.py", line 1370, in load
return Unpickler(file).load()
File "/usr/lib/python2.5/pickle.py", line 858, in load
dispatch[key](self)
File "/usr/lib/python2.5/pickle.py", line 1133, in load_reduce
value = func(*args)
TypeError: 'str' object is not callable
The cPickle variant produces essentially the same thing as calling
r2e itself:
Traceback (most recent call last):
File "./r2e-rescue.py", line 10, in <module>
feeds = pickle.load(feedfile)
TypeError: ("'str' object is not callable", 'sxOYAAuyzSx0WqN3BVPjE+6pgPU', ((2009, 3, 19, 1, 19, 31, 3, 78, 0), {}))
EDIT 2
Following J.F. Sebastian's suggestion around putting "printf
debugging" into Feed.__setstate__ into my test script, these are the
last few lines before Python bails out.
u'http:/com/news.ars/post/20080924-everyone-declares-victory-in-smutfree-wireless-broadband-test.html': u'http:/com/news.ars/post/20080924-everyone-declares-victory-in-smutfree-wireless-broadband-test.html'},
'to': None,
'url': 'http://arstechnica.com/'}
Traceback (most recent call last):
File "./r2e-rescue.py", line 23, in ?
feeds = pickle.load(feedfile)
TypeError: ("'str' object is not callable", 'sxOYAAuyzSx0WqN3BVPjE+6pgPU', ((2009, 3, 19, 1, 19, 31, 3, 78, 0), {}))
The same thing happens on a Debian/etch box using python 2.4.4-2.
How I solved my problem
A Perl port of pickle.py
Following J.F. Sebastian's comment about how simple the pickle
format is, I went out to port parts of pickle.py to Perl. A couple
of quick regular expressions would have been a faster way to access my
data, but I felt that the hack value and an opportunity to learn more
about Python would be be worth it. Plus, I still feel much more
comfortable using (and debugging code in) Perl than Python.
Most of the porting effort (simple types, tuples, lists, dictionaries)
went very straightforward. Perl's and Python's different notions of
classes and objects has been the only issue so far where a bit more
than simple translation of idioms was needed. The result is a module
called Pickle::Parse which after a bit of polishing will be
published on CPAN.
A module called Python::Serialise::Pickle existed on CPAN, but I
found its parsing capabilities lacking: It spews debugging output all
over the place and doesn't seem to support classes/objects.
Parsing, transforming data, detecting actual errors in the stream
Based upon Pickle::Parse, I tried to parse the feeds.dat file.
After a few iteration of fixing trivial bugs in my parsing code, I got
an error message that was strikingly similar to pickle.py's original
object not callable error message:
Can't use string ("sxOYAAuyzSx0WqN3BVPjE+6pgPU") as a subroutine
ref while "strict refs" in use at lib/Pickle/Parse.pm line 489,
<STDIN> line 187102.
Ha! Now we're at a point where it's quite likely that the actual data
stream is broken. Plus, we get an idea where it is broken.
It turned out that the first line of the following sequence was wrong:
g7724
((I2009
I3
I19
I1
I19
I31
I3
I78
I0
t(dtRp62457
Position 7724 in the "memo" pointed to that string
"sxOYAAuyzSx0WqN3BVPjE+6pgPU". From similar records earlier in the
stream, it was clear that a time.struct_time object was needed
instead. All later records shared this wrong pointer. With a simple
search/replace operation, it was trivial to fix this.
I find it ironic that I found the source of the error by accident
through Perl's feature that tells the user its position in the input
data stream when it dies.
Conclusion
I will move away from rss2email as soon as I find time to
automatically transform its pickled configuration/state mess to
another tool's format.
pickle.py needs more meaningful error messages that tell the user
about the position of the data stream (not the poision in its own
code) where things go wrong.
Porting parts pickle.py to Perl was fun and, in the end, rewarding.
Have you tried manually loading the feeds.dat file using both cPickle and pickle? If the output differs it might hint at the error.
Something like (from your home directory):
import cPickle, pickle
f = open('.rss2email/feeds.dat', 'r')
obj1 = cPickle.load(f)
obj2 = pickle.load(f)
(you might need to open in binary mode 'rb' if rss2email doesn't pickle in ascii).
Pete
Edit: The fact that cPickle and pickle give the same error suggests that the feeds.dat file is the problem. Probably a change in the Feed class between versions of rss2email as suggested in the Ubuntu bug J.F. Sebastian links to.
Sounds like the internals of cPickle are getting tangled up. This thread (http://bytes.com/groups/python/565085-cpickle-problems) looks like it might have a clue..
'sxOYAAuyzSx0WqN3BVPjE+6pgPU' is most probably unrelated to the pickle's problem
Post an error traceback for (to determine what class defines the attribute that can't be called (the one that leads to the TypeError):
python -c "import pickle; pickle.load(open('feeds.dat'))"
EDIT:
Add the following to your code and run (redirect stderr to file then use 'tail -2' on it to print last 2 lines):
from pprint import pprint
def setstate(self, dict_):
pprint(dict_, stream=sys.stderr, depth=None)
self.__dict__.update(dict_)
Feed.__setstate__ = setstate
If the above doesn't yield an interesting output then use general troubleshooting tactics:
Confirm that 'feeds.dat' is the problem:
backup ~/.rss2email directory
install rss2email into virtualenv/pip sandbox (or use zc.buildout) to isolate the environment (make sure you are using feedparser.py from the trunk).
add couple of feeds, add feeds until 'feeds.dat' size is greater than the current. Run some tests.
try old 'feeds.dat'
try new 'feeds.dat' on existing rss2email installation
See r2e bails out with TypeError bug on Ubuntu.

Categories

Resources