PyWin32 using MakePy utility and win32com to get Network Statistics - python

This question is in continuation to my previous question.
I am trying to get Network Statistics for my Windows 7 system using PyWin32.
The steps I followed:
1) Run COM MakePy utility and than select network list manager 1.0
type library under type library.
2) Above process generated this python file.
Next I created the object of class NetworkListManager(CoClassBaseClass) using
import win32com.client as wc
obj = wc.Dispatch("{DCB00C01-570F-4A9B-8D69-199FDBA5723B}")
Now I am trying to access the methods provided by the above created object obj.
help(obj) gave me
GetNetwork(self, gdNetworkId= <PyOleEmpty object>)
Get a network given a Network ID.
IsConnected
Returns whether connected to internet or not
//Other methods removed
So, now when I use
>>> obj.IsConnected
True
It works fine.
Now the problem I am facing is how to use GetNetowrk method because when I try to use it
>>> obj.GetNetwork()
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
ret = self._oleobj_.InvokeTypes(2, LCID, 1, (9, 0), ((36, 1),),gdNetworkId
com_error: (-2147024809, 'The parameter is incorrect.', None, None)
I also tried creating PyOleEmpty object by using pythoncom.Empty and passed it as a paremeter but no luck.
I understand GetNetwork require NetworkID as a parameter but the method GetNetworkId is defined in INetwork class.
So my question is how to use classes defined in the python file created using MakePy utility which are not CoClass.

It looks like the way to get to the Network objects is to enumerate them using GetNetworks:
networks=obj.GetNetworks(win32com.client.constants.NLM_ENUM_NETWORK_CONNECTED)
for network in networks:
print (network.GetName(), network.GetDescription())
Using the network ids will be problematic. They're defined as raw structs, so they will need to be passed using Records. Pywin32's support for the IRecordInfo interface is still somewhat weak.

Related

Solidworks PDM API in Python--getting AttributeError object has no attribute 'QueryInterface'

I've written a bunch of Python code for tagging our vendor files in Solidworks PDM and I'm trying to use the Solidworks PDM API to actually apply that information. Officially the API only supports C# and VB, but I'd like to keep everything in Python if possible, because everything else is already in Python (and it's the language I'm most comfortable programming with). Here's a high level list of what I'm trying to accomplish:
Check out a bunch of files
Update a data card variable
Check those files back in
The API defines two ways main ways to check in/check out/update variables in individual files--one for individual files and one for groups of files. You can use methods accessible through the IEdmVault5 interface to perform all 3 operations on individual files, and to perform these operations on groups of files you have to use 3 separate interfaces--IEdmBatchGet (checkout), IEdmBatchUpdate2 (update variables), and IEdmBatchUnlock (check in).
I was able write functional code that does all 3 things for each individual file, but it was slow when operating on many files--my goal is to update a couple thousand files at once. Getting the batch interfaces to work proved much trickier, but I was able to eventually get batch checkout and checkin working (and it was definitely worth it--each operation was about 10X faster using the vault interface). However, I'm gotten pretty stuck trying to make variable updating work. Here's my code for updating variables:
import win32com.client
import os
import comtypes.client as cc
cc.GetModule('C:\Program Files (x86)\SOLIDWORKS PDM\EdmInterface.dll')
import comtypes.gen._5FA2C692_8393_4F31_9BDB_05E6F807D0D3_0_5_22 as pdm_lib2
vault_name = 'vault_name'
folder_path = 'some_folder_path'
def connect_to_vault(vault_name, lib = 'comtypes'):
if lib == 'comtypes':
vault = cc.CreateObject('ConisioLib.EdmVault.1')
vault.LoginAuto(vault_name, 0)
else:
vault = win32com.client.dynamic.Dispatch('ConisioLib.EdmVault.1')
vault.LoginAuto(vault_name, 0)
return vault
def getrefs(vault, filenames, folder_path):
DocIDs = []
ProjIDs = []
for filename in filenames:
temp_ProjID = vault.GetFolderFromPath(folder_path)
temp_DocID = vault.GetFileFromPath(filename, temp_ProjID)[0] #this fails when I use a comtypes generated vault
DocIDs.append(temp_DocID.ID)
ProjIDs.append(temp_ProjID.ID)
print('Document and Project IDs pulled')
return DocIDs, ProjIDs
vault = connect_to_vault(vault_name)
ref_vault =connect_to_vault(vault_name, lib = 'win32com')
filenames = [folder_path + s for s in os.listdir(folder_path)]
DocIDs, ProjIDs = getrefs(ref_vault, filenames, folder_path)
#Using Comtypes to update files
VarIDs = [54] * len(DocIDs) #Updating description only
var_values = [['foo' + str(s)] for s in range(len(DocIDs))] #dummy values for now
update_vars = vault.CreateUtility(2) #create instance of BatchUpdate
for i, file in enumerate(DocIDs):
update_vars.SetVar(file, VarIDs[i], var_values[i], '', 1)
pdm_error = [pdm_lib2.EdmBatchError2()] * len(DocIDs)
update_vars.CommitUpdate([pdm_error])
When I call update_vars.CommitUpdate([pdm_error]), I get the following error:
ArgumentError: argument 2: <class 'AttributeError'>: 'list' object has no attribute 'QueryInterface'
I'm not sure why this method is expecting an object with a 'QueryInterface' attribute--I'm only passing it a list of structs, not a full COM object like my file vault. I also tried using win32com to execute the method:
update_vars = ref_vault.CreateUtility(2) #create instance of BatchUpdate, use win32com instead
for i, file in enumerate(DocIDs):
update_vars.SetVar(file, VarIDs[i], var_values[i], '', 1)
pdm_error = [pdm_lib2.EdmBatchError2()] * len(DocIDs)
update_vars.CommitUpdate([pdm_error])
And now I get this error:
Traceback (most recent call last):
File "<ipython-input-222-0c49fb0861b9>", line 7, in <module>
update_vars.CommitUpdate([pdm_error])
File "D:\Users\apreacher\Documents\Shared Files\Python\Webscraping_projects\Helper Modules\pdm_lib.py", line 1500, in CommitUpdate
, poCallback)
File "C:\Users\apreacher\AppData\Local\Continuum\anaconda3\lib\site-packages\win32com\client\__init__.py", line 467, in _ApplyTypes_
self._oleobj_.InvokeTypes(dispid, 0, wFlags, retType, argTypes, *args),
MemoryError: CreatingSafeArray
And this is where I'm stuck. I haven't been able to make any headway on getting the CommitUpdate method to work properly. I also have the method definitions from the files generated by makepy.py and comtypes, but I don't really know how to interpret them:
makepy.py method definition:
def CommitUpdate(self, ppoRetErrors=pythoncom.Missing, poCallback=0):
'method Commit'
return self._ApplyTypes_(3, 1, (3, 0), ((24612, 2), (9, 49)), 'CommitUpdate', None,ppoRetErrors
, poCallback)
comtypes generated file:
COMMETHOD([dispid(3), helpstring('method Commit')], HRESULT, 'CommitUpdate',
( ['out'], POINTER(_midlSAFEARRAY(EdmBatchError2)), 'ppoRetErrors' ),
( ['in', 'optional'], POINTER(IEdmCallback), 'poCallback', 0 ),
( ['out', 'retval'], POINTER(c_int), 'plErrorCount' )),
Any ideas?
What version of PDM are you using? (I am on Pro 2019 sp4.)
I just noticed an inconsistency in your code. vault.CreateUtility(2) would (in .NET) return an object of type IEdmBatchUpdate. 4 lines later, you are calling the method CommitUpdate which only exists for the newer API IEdmBatchUpdate2 (see https://help.solidworks.com/2020/english/api/epdmapi/EPDM.Interop.epdm~EPDM.Interop.epdm.IEdmBatchUpdate2.html ).
I can tell you for certain under C#, this would require casting the result of CreatUtility to the proper object type.
It seems you are looking for a way to automate entry of data into file datacards.
Have you tried using data import rules? https://help.solidworks.com/2020/English/EnterprisePDM/Admin/c_Working_With_Variable_Values_overview.htm

Attribute error from SoCo class MusicLibrary that documentation appears to say is not an error

I am doing initial exploration in the SoCo module which is a Python API for Sonos. Following the tutorial I do
>>> speakers = soco.discover()
>>> speaker = speakers.pop()
>>> speaker.player_name
'Portable'
>>> speaker.ip_address
'192.168.0.11'
>>> speaker.get_current_transport_info()['current_transport_state']
'STOPPED'
So far, so good. Now, still following the documentation, I do
>>> speaker.music_library.list_library_shares()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'MusicLibrary' object has no attribute 'list_library_shares'
and, sure enough, dir(speaker.music_library) confirms there is no such method.
But the documentation for this class says:
Listing and deleting music library shares
Music library shares are the local network drive shares connected to Sonos, which host the
audio content in the Sonos Music Library.
To list the shares connected to Sonos, use the list_library_shares()
method as follows:
››› device.music_library.list_library_shares()
['//share_host_01/music', '//share_host_02/music']
The result is a
list of network share locations.
Now either the documentation is badly out of step with the version I just downloaded (0.18.1; it says not), or I need another pair of eyes to point out what I am doing wrong.
I asked this question also on the SoCo Google group and this is the answer I got:
This function is not included in v0.18.1, but will be in the upcoming
v0.19 release. It's unintuitive but you need to look at the v0.18.1
documentation at:
http://docs.python-soco.com/en/v0.18.1/api/soco.music_library.html
... not the 'latest' version of the documentation.
I forbear to remark on the wisdom of pointing readers of the Getting Started page in the wrong direction.

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.

Heavily confused by win32api + COM and an answer from SO

From my other question here on SO, I asked how to retrieve the current playing song from Windows Media Player and Zune, I got an answer from a c++ dev who gave me an explanation of how I would do this for WMP.
However, I am no C++ dev, nor am I very experienced with the pywin32 library. And on-top of all that, the documentation on all this (especially concerning WMP) is horrible.
Therefor, I need your help understanding how I would do the following in Python.
Source
I have working code in C++ to print the name of media currently
playing in WMP. It's a simple console application (78 lines of code).
Steps:
1) implements a basic COM object implementing IUnknown, IOleClientSite, IServiceProvider and IWMPRemoteMediaServices. This is
straightforward (sort of, your mileage may vary) using the ATL
template CComObjectRootEx. The only methods needing (simple) code are
IServiceProvider::QueryService and
IWMPRemoteMediaServices::GetServiceType. All other methods may return
E_NOTIMPL
2) Instantiate the "WMPlayer.OCX" COM object (in my case, via CoCreateInstance)
3) Retrieve from the object an IOleObject interface pointer via QueryInterface
4) Instanciate an object from the class seen in 1) (I use the CComObject<>::CreateInstance template)
5) Use the SetClientSite method from the interface you got at 3), passing a pointer to your OleClientSite implementation.
6) During the SetClientSite call, WMP will callback you: fisrt asking for an IServiceProvider interface pointer, second calling the
QueryService method, asking for an IWMPRemoteMediaServices interface
pointer. Return your implementation of IWMPRemoteMediaServices and,
third, you will be called again via GetServiceType. You must then
return "Remote". You are now connected to the WMP running instance
7) Query the COM object for an IWMPMedia interface pointer
8) If 7) didn't gave NULL, read the the IWMPMedia::name property.
9) DONE
All the above was tested with VS2010 / Windows Seven, and with WMP
running (if there is no Media Player process running, just do
nothing).
I don't know if yoy can/want to implement COM interface and object in
Python. If you are interested by my C++ code, let me know. You could
use that code in a C++ DLL, and then call it from python.
I know a little bit about the win32api.
At the first step, I really don't know what to do, googling IOleClientSite results in the msdn documentation, it's an interface. However, that's where I get stuck already. I can't find anything (might just be my horrendous googling skills) on working with these things in Python.
The second step:
WMP = win32com.client.Dispatch("WMPlayer.OCX")
Alright, that's doable.
On to the third step. QueryInterface -
"regardless of the object you have, you can always call its QueryInterface() method to obtain a new interface, such as IStream."
source
However, not for me. As I understand his explanation, I think it means that every com object sort of "inherits" three methods from IUnknown, one of which is QueryInterface, however this does not seem the case since calling QueryInterface on my WMP object fails miserably. (Object has no attribute 'QueryInterface')
I could ramble on, but I believe you got the point, I have no idea how to work with this. Can anyone help me out with this one? Preferably with code examples, but resources/documentation is welcome too.
Almost final answser but CAN'T finish.
I seems that pythoncom can't be used to implement custom Interface without the help of a C++ module.
Here is an answser from Mark Hammon (Mon, 13 Jan 2003): How to create COM Servers with IID_IDTExtensibility2 interface
Sorry - you are SOL. To support arbitary interfaces, you need C++
support, in the form of an extension module. There is a new "Univgw"
that may help you out, but I dont know much about this
I am not able to find anything about that "Univgw" thing...
The comtypes python module is intended to resolve the problem, and I found links saying it does, but I can't make it works with my fresh new Python 3.3. It's Python 2.x code. comtypes seems outdated and unmaintained.
Step 1 OK for IOleClientSite and IServiceProvider, KO for IWMPRemoteMediaServices
Step 2, 3, 4 and 5 OK
Step 6, 7 and 8 can't be implemented without IWMPRemoteMediaServices :-(
disclaimer: complete newbie in Python, please don't yell
import pythoncom
import win32com.client as wc
from win32com.axcontrol import axcontrol
import win32com.server as ws
from win32com.server import util
from win32com.server.exception import COMException
import winerror
import pywintypes
# Windows Media Player Custom Interface IWMPRemoteMediaServices
IWMPRemoteMediaServices = pywintypes.IID("{CBB92747-741F-44FE-AB5B-F1A48F3B2A59}")
class OleClientSite:
_public_methods_ = [ 'SaveObject', 'GetMoniker', 'GetContainer', 'ShowObject', 'OnShowWindow', 'RequestNewObjectLayout', 'QueryService' ]
_com_interfaces_ = [ axcontrol.IID_IOleClientSite, pythoncom.IID_IServiceProvider ]
def SaveObject(self):
print("SaveObject")
raise COMException(hresult=winerror.E_NOTIMPL)
def GetMoniker(self, dwAssign, dwWhichMoniker):
print("GetMoniker ")
raise COMException(hresult=winerror.E_NOTIMPL)
def GetContainer(self):
print("GetContainer")
raise COMException(hresult=winerror.E_NOTIMPL)
def ShowObject(self):
print("ShowObject")
raise COMException(hresult=winerror.E_NOTIMPL)
def OnShowWindow(self, fShow):
print("ShowObject" + str(fShow))
raise COMException(hresult=winerror.E_NOTIMPL)
def RequestNewObjectLayout(self):
print("RequestNewObjectLayout")
raise COMException(hresult=winerror.E_NOTIMPL)
def QueryService(self, guidService, riid):
print("QueryService",guidService,riid)
if riid == IWMPRemoteMediaServices:
print("Known Requested IID, but can't implement!")
raise COMException(hresult=winerror.E_NOINTERFACE)
else:
print("Requested IID is not IWMPRemoteMediaServices" )
raise COMException(hresult=winerror.E_NOINTERFACE)
if __name__=='__main__':
wmp = wc.Dispatch("WMPlayer.OCX")
IOO = wmp._oleobj_.QueryInterface(axcontrol.IID_IOleObject)
pyOCS = OleClientSite()
comOCS = ws.util.wrap(pyOCS, axcontrol.IID_IOleClientSite)
IOO.SetClientSite(comOCS)

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