Pass the variable `Nothing` using Python's `win32com` - python

I am trying to pass the variable Nothing in VBA using Python's win32com. I tried to use None but it returned 'Type dismatch.'
Could anyone please help?
Thank you!
An example:
' Book1.xlsm!Module1
Function test(arg As Object) As String
If arg Is Nothing Then
test = "Success"
Exit Function
Else
test = "Failure"
Exit Function
End If
End Function
And in Python:
import win32com.client
import os
import pythoncom
xl = win32com.client.Dispatch('Excel.Application')
xl.Visible = True
xl.Workbooks.Open(Filename=os.path.abspath('Book1.xlsm'))
test_str = xl.Application.Run('Book1.xlsm!Module1.test', pythoncom.Empty)
The REPL says:
runfile('C:/Users/shwang/Downloads/untitled0.py', wdir='C:/Users/shwang/Downloads')
Traceback (most recent call last):
File "<ipython-input-22-301693920f2c>", line 1, in <module>
runfile('C:/Users/shwang/Downloads/untitled0.py', wdir='C:/Users/shwang/Downloads')
File "C:\Anaconda3\lib\site-packages\spyder\utils\site\sitecustomize.py", line 866, in runfile
execfile(filename, namespace)
File "C:\Anaconda3\lib\site-packages\spyder\utils\site\sitecustomize.py", line 102, in execfile
exec(compile(f.read(), filename, 'exec'), namespace)
File "C:/Users/shwang/Downloads/untitled0.py", line 16, in <module>
test_str = xl.Application.Run('Book1.xlsm!Module1.test', pythoncom.Empty)
File "<COMObject <unknown>>", line 14, in Run
File "C:\Anaconda3\lib\site-packages\win32com\client\dynamic.py", line 287, in _ApplyTypes_
result = self._oleobj_.InvokeTypes(*(dispid, LCID, wFlags, retType, argTypes) + args)
com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2147352561), None)

In VBA, Nothing is used as the uninitialized default value Object type which usually references COM objects (i.e., Excel object library or external application's object library). VBA's primitive integer, long, and string types cannot be assigned the Nothing value. And usually programmers use this at the end of code block to release objects from memory.
Hence, there is no strict translation between VBA's Nothing (a special value for COM types) and Python's value types including None which crudely means empty or no value for any type.
With that said, your code will not err out if you pass a COM object which you already initialize with xl. Below outputs FAILURE. If somehow you can declare an uninitialized COM object which then will carry Nothing then you can pass that into your function. But to call Dispatch requires a named object. Catch-22!
import win32com.client
import os
try:
xl = win32com.client.Dispatch('Excel.Application')
xl.Visible = True
wb = xl.Workbooks.Open(Filename=os.path.abspath('Book1.xlsm'))
test_str = xl.Application.Run('test', xl)
print(test_str)
# FAILURE
wb.Close(False)
xl.Quit
except Exception as e:
print(e)
finally:
wb = None
xl = None

Here is a working example (in python) that passes VBA Nothing object to SolidWorks API.
import win32com.client
import pythoncom
swApp = win32com.client.Dispatch('SldWorks.Application')
Part = swApp.ActiveDoc
boolstatus = Part.Extension.SelectByID2("", "SKETCHCONTOUR", 75e-3, -4e-3, 0, False, 0, pythoncom.Nothing, 0)
print(boolstatus)
Here is the output in Sublime Text 3:
True
[Finished in 0.7s]
The script tries to select a sketch contour with the coordinates (75mm, -4mm). The "Callout" argument of the SolidWorks API "SelectByID2" is assigned as pythoncom.Nothing. For the script to work, the premise is that you are editing a sketch as shown in the attached figure below.
The attached figure shows what happens in SolidWorks (before | after).
Pass Nothing to SW API SelectByID2
Some background. I want to draw some electric motor geometry in SolidWorks via python because I already have the working python codes with other drawing tools (such as JMAG Designer, FEMM, or PyX).
Thanks for the post! Your discussion helps me find this.

Related

AttributeError when using googletrans module

I am writing code to make a translator using GUI. My program runs but when I try to translate text it throws the error AttributeError: 'NoneType' object has no attribute 'group'
My code
from tkinter import*
from tkinter import ttk
from googletrans import Translator,LANGUAGES
def change(text="type",src="English",dest="Hindi"):
text1=text
src1=src
dest1=dest
trans = Translator()
trans1 = trans.translate(text,src=src1,dest=dest1)
return trans1.text
def data():
s =comb_sor.get()
d =comb_dest.get()
msg = Sor_txt.get(1.0,END)
textget = change(text=msg,src=s,dest=d)
dest_txt.delete(1.0,END)
dest_txt.insert(END,textget)
root = Tk()
root.title("Translater")
root.geometry("500x800")
root.config(bg="#FFE1F3")
lab_txt=Label(root,text="Translator", font=("Time New Roman",40,"bold"),fg="#478C5C")
lab_txt.place(x=100,y=40,height=50,width=300)
frame=Frame(root).pack(side=BOTTOM)
lab_txt=Label(root,text="Source Text", font=("Time New Roman",20,"bold"),fg="#FFFF8A",bg="#FDA172")
lab_txt.place(x=100,y=100,height=20,width=300)
Sor_txt =Text(frame,font=("Time New Roman",20,"bold"),wrap=WORD)
Sor_txt.place(x=10,y=130,height=150,width=480)
list_text = list(LANGUAGES.values())
comb_sor = ttk.Combobox(frame,value=list_text)
comb_sor.place(x=10,y=300,height=20,width=100)
comb_sor.set("English")
button_change = Button(frame,text="Translate",relief=RAISED,command=data)
button_change.place(x=120,y=300,height=40,width=100)
comb_dest = ttk.Combobox(frame,value=list_text)
comb_dest.place(x=230,y=300,height=20,width=100)
comb_dest.set("English")
lab_txt=Label(root,text="Dest Text", font=("Time New Roman",20,"bold"),fg="#2E2EFF")
lab_txt.place(x=100,y=360,height=50,width=300)
dest_txt=Text(frame,font=("Time New Roman",20,"bold"),wrap=WORD)
dest_txt.place(x=10,y=400,height=150,width=480)
root.mainloop()
The error and stack trace
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\praful pawar\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 1921, in __call__
return self.func(*args)
File "C:\Users\praful pawar\AppData\Local\Temp\ipykernel_9920\1422625581.py", line 19, in data
textget = change(text=msg,src=s,dest=d)
File "C:\Users\praful pawar\AppData\Local\Temp\ipykernel_9920\1422625581.py", line 10, in change
trans1 = trans.translate(text,src=src1,dest=dest1)
File "C:\Users\praful pawar\AppData\Local\Programs\Python\Python310\lib\site-packages\googletrans\client.py", line 182, in translate
data = self._translate(text, dest, src, kwargs)
File "C:\Users\praful pawar\AppData\Local\Programs\Python\Python310\lib\site-packages\googletrans\client.py", line 78, in _translate
token = self.token_acquirer.do(text)
File "C:\Users\praful pawar\AppData\Local\Programs\Python\Python310\lib\site-packages\googletrans\gtoken.py", line 194, in do
self._update()
File "C:\Users\praful pawar\AppData\Local\Programs\Python\Python310\lib\site-packages\googletrans\gtoken.py", line 62, in _update
code = self.RE_TKK.search(r.text).group(1).replace('var ', '')
AttributeError: 'NoneType' object has no attribute 'group'
What it looks like
This image shows that my application is running but something is wrong:
This library's own documentation says (bold added by me):
I eventually figure out a way to generate a ticket by reverse engineering on the obfuscated and minified code used by Google to generate such token, and implemented on the top of Python. However, this could be blocked at any time.
It is designed to work around limitations that Google deliberately installed in Google Translate to make sure you use their official API (and presumably pay) to connect to their service programmatically.
I believe that what you are seeing today is that, as the author warned could happen at any time, it got blocked. The last release was two years ago, so Google has had plenty of time to patch the hole this library exploited.
PS: there's a ticket about this...
Well, I still think this library could get blocked at any time, but it turns out the library is still actively maintained, and they have a ticket open about this issue: https://github.com/ssut/py-googletrans/issues/354 I suggest you watch that ticket, maybe they will fix it.
I just tested the release candidate one reply mentions in the ticket, and it fixed the problem for me:
pip install googletrans==4.0.0rc1
might make your code work.

What does a "with" statement do without the "as"?

with dpg.window(label="Window"):
dpg.add_text("Hello, world")
dpg.add_button(label="Save")
dpg.add_input_text(label="string", default_value="Quick brown fox")
dpg.add_slider_float(label="float", default_value=0.273, max_value=1)
dpg.add_color_picker(label="Pick", default_value=(0, 0, 0))
This code runs without error (given the correct imports and setup)
dpg.window(label="Window")
dpg.add_text("Hello, world")
dpg.add_button(label="Save")
dpg.add_input_text(label="string", default_value="Quick brown fox")
dpg.add_slider_float(label="float", default_value=0.273, max_value=1)
dpg.add_color_picker(label="Pick", default_value=(0, 0, 0))
This code does not. A runtime error occurs on line 2. I do not understand how a with statement with no as affects the contents of the with. I've seen another similar post, but I can't understand how the explanation answers my question.
Here is the stacktrace for the error:
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:\Users\18328\PycharmProjects\sandbox\main.py", line 10, in <module>
dpg.add_text("Hello, world")
File "C:\Users\18328\AppData\Local\Programs\Python\Python39\lib\site-packages\dearpygui\dearpygui.py", line 7019, in add_text
return internal_dpg.add_text(default_value, label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, source=source, payload_type=payload_type, drag_callback=drag_callback, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, wrap=wrap, bullet=bullet, color=color, show_label=show_label, **kwargs)
SystemError: <built-in function add_text> returned a result with an error set
On the Python side: Context managers run completely arbitrary code on enter and exit. Python doesn't force that code to do things "behind your back", but neither does it present them from doing so; so the implementation of the specific context manager at hand needs to be inspected to know why it's modifying behavior.
From a DearPyGui perspective: The C++ library that dpg backends into maintains a "container stack". Entering a container as a context manager ensures that it's on the top of your stack. When you create a new DearPyGui object that needs to be attached to a container, it refers to that stack, and attaches itself to the thing that is currently on top.
Using the translation provided by PEP-343, you can see that
with dpg.window(label="Window"):
...
is equivalent to
mgr = dpg.window(label="Window")
exit = type(mgr.__exit__)
value = type(mgr).__enter__(mgr)
exc = True
try:
try:
...
except:
exc = False
if not exit(mgr, *sys.exc_info()):
raise
finally:
if exc:
exit(mgr, None, None, None)
You can compare the above to the fuller translation in PEP-343 to see the single line I omitted that results from the use of as.
In your examples, dpg.window(label="Window").__enter__ is called in the first example, but not in the second.

Python pywin32 error passing an optional string via a VBA click

I am working with legacy access code and am using pywin32 to automate batch processing.
This python code:
import win32com.client as win32
access = win32.Dispatch('Access.Application')
db = access.OpenCurrentDatabase(r'C:\test\PN.mdb')
access.Forms('frm_PN_Startup').cmdScenarioExport_Click()
sucessfully executes this Access VBA sub
Public Sub cmdScenarioExport_Click()
Export_Scenario_To_ScenarioDB
End Sub
I would like to pass an optional text string to fill the Access InputBox that opens in Export_Scenario_To_ScenarioDB. However, when I try
Python
import win32com.client as win32
access = win32.Dispatch('Access.Application')
db = access.OpenCurrentDatabase(r'C:\test\PN.mdb')
access.Forms('frm_PN_Startup').cmdScenarioExport_Click("hello")
Vba
Public Sub cmdScenarioExport_Click(Optional strTest As String = "")
Export_Scenario_To_ScenarioDB (strTest)
End Sub
I get the following error:
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "C:\Users\RS\miniconda3\envs\PN_PY\lib\site-packages\win32com\client\dynamic.py", line 197, in __call__
return self._get_good_object_(self._oleobj_.Invoke(*allArgs),self._olerepr_.defaultDispatchName,None)
pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2146788252), None)
win32api tells me that the error is
win32api.FormatMessage(-2147352567)
'Exception occurred.\r\n'
After numerous hours spinning my wheels, I'm asking for any ideas to make this work. Thank you! This is my first foray into VBA.

Modify VHDL generic value with ghdl in cocotb

I managed to read generic module value with cocotb without problem. But if I can't manage to write it.
My VHDL generic is :
...
generic (
...
C_M00_AXI_BURST_LEN : integer := 16;
...
)
I can read it in cocotb:
self.dut.log.info("C_M00_AXI_BURST_LEN 0x{:x}".format(
int(self.dut.c_m00_axi_burst_len)))
But if I try to change it :
self.dut.c_m00_axi_burst_len = 32
I get this python error :
Send raised exception: Not permissible to set values on object c_m00_axi_burst_len
File "/opt/cocotb/cocotb/decorators.py", line 197, in send
return self._coro.send(value)
File "/usr/local/projects/axi_pattern_tester/vivado_ip/axi_pattern_tester_1.0/cocotb/test_axi_pattern_tester_v1_0.py", line 165, in axi4_master_test
dutest.print_master_generics()
File "/usr/local/projects/axi_pattern_tester/vivado_ip/axi_pattern_tester_1.0/cocotb/test_axi_pattern_tester_v1_0.py", line 86, in print_master_generics
self.dut.c_m00_axi_burst_len = 32
File "/opt/cocotb/cocotb/handle.py", line 239, in __setattr__
return getattr(self, name)._setcachedvalue(value)
File "/opt/cocotb/cocotb/handle.py", line 378, in _setcachedvalue
raise TypeError("Not permissible to set values on object %s" % (self._name))
Is there a way to do it using GHDL as simulator ?
In fact, user1155120, Paebbels and scary_jeff respond to the question : It's not possible.
But it's possible to use configuration differently to solve this problem. VHDL Generic value can be configured in Makefile adding "-g" option to SIM_ARGS parameter :
SIM_ARGS+=-gC_M00_AXI_BURST_LEN=16
This value can then be read under cocotb "dut" object like any others signal and used as simulation parameter :
C_M00_AXI_BURST_LEN = int(dut.C_M00_AXI_BURST_LEN.value)

PicklingError: Can't pickle <class 'decimal.Decimal'>: it's not the same object as decimal.Decimal

This is the error I got today at <a href"http://filmaster.com">filmaster.com:
PicklingError: Can't pickle <class
'decimal.Decimal'>: it's not the same
object as decimal.Decimal
What does that exactly mean? It does not seem to be making a lot of sense...
It seems to be connected with django caching. You can see the whole traceback here:
Traceback (most recent call last):
File
"/home/filmaster/django-trunk/django/core/handlers/base.py",
line 92, in get_response response =
callback(request, *callback_args,
**callback_kwargs)
File
"/home/filmaster/film20/film20/core/film_views.py",
line 193, in show_film
workflow.set_data_for_authenticated_user()
File
"/home/filmaster/film20/film20/core/film_views.py",
line 518, in
set_data_for_authenticated_user
object_id = self.the_film.parent.id)
File
"/home/filmaster/film20/film20/core/film_helper.py",
line 179, in get_others_ratings
set_cache(CACHE_OTHERS_RATINGS,
str(object_id) + "_" + str(user_id),
userratings)
File
"/home/filmaster/film20/film20/utils/cache_helper.py",
line 80, in set_cache return
cache.set(CACHE_MIDDLEWARE_KEY_PREFIX
+ full_path, result, get_time(cache_string))
File
"/home/filmaster/django-trunk/django/core/cache/backends/memcached.py",
line 37, in set
self._cache.set(smart_str(key), value,
timeout or self.default_timeout)
File
"/usr/lib/python2.5/site-packages/cmemcache.py",
line 128, in set val, flags =
self._convert(val)
File
"/usr/lib/python2.5/site-packages/cmemcache.py",
line 112, in _convert val =
pickle.dumps(val, 2)
PicklingError: Can't pickle <class
'decimal.Decimal'>: it's not the same
object as decimal.Decimal
And the source code for Filmaster can be downloaded from here: bitbucket.org/filmaster/filmaster-test
Any help will be greatly appreciated.
I got this error when running in an jupyter notebook. I think the problem was that I was using %load_ext autoreload autoreload 2. Restarting my kernel and rerunning solved the problem.
One oddity of Pickle is that the way you import a class before you pickle one of it's instances can subtly change the pickled object. Pickle requires you to have imported the object identically both before you pickle it and before you unpickle it.
So for example:
from a.b import c
C = c()
pickler.dump(C)
will make a subtly different object (sometimes) to:
from a import b
C = b.c()
pickler.dump(C)
Try fiddling with your imports, it might correct the problem.
I will demonstrate the problem with simple Python classes in Python2.7:
In [13]: class A: pass
In [14]: class B: pass
In [15]: A
Out[15]: <class __main__.A at 0x7f4089235738>
In [16]: B
Out[16]: <class __main__.B at 0x7f408939eb48>
In [17]: A.__name__ = "B"
In [18]: pickle.dumps(A)
---------------------------------------------------------------------------
PicklingError: Can't pickle <class __main__.B at 0x7f4089235738>: it's not the same object as __main__.B
This error is shown because we are trying to dump A, but because we changed its name to refer to another object "B", pickle is actually confused with which object to dump - class A or B. Apparently, pickle guys are very smart and they have already put a check on this behavior.
Solution:
Check if the object you are trying to dump has conflicting name with another object.
I have demonstrated debugging for the case presented above with ipython and ipdb below:
PicklingError: Can't pickle <class __main__.B at 0x7f4089235738>: it's not the same object as __main__.B
In [19]: debug
> /<path to pickle dir>/pickle.py(789)save_global()
787 raise PicklingError(
788 "Can't pickle %r: it's not the same object as %s.%s" %
--> 789 (obj, module, name))
790
791 if self.proto >= 2:
ipdb> pp (obj, module, name) **<------------- you are trying to dump obj which is class A from the pickle.dumps(A) call.**
(<class __main__.B at 0x7f4089235738>, '__main__', 'B')
ipdb> getattr(sys.modules[module], name) **<------------- this is the conflicting definition in the module (__main__ here) with same name ('B' here).**
<class __main__.B at 0x7f408939eb48>
I hope this saves some headaches! Adios!!
I can't explain why this is failing either, but my own solution to fix this was to change all my code from doing
from point import Point
to
import point
this one change and it worked. I'd love to know why... hth
There can be issues starting a process with multiprocessing by calling __init__. Here's a demo:
import multiprocessing as mp
class SubProcClass:
def __init__(self, pipe, startloop=False):
self.pipe = pipe
if startloop:
self.do_loop()
def do_loop(self):
while True:
req = self.pipe.recv()
self.pipe.send(req * req)
class ProcessInitTest:
def __init__(self, spawn=False):
if spawn:
mp.set_start_method('spawn')
(self.msg_pipe_child, self.msg_pipe_parent) = mp.Pipe(duplex=True)
def start_process(self):
subproc = SubProcClass(self.msg_pipe_child)
self.trig_proc = mp.Process(target=subproc.do_loop, args=())
self.trig_proc.daemon = True
self.trig_proc.start()
def start_process_fail(self):
self.trig_proc = mp.Process(target=SubProcClass.__init__, args=(self.msg_pipe_child,))
self.trig_proc.daemon = True
self.trig_proc.start()
def do_square(self, num):
# Note: this is an synchronous usage of mp,
# which doesn't make sense. But this is just for demo
self.msg_pipe_parent.send(num)
msg = self.msg_pipe_parent.recv()
print('{}^2 = {}'.format(num, msg))
Now, with the above code, if we run this:
if __name__ == '__main__':
t = ProcessInitTest(spawn=True)
t.start_process_fail()
for i in range(1000):
t.do_square(i)
We get this error:
Traceback (most recent call last):
File "start_class_process1.py", line 40, in <module>
t.start_process_fail()
File "start_class_process1.py", line 29, in start_process_fail
self.trig_proc.start()
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/process.py", line 105, in start
self._popen = self._Popen(self)
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/context.py", line 212, in _Popen
return _default_context.get_context().Process._Popen(process_obj)
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/context.py", line 274, in _Popen
return Popen(process_obj)
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/popen_spawn_posix.py", line 33, in __init__
super().__init__(process_obj)
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/popen_fork.py", line 21, in __init__
self._launch(process_obj)
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/popen_spawn_posix.py", line 48, in _launch
reduction.dump(process_obj, fp)
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/reduction.py", line 59, in dump
ForkingPickler(file, protocol).dump(obj)
_pickle.PicklingError: Can't pickle <function SubProcClass.__init__ at 0x10073e510>: it's not the same object as __main__.__init__
And if we change it to use fork instead of spawn:
if __name__ == '__main__':
t = ProcessInitTest(spawn=False)
t.start_process_fail()
for i in range(1000):
t.do_square(i)
We get this error:
Process Process-1:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/process.py", line 254, in _bootstrap
self.run()
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/process.py", line 93, in run
self._target(*self._args, **self._kwargs)
TypeError: __init__() missing 1 required positional argument: 'pipe'
But if we call the start_process method, which doesn't call __init__ in the mp.Process target, like this:
if __name__ == '__main__':
t = ProcessInitTest(spawn=False)
t.start_process()
for i in range(1000):
t.do_square(i)
It works as expected (whether we use spawn or fork).
Did you somehow reload(decimal), or monkeypatch the decimal module to change the Decimal class? These are the two things most likely to produce such a problem.
Same happened to me
Restarting the kernel worked for me
Due to the restrictions based upon reputation I cannot comment, but the answer of Salim Fahedy and following the debugging-path set me up to identify a cause for this error, even when using dill instead of pickle:
Under the hood, dill also accesses some functions of dill. And in pickle._Pickler.save_global() there is an import happening. To me it seems, that this is more of a "hack" than a real solution as this method fails as soon as the class of the instance you are trying to pickle is not imported from the lowest level of the package the class is in. Sorry for the bad explanation, maybe examples are more suitable:
The following example would fail:
from oemof import solph
...
(some code here, giving you the object 'es')
...
model = solph.Model(es)
pickle.dump(model, open('file.pickle', 'wb))
It fails, because while you can use solph.Model, the class actually is oemof.solph.models.Model for example. The save_global() resolves that (or some function before that which passes it to save_global()), but then imports Model from oemof.solph.models and throws an error, because it's not the same import as from oemof import solph.Model (or something like that, I'm not 100% sure about the workings).
The following example would work:
from oemof.solph.models import Model
...
some code here, giving you the object 'es')
...
model = Model(es)
pickle.dump(model, open('file.pickle', 'wb'))
It works, because now the Model object is imported from the same place, the pickle._Pickler.save_global() imports the comparison object (obj2) from.
Long story short: When pickling an object, make sure to import the class from the lowest possible level.
Addition: This also seems to apply to objects stored in the attributes of the class-instance you want to pickle. If for example model had an attribute es that itself is an object of the class oemof.solph.energysystems.EnergySystem, we would need to import it as:
from oemof.solph.energysystems import EnergySystem
es = EnergySystem()
My issue was that I had a function with the same name defined twice in a file. So I guess it was confused about which one it was trying to pickle.
I had same problem while debugging (Spyder). Everything worked normally if run the program. But, if I start to debug I faced the picklingError.
But, once I chose the option Execute in dedicated console in Run configuration per file (short-cut: ctrl+F6) everything worked normally as expected. I do not know exactly how it is adapting.
Note: In my script I have many imports like
from PyQt5.QtWidgets import *
from PyQt5.Qt import *
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import os, sys, re, math
My basic understanding was, because of star (*) I was getting this picklingError.
I had a problem that no one has mentioned yet. I have a package with a __init__ file that does, among other things:
from .mymodule import cls
Then my top-level code says:
import mypkg
obj = mypkg.cls()
The problem with this is that in my top-level code, the type appears to be mypkg.cls, but it's actually mypkg.mymodule.cls. Using the full path:
obj = mypkg.mymodule.cls()
avoids the error.
I had the same error in Spyder. Turned out to be simple in my case. I defined a class named "Class" in a file also named "Class". I changed the name of the class in the definition to "Class_obj". pickle.dump(Class_obj,fileh) works, but pickle.dump(Class,fileh) does not when its saved in a file named "Class".
This miraculous function solves the mentioned error, but for me it turned out to another error 'permission denied' which comes out of the blue. However, I guess it might help someone find a solution so I am still posting the function:
import tempfile
import time
from tensorflow.keras.models import save_model, Model
# Hotfix function
def make_keras_picklable():
def __getstate__(self):
model_str = ""
with tempfile.NamedTemporaryFile(suffix='.hdf5', delete=True) as fd:
save_model(self, fd.name, overwrite=True)
model_str = fd.read()
d = {'model_str': model_str}
return d
def __setstate__(self, state):
with tempfile.NamedTemporaryFile(suffix='.hdf5', delete=True) as fd:
fd.write(state['model_str'])
fd.flush()
model = load_model(fd.name)
self.__dict__ = model.__dict__
cls = Model
cls.__getstate__ = __getstate__
cls.__setstate__ = __setstate__
# Run the function
make_keras_picklable()
### create then save your model here ###

Categories