Failing hard at OOP in python - python

This represents a simple class, that I have made to try and practice OOP.
import csv
import logging
class LoaderCSV:
def __init__(self, file):
self.file = file
if file is None:
logging.warning('Missing input file.')
def load(self):
with open(self.file) as f:
holder = csv.reader(f)
file_data = list(holder)
return file_data
What happens is when I call this class with:
data = LoaderCSV.load(input_file)
I get
line 14, in load
with open(self.file) as f:
AttributeError: 'str' object has no attribute 'file'
I must be messing something up, but can't understand what. My previous attempt worked just fine this way. I just don't understand why
self.file
does not pass the value, assigned to the argument, when it is defined under __init__

The problem is you're calling an instance method as a static method, so your filename is being passed in instead of self. The proper way to do this would be like:
loader = LoaderCSV(input_file)
data = loader.load()
This will pass in loader as the self parameter, allowing you to access the file name in the object's file field.
Check out the Python documentation on classes for more information.

You need to create the LoaderCSV object first, then call the load method on that object.
loader = LoaderCSV(input_file)
data = loader.load()

The way to use the instance method load is to make an instance of your class, and then call the method on that class. Like this:
myloader = LoaderCSV(input_file)
data = myloader.load()
or succinctly:
data = LoaderCSV(input_file).load()

Related

Reading a file inside a class within an __init__ function does not work

I am trying to read a file line-by-line in python using open(). Below is a small snippet(Snippet - 1) that works, but when put the same working logic inside a class and inside a __init__() function, the same function stops working and generates no output but also no error message, just finishes the execution with exit code 0.
Can you please help in identifying the issue with Snippet-2? I am assuming that open() does not like to be called from __init__(). Thanks in advance.
#Snippet - 1
f = open("file.txt", 'r')
for line in f:
print(line)
#Snippet - 2
class InitProcess:
def __init__(self):
self.count = 0
filepath = "file.txt"
try:
self.fd = open(filepath)
for line in self.fd:
print(line)
finally:
self.fd.close()
The code inside __init__() gets executed when you create a class instance (i.e., an object of the class). Try creating an object of the class like:
test_process = InitProcess()
Your code will get executed as soon as this line gets executed.

How can I use callback method in Overwrite storage class for django save method?

I want invoke a callback method once I try to call save mthod of my overwrite method, but is doesn't seem to work.
below is my code.
class OverwriteStorage(Storage):
def save(self, name, content, max_length=None, callback=None):
"""
Save new content to the file specified by name. The content should be
a proper File object or any Python file-like object, ready to be read
from the beginning.
This method is modified to take care of callbacks for S3 storage class of amazon.
So that user specific callback can be accommodated.
:param name: name of the file.
:param content: content of the file
:param max_length: max length of the file.
:param callback: callback method.
:return:
"""
# Get the proper name for the file, as it will actually be saved.
if name is None:
name = content.name
if not hasattr(content, 'chunks'):
content = File(content, name)
name = self.get_available_name(name, max_length=max_length)
return self._save(name, content, callback=callback)
but when I am trying to call this:
file.file_location.save(name_of_the_file, File(open(str(name_of_the_file), 'r')),callback=ProgressPercentageUpload(name_of_the_file, size_of_the_file))
It throws below error:
TypeError: save() got an unexpected keyword argument 'callback'
Is there anything I am doing wrong?
Thanks for the help.

Accessing variable outside class using inheritance

I am trying to inherit a variable from base class but the interpreter throws an error.
Here is my code:
class LibAccess(object):
def __init__(self,url):
self.url = url
def url_lib(self):
self.urllib_data = urllib.request.urlopen(self.url).read()
return self.urllib_data
class Spidering(LibAccess):
def category1(self):
print (self.urllib_data)
scrap = Spidering("http://jabong.com")
scrap.category1()
This is the output:
Traceback (most recent call last):
File "variable_concat.py", line 16, in <module>
scrap.category1()
File "variable_concat.py", line 12, in category1
print (self.urllib_data)
AttributeError: 'Spidering' object has no attribute 'urllib_data'
What is the problem with the code?
You will need to define self.urllib_data prior to accessing it. The simples way would be to create it during initialization, e.g.
class LibAccess(object):
def __init__(self,url):
self.url = url
self.urllib_data = None
That way you can make sure it exists everytime you try to access it. From your code I take it that you do not want to obtain the actual data during initialization. Alternatively, you could call self.url_lib() from __init__(..) to read the data for the first time. Updating it later on would be done in the same way as before.

pickle load error "__init__() takes exactly 2 arguments (1 given)"

My issue is that a custom class has been saved with pickle.dump, since these files were saved the custom class has been changed and now when I use pickle.load I am getting this error. Is it a problem with the saved file?
The error:
File "/cprprod/extern/lib/python2.7/pickle.py", line 1378, in load
return Unpickler(file).load()
File "/cprprod/extern/lib/python2.7/pickle.py", line 858, in load
dispatch[key](self)
file "/cprprod/extern/lib/python2.7/pickle.py", line 1070, in load_inst
self._instantiate(klass, self.marker())
File "/cprprod/extern/lib/python2.7/pickle.py", line 1060, in _instantiate
value = klass(*args)
Is there anything I can do to load the file?
The code
file = open(filename,'rb')
obj = pickle.load(file)
will give me the error.
Here is some minimal code which can reproduce the error:
import pickle
class foo:
def __init__(self,a):
self.a = a
def __str__(self):
return str(self.a)
obj = foo(1)
with open('junk','wb') as f:
pickle.dump(obj,f)
class foo:
def __init__(self,a,b):
self.a = a
self.b = b
def __str__(self):
return '%s %s'%(self.a,self.b)
def __getinitargs__(self):
return (self.a,self.b)
with open('junk','rb') as f:
obj = pickle.load(f)
print str(obj)
Given the contrived code that I posted on your behalf in the question, we can "fix" this error as:
with open('junk','rb') as f:
try:
obj = pickle.load(f)
except Exception as e:
print e
position = f.tell()
a = foo.__getinitargs__
del foo.__getinitargs__
f.seek(position)
obj = pickle.load(f)
foo.__getinitargs__ = a
print str(obj)
Now we see that the instance has been unpickled and no longer has attribute b.
If you added __getinitargs__() then it is up to you to make sure your new class can handle the arguments passed to __init__(). Old data that doesn't have the __getinitargs__ data will still lead to __init__ to be called but with no arguments.
Make the arguments to __init__ optional via keyword arguments:
def __init__(self, otherarg=None):
if otherarg is None:
# created from an old-revision pickle. Handle separately.
# The pickle will be loaded *normally* and data will still be set normally
return
self.otherarg = otherarg
When loading the old-style pickle, the data for these classes will still be restored. You can use __setstate__() to transform the internal state as needed.
Alternatively, temporarily remove the __getinitargs__ method from the class:
initargs = foo.__getinitargs__.__func__
del foo.__getinitargs__
obj = pickle.load(f)
foo.__getinitargs__ = initargs
and re-dump your pickles from the now-loaded objects with __getinitargs__ reinstated.
I've tested both methods and in both cases the old data is loaded correctly and you can then dump your objects again to a new pickle file with __getinitargs__ just fine.
You might want to modify the custom class to optionally require a second parameter. This would keep back award compatibility with your pickled objects.

AppEngine -> "AttributeError: 'unicode' object has no attribute 'has_key'" when using blobstore

There have been a number of other questions on AttributeErrors here, but I've read through them and am still not sure what's causing the type mismatch in my specific case.
Thanks in advance for any thoughts on this.
My model:
class Object(db.Model):
notes = db.StringProperty(multiline=False)
other_item = db.ReferenceProperty(Other)
time = db.DateTimeProperty(auto_now_add=True)
new_files = blobstore.BlobReferenceProperty(required=True)
email = db.EmailProperty()
is_purple = db.BooleanProperty()
My BlobstoreUploadHandler:
class FormUploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
try:
note = self.request.get('notes')
email_addr = self.request.get('email')
o = self.request.get('other')
upload_file = self.get_uploads()[0]
# Save the object record
new_object = Object(notes=note,
other=o,
email=email_addr,
is_purple=False,
new_files=upload_file.key())
db.put(new_object)
# Redirect to let user know everything's peachy.
self.redirect('/upload_success.html')
except:
self.redirect('/upload_failure.html')
And every time I submit the form that uploads the file, it throws the following exception:
ERROR 2010-10-30 21:31:01,045 __init__.py:391] 'unicode' object has no attribute 'has_key'
Traceback (most recent call last):
File "/home/user/Public/dir/google_appengine/google/appengine/ext/webapp/__init__.py", line 513, in __call__
handler.post(*groups)
File "/home/user/Public/dir/myapp/myapp.py", line 187, in post
new_files=upload_file.key())
File "/home/user/Public/dir/google_appengine/google/appengine/ext/db/__init__.py", line 813, in __init__
prop.__set__(self, value)
File "/home/user/Public/dir/google_appengine/google/appengine/ext/db/__init__.py", line 3216, in __set__
value = self.validate(value)
File "/home/user/Public/dir/google_appengine/google/appengine/ext/db/__init__.py", line 3246, in validate
if value is not None and not value.has_key():
AttributeError: 'unicode' object has no attribute 'has_key'
What perplexes me most is that this code is nearly straight out of the documentation, and jives with other examples of blob upload handler's I've found online in tutorials as well.
I've run --clear-datastore to ensure that any changes I've made to the DB schema aren't causing problems, and have tried casting upload_file as all sorts of things to see if it would appease Python - any ideas on what I've screwed up?
Edit: I've found a workaround, but it's suboptimal.
Altering the UploadHandler to this instead resolves the issue:
...
# Save the object record
new_object = Object()
new_object.notes = note
new_object.other = o
new_object.email = email.addr
new_object.is_purple = False
new_object.new_files = upload_file.key()
db.put(new_object)
...
I made this switch after noticing that commenting out the files line threw the same issues for the other line, and so on. This isn't an optimal solution, though, as I can't enforce validation this way (in the model, if I set anything as required, I can't declare an empty entity like above without throwing an exception).
Any thoughts on why I can't declare the entity and populate it at the same time?
You're passing in o as the value of other_item (in your sample code, you call it other, but I presume that's a typo). o is a string fetched from the request, though, and the model definition specifies that it's a ReferenceProperty, so it should either be an instance of the Other class, or a db.Key object.
If o is supposed to be a stringified key, pass in db.Key(o) instead, to deserialize it.
Object is a really terrible name for a datastore class (or any class, really), by the way - the Python base object is called object, and that's only one capitalized letter away - very easy to mistake.
has_key error is due to the ReferenceProperty other_items. You are most likely passing in '' for other_items when appengine's api expects a dict. In order to get around this, you need to convert other_items to hash.
[caveat lector: I know zilch about "google_app_engine"]
The message indicates that it is expecting a dict (the only known object that has a has_key attribute) or a work-alike object, not the unicode object that you supplied. Perhaps you should be passing upload_file, not upload_file.key() ...

Categories