MemoryError in Python leads to empty pickle file - python

I'm working on a library-type checkout/checkin system. When the user clicks exit, the program calls a close_window function which dumps the current dictionary objects into pickle files before the window is destroyed.
def close_window(self):
if messagebox.askokcancel("Quit", "You want to close the program now?"):
patrons.dump_data()
self.master.destroy()
When the program is started again, it calls a load_data function which loads the pickled files. Somehow I ran into MemoryError when exiting the system and one of the pickled files was overwritten with an empty file. From the documentation, I gather that MemoryError occurs when the program creates too many objects and runs out of memory. I am not sure why this happened in my case since I am not dealing with large data. The pickled file that got overwritten was only 1 KB.
How can I ensure my pickled file is not overwritten with an empty file when MemoryError occurs? This can lead to serious data loss. I am new to programming and am using this project to learn. It is possible I've done something seriously wrong to lead to the memory error or maybe I just need more computer memory. In any case, it doesn't make sense to overwrite a saved file with an empty file whether memory error or not.
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python34\lib\tkinter\__init__.py", line 1487, in __call__
return self.func(*args)
File "C:/Python34/Lib/site-packages/toolkit/main.py", line 435, in close_window
patrons.dump_data()
File "C:\Python34\Lib\site-packages\toolkit\patrons.py", line 20, in dump_data
pickle.dump(patronslist, f)
MemoryError
This error is partially discussed in MemoryError while pickling data in python. Here though, I got an empty file, not even a partial file. And I want to know if there is a workaround for this problem. Perhaps saving the pickled data to a temporary file. If no memory error occurred during the save, then the temp file can be used to overwrite the permanent file (but this may yet trigger another MemoryError right?).
I run Win7 x86, 3 GB RAM, Python 3.4.1

Based on Gerrat's comment above, I wonder if the following is a good way to go about this:
patrons.py
def dump_data():
with open("./pickled_dicts/temp_patrons.pkl", 'wb') as f:
global patronslist
pickle.dump(patronslist, f)
main.py
def close_window(self):
if messagebox.askokcancel("Quit", "You want to close the program now?"):
try:
patrons.dump_data()
os.remove("./pickled_dicts/patrons.pkl")
os.rename("./pickled_dicts/temp_patrons.pkl", "./pickled_dicts/patrons.pkl")
except MemoryError:
messagebox.showerror("Memory Problem", "Your computer experienced memory problem. Your last session was not saved.")
self.master.destroy()
Essentially, I am first saving the dictionary object to a temporary file (temp_patrons.pkl) which is renamed to my permanent file (patrons.pkl) assuming no MemoryError. If MemoryError, then the original patrons.pkl remains.

Related

What causes this Attribute Error encountered when implementing LangChain's OpenAI LLM wrapper?

This is my first post here. I'm building a Python window application with PyQt5 that implements interactions with the OpenAI completions endpoint. So far, any code that I've written myself has performed fine, and I was reaching the point where I wanted to start implementing long-term memory for conversational interactions. I started by just running my own chain of prompts for categorizing and writing topical subjects and summaries to text files, but I decided it best to try exploring open source options to see how the programming community is managing things. This led me to LangChain, which seems to have some popular support behind it and already implements many features that I intend.
However, I have not had even the tiniest bit of success with it yet. Even the most simple examples don't perform, regardless of what context I'm implementing it in (within a class, outside a class, in an asynchronous loop, to the console, to my text browsers within the main window, whatever) I always get the same error message.
The simplest possible example:
import os
from langchain.llms import OpenAI
from local import constants #For API key
os.environ["OPENAI_API_KEY"] = constants.OPENAI_API_KEY
davinci = OpenAI(model_name= 'text-davinci-003', verbose=True, temperature=0.6)
text = "Write me a story about a guy who is frustrated with Python."
print("Prompt: " + text)
print(davinci(text))
It capably instantiates the wrapper and prints the prompt to the console, but at any point a command is sent through the wrapper's functions to receive generated text, it encounters this AttributeError.
Here is the traceback:
Traceback (most recent call last):
File "D:\Dropbox\Pycharm Projects\workspace\main.py", line 16, in <module>
print(davinci(text))
File "D:\Dropbox\Pycharm Projects\workspace\venv\lib\site-packages\langchain\llms\base.py", line 255, in __call__
return self.generate([prompt], stop=stop).generations[0][0].text
File "D:\Dropbox\Pycharm Projects\workspace\venv\lib\site-packages\langchain\llms\base.py", line 128, in generate
raise e
File "D:\Dropbox\Pycharm Projects\workspace\venv\lib\site-packages\langchain\llms\base.py", line 125, in generate
output = self._generate(prompts, stop=stop)
File "D:\Dropbox\Pycharm Projects\workspace\venv\lib\site-packages\langchain\llms\openai.py", line 259, in _generate
response = self.completion_with_retry(prompt=_prompts, **params)
File "D:\Dropbox\Pycharm Projects\workspace\venv\lib\site-packages\langchain\llms\openai.py", line 200, in completion_with_retry
retry_decorator = self._create_retry_decorator()
File "D:\Dropbox\Pycharm Projects\workspace\venv\lib\site-packages\langchain\llms\openai.py", line 189, in _create_retry_decorator
retry_if_exception_type(openai.error.Timeout)
AttributeError: module 'openai.error' has no attribute 'Timeout'
I don't expect that there is a fault in the LangChain library, because it seems like nobody else has experienced this problem. I imagine I may have some dependency issue? Or I do notice that others using the LangChain library are doing so in a notebook development environment, and my lack of familiarity in that regard is making me overlook some fundamental expectation of the library's use?
Any advice is welcome! Thanks!
What I tried: I initially just replaced my own function for managing calls to the completion endpoint with one that issued the calls through LangChain's llm wrapper. I expected it to work as easily as my own code had, but I received that error. I then stripped everything apart layer by layer attempting to instantiate the wrapper at every scope of the program, then I attempted to make the calls in an asynchronous function through a loop that waited to completion, and no matter what, I always get that same error message.
I think it might be something about your current installed versions of Python, OpenAI, and/or LangChain. Maybe try using a newer version of Python and OpenAI. I'm new to Python and these things but hopefully I could help.

Multiprocessing array .get_lock works on one computer but not another

I am working a somewhat extensive python program that uses multiprocessing. Because I wanted the user to see some progress on the console when running the program, I read about using a shared counter on stackoverflow and after a while of playing around with my code, I got it to work. As I said it's too much code to post here, but the gist is that I instantiate a multiprocessing array after the name==main line,
if __name__ == "__main__":
total_progress_counter = Array('i',[0,0])
and then during the main portion of code I pass this array to a function in other module:
some_name.plot(<other variables>,
total_progress_counter=total_progress_counter)
Then within that other function, I used the .get_lock method that I found described here on stackoverflow:
with total_progress_counter.get_lock():
total_progress_counter[0] += self.total_panels_to_plot
I also update the other component, total_progress_counter[1], in the same function. This works fine for me on my work machine, where I wrote the code, and that machine has a Centos operating system.
But, when I run it on my personal MacBook it gives the following traceback:
Traceback (most recent call last):
File "./program.py", line 775, in <module>
program.run()
File "./program.py", line 177, in run
cases_plotted = pool.map(self.__plot__, all_cases)
File "/opt/anaconda3/lib/python3.8/multiprocessing/pool.py", line 364, in map
return self._map_async(func, iterable, mapstar, chunksize).get()
File "/opt/anaconda3/lib/python3.8/multiprocessing/pool.py", line 771, in get
raise self._value
AttributeError: 'list' object has no attribute 'get_lock'
I have python3 version 3.8.3 on my personal machine and python3 version 3.7.4 on my work machine. Can anyone help me understand why I'm getting different behavior on these two environments? I'd be grateful, as this is meant to be software others might use on different machines.

PyTorch - RuntimeError: [enforce fail at inline_container.cc:209] . file not found: archive/data.pkl

Problem
I'm trying to load a file using PyTorch, but the error states archive/data.pkl does not exist.
Code
import torch
cachefile = 'cacheddata.pth'
torch.load(cachefile)
Output
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-4-8edf1f27a4bd> in <module>
1 import torch
2 cachefile = 'cacheddata.pth'
----> 3 torch.load(cachefile)
~/opt/anaconda3/envs/matching/lib/python3.8/site-packages/torch/serialization.py in load(f, map_location, pickle_module, **pickle_load_args)
582 opened_file.seek(orig_position)
583 return torch.jit.load(opened_file)
--> 584 return _load(opened_zipfile, map_location, pickle_module, **pickle_load_args)
585 return _legacy_load(opened_file, map_location, pickle_module, **pickle_load_args)
586
~/opt/anaconda3/envs/matching/lib/python3.8/site-packages/torch/serialization.py in _load(zip_file, map_location, pickle_module, **pickle_load_args)
837
838 # Load the data (which may in turn use `persistent_load` to load tensors)
--> 839 data_file = io.BytesIO(zip_file.get_record('data.pkl'))
840 unpickler = pickle_module.Unpickler(data_file, **pickle_load_args)
841 unpickler.persistent_load = persistent_load
RuntimeError: [enforce fail at inline_container.cc:209] . file not found: archive/data.pkl
Hypothesis
I'm guessing this has something to do with pickle, from the docs:
This save/load process uses the most intuitive syntax and involves the
least amount of code. Saving a model in this way will save the entire
module using Python’s pickle module. The disadvantage of this approach
is that the serialized data is bound to the specific classes and the
exact directory structure used when the model is saved. The reason for
this is because pickle does not save the model class itself. Rather,
it saves a path to the file containing the class, which is used during
load time. Because of this, your code can break in various ways when
used in other projects or after refactors.
Versions
PyTorch version: 1.6.0
Python version: 3.8.0
Turned out the file was somehow corrupted. After generating it again it loaded without issue.
I was facing the same problem. I downloaded directly the model (.pt) trained with GPU from a notebook on GCP AI Platform. When I loaded it on local by torch.load('models/model.pt', map_location=device), I got this error:
RuntimeError: [enforce fail at inline_container.cc:145] . PytorchStreamReader failed reading zip archive: failed finding central directory`.
I noticed that the size of the downloaded file is much smaller than expected. So same as #Ian, it turned out the file were corrupted when downloading from the notebook. Finally I had to transfer the file from the notebook into a bucket on Google Cloud Storage (GCS) at first instead of downloading it directly, then downloaded the file from GCS. It works now.
I encountered this issue not for a single file, but consistently on any file I was dealing with.
Looking at the file size, you could say they were corrupted, in the sense that they were too small and incomplete, but why were they always created that way?
I think the issue was that I had done a harmless modification to a simple class that I was saving. So like I made a class Foo, kept the data the same but added some method, then tried to save an older instance when I only had a newer class definition of Foo.
Here is an example of what I think happened, but it doesn't reproduce it exactly:
class Foo(object):
def __init__(self):
self.contents = [1,2,3]
torch.save(Foo(), "foo1.pth")
foo1 = torch.load("foo1.pth") # saved with class version 1 of Foo
# some days later the code looks like this
class Foo(object):
def __init__(self):
self.contents = [1,2,3]
def __len__(self):
return len(self.contents)
foo1 = torch.load("foo1.pth") # still works
torch.save(foo1, "foo2.pth") # try to save version 1 object where class is no longer known
The first time around I got an error like PicklingError: Can't pickle <class '__main__.Foo'>: it's not the same object as __main__.Foo, but when using Jupyter Notebook's autoreload feature it's hard to tell what exactly happened.
Normally older classes can be loaded into newer class definitions without problems.
In any case of what really happened, my solution was to load the old version and manually copy over the data fields into a freshly instantiated version of Foo, like such:
old = torch.load("foo1.pth")
new = Foo()
# new = old # this was the code that caused issues
new.contents = old.contents
torch.save(new, "foo2.pth")
In my case, the main reason for this error was the .pt file being corrupted. I started downloading the file when the file was still getting created.
So, in order to avoid the error, copy the .pt file in another directory and download the .pt file from that directory.
In my case, my disk drive was full.

Can't install trigger network automation tools

I read in the howto documentation to install Trigger, but when I test in python environment, I get the error below:
>>> from trigger.netdevices import NetDevices
>>> nd = NetDevices()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/trigger/netdevices/__init__.py", line 913, in __init__
with_acls=with_acls)
File "/usr/local/lib/python2.7/dist-packages/trigger/netdevices/__init__.py", line 767, in __init__
production_only=production_only, with_acls=with_acls)
File "/usr/local/lib/python2.7/dist-packages/trigger/netdevices/__init__.py", line 83, in _populate
# device_data = _munge_source_data(data_source=data_source)
File "/usr/local/lib/python2.7/dist-packages/trigger/netdevices/__init__.py", line 73, in _munge_source_data
# return loader.load_metadata(path, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/trigger/netdevices/loader.py", line 163, in load_metadata
raise RuntimeError('No data loaders succeeded. Tried: %r' % tried)
RuntimeError: No data loaders succeeded. Tried: [<trigger.netdevices.loaders.filesystem.XMLLoader object at 0x7f550a1ed350>, <trigger.netdevices.loaders.filesystem.JSONLoader object at 0x7f550a1ed210>, <trigger.netdevices.loaders.filesystem.SQLiteLoader object at 0x7f550a1ed250>, <trigger.netdevices.loaders.filesystem.CSVLoader object at 0x7f550a1ed290>, <trigger.netdevices.loaders.filesystem.RancidLoader object at 0x7f550a1ed550>]
Does anyone have some idea how to fix it?
The NetDevices constructor is apparently trying to find a "metadata source" that isn't there.
Firstly, you need to define the metadata. Second, your code should handle the exception where none is found.
I'm the lead developer of Trigger. Check out the the doc Working with NetDevices. It is probably what you were missing. We've done some work recently to improve the quality of the setup/install docs, and I hope that this is more clear now!
If you want to get started super quickly, you can feed Trigger a CSV-formatted NetDevices file, like so:
test1-abc.net.example.com,juniper
test2-abc.net.example.com,cisco
Just put that in a file, e.g. /tmp/netdevices.csv and then set the NETDEVICES_SOURCE environment variable:
export NETDEVICES_SOURCE=/tmp/netdevices.csv
And then fire up python and continue on with your examples and you should be good to go!
I found that the default of /etc/trigger/netdevices.xml wasn't listed in the setup instructions. It did indicate to copy from the trigger source folder:
cp conf/netdevices.json /etc/trigger/netdevices.json
But, I didn't see how to specify this instead of the default NETDEVICES_SOURCE on the installation page. But, as soon as I had a file that NETDEVICES_SOURCE pointed to in my /etc/trigger folder, it worked.
I recommend this to get the verifying functionality examples to work right away with minimal fuss:
cp conf/netdevices.xml /etc/trigger/netdevices.xml
Using Ubuntu 14.04 with Python 2.7.3

Threaded Sessions expiring on SQLAlchemy?

This is difficult to describe or show much code for, but I'll try. Essentially I have a multi-threaded desktop app that will frequently handle the adding/removing/changing of tables in threads. From what I read, I should use scoped_session and pass that around to the various threads to do the work (I think?). Here're some basic code examples:
class SQL():
def __init__(self):
self.db = create_engine('mysql+mysqldb://thesqlserver')
self.metadata = MetaData(self.db)
self.SessionObj = scoped_session(sessionmaker(bind=self.db, autoflush=True))
db = SQL()
session = db.SessionObj()
someObj = Obj(val, val2)
session.add(someObj)
session.commit()
The above class is what I'm using as the general access of SQL stuff. After creating a new session, performing a query and update/add to it, upon the session.commit(), I get the following error:
Traceback (most recent call last):
File "core\taskHandler.pyc", line 42, in run
File "core\taskHandler.pyc", line 184, in addTasks
File "core\sqlHandler.pyc", line 35, in commit
File "sqlalchemy\orm\session.pyc", line 624, in rollback
File "sqlalchemy\orm\session.pyc", line 338, in rollback
File "sqlalchemy\orm\session.pyc", line 369, in _rollback_impl
File "sqlalchemy\orm\session.pyc", line 239, in _restore_snapshot
File "sqlalchemy\orm\state.pyc", line 252, in expire
AttributeError: 'NoneType' object has no attribute 'expire'
Then the next if another sql attempt goes through:
Traceback (most recent call last):
File "core\taskHandler.pyc", line 44, in run
File "core\taskHandler.pyc", line 196, in deleteTasks
File "sqlalchemy\orm\query.pyc", line 2164, in scalar
File "sqlalchemy\orm\query.pyc", line 2133, in one
File "sqlalchemy\orm\query.pyc", line 2176, in __iter__
File "sqlalchemy\orm\query.pyc", line 2189, in _execute_and_instances
File "sqlalchemy\orm\query.pyc", line 2180, in _connection_from_session
File "sqlalchemy\orm\session.pyc", line 729, in connection
File "sqlalchemy\orm\session.pyc", line 733, in _connection_for_bind
File "sqlalchemy\orm\session.pyc", line 249, in _connection_for_bind
File "sqlalchemy\orm\session.pyc", line 177, in _assert_is_active
sqlalchemy.exc.InvalidRequestError: This Session's transaction has been rolled back by a nested rollback() call. To begin a new transaction, issue Session.rollback() first.
That's about as much as I know and I think the best I can describe. Any ideas on what I'm supposed to be doing here? It's all mud to me. Thanks in advance!
The funny part is, you missed the most critical part of the answer you "ripped the code from", which is that there is a Python function in the middle, which is executing some abstract operation (it's labeled as func()). That code illustrates a transactional wrapper for a function, and in the above example you instead have an object method called commit() that isn't otherwise calling upon any additional operations with the Session.
Here you have kind of a session-holding object called SQL() that is not really adding any usefulness to your program and makes it needlessly complicated, and is probably also the source of the issue. Unless your application intends to connect to many different databases at different times, and use SQL() objects to represent that state, there's not much use in building a class called "SQL" that has an "engine" stuck onto it. Just stick the engine in a module somewhere, as well as your scoped_session().
The engine and scoped_session represent a pattern called the factory pattern - they are objects that create some other useful object, in this case scoped_session creates a Session, and the Engine is used internally by the Session to create a Connection with which to talk to the database. It doesn't make much sense to place the Session object as a sibling member along with Engine and scoped_session - you'd be carrying around either the factories (the Engine and scoped_session), or the object itself that they create (the Session), which all depends on what you're trying to do.
The Session itself, remember here we're talking about the thing the factories create (Session), not the factories themselves (Engine and scoped_session), is not in the least bit thread safe. It is something you usually create only local to a function - it shouldn't be global, and if you're in fact using a single SQL() object across threads that's probably the problem here. The actual error you're getting, I'm not really sure what that is and I could only have a better clue if I knew the exact version of SQLAlchemy in use here, though the randomness of the error suggests that you have some kind of threading issue where something is becoming None in one thread as another expects that same object to be present.
So what you need to establish in this program is when exactly a particular thread of execution begins, what it needs to do with the database as it proceeds, and then when it ends. When you can establish a consistent pattern for that, you would then link a single Session to this thread, which goes for the lifespan of that thread, and is never shared. All the objects which are produced by this session must also not be shared to other threads - they are extensions of the Session's state. If you have "worker threads" in use, those worker threads should load up their own data as needed, within their own Session. The Session represents a live database transaction and you generally want transactions local to a single thread.
As this is not a web application you might want to forego the usage of scoped_session, unless you do in fact have a place for a thread-local pattern to be used.

Categories