I'm getting a syntax error trying to make a Federated Table Builder.
Here's the offended interpreter:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "federatedTableBuilder.py", line 7, in <module>
local_public_files.generate()
File "localViewDefinition.py", line 22, in generate
self.generate_for_host(conn)
File "localViewDefinition.py", line 17, in generate_for_host
self.conn.doQuery(rsaconn,self.query)
TypeError: doQuery() takes exactly 2 arguments (3 given)
and the offending code:
import mysql as sql
from connector import Connector
import io
import traceback
class LocalViewDefinition:
...insert variables...
def doQuery(connection, query):
try:
cursor = MySQLdb.cursors.Cursor(connection)
cursor.execute(query)
except: #figure out how to handle generic and sql errors separately
traceback.print_exc()
Do you have any idea about the cause?
For class methods, Python takes an additional first argument to refer to the instance of the class. The convention is to use the word self:
def doQuery(self, connection, query):
try:
cursor = MySQLdb.cursors.Cursor(connection)
cursor.execute(query)
except: #figure out how to handle generic and sql errors separately
traceback.print_exc()
This requirement to refer to the instance of the class is because "explicit is better than implicit" in Python (cf. import this).
The other answers have already covered the fact that your instance method needs to have self1 as the first argument. However, it is worth noting that an instance method which doesn't use self maybe shouldn't be an instance method at all ...
class Example(object):
def instance_method(self):
print "I need self: %s" % self
#staticmethod
def static_method():
print "I don't need self."
#classmethod
def class_method(cls):
print "I use the class, not the instance: %s" % cls
Example.static_method() # I don't need self.
Example.class_method() # I use the class, not the instance: ...
e = Example()
e.instance_method() # I need self: ...
# can call staticmethods and classmethods from an instance as well:
e.static_method() # I don't need self.
As a final word, staticmethods in particular aren't generally super useful. Most of the time, a module level function without a class will due just fine.
1The name "self" is just convention -- You could use any name you like, but I wouldn't suggest it
You need to add another argument - name it "self" - in the method definition.
def doQuery(self, connection, query)
add self to def doQuery(connection, query)
def doQuery(self, connection, query):
that is the python class object reference.
Related
I saw a code snippet in Python 3.6.5 that can be replicated with this simplified example below and I do not understand if this is something concerning or not. I am surprised it works honestly...
class Foo:
def bar(numb):
return numb
A1 = bar(1)
print(Foo)
print(Foo.A1)
print(Foo.bar(17))
In all python guides that I have seen, self appears as the first argument for all the purposes we know and love. When it is not, the methods are decorated with a static decorator and all is well. This case works as it is, however. If I were to use the static decorator on bar, I get a TypeError when setting A1:
Traceback (most recent call last):
File "/home/user/dir/understanding_classes.py", line 1, in <module>
class Foo:
File "/home/user/dir/understanding_classes.py", line 7, in Foo
A1 = bar(1)
TypeError: 'staticmethod' object is not callable
Is this something that is OK keeping in the code or is this a potential problem? I hope the question is not too broad, but how and why does this work?
The first parameter of the method will be set to the receiver. We call it self by convention, but self isn't a keyword; any valid parameter name would work just as well.
There's two different ways to invoke a method that are relevant here. Let's say we have a simple Person class with a name and a say_hi method
class Person:
def __init__(self, name):
self.name = name
def say_hi(self):
print(f'Hi my name is {self.name}')
p = Person('J.K.')
If we call the method on p, we'll get a call to say_hi with self=p
p.say_hi() # self=p, prints 'Hi my name is J.K.'
What you're doing in your example is calling the method via the class, and passing that first argument explicitly. The equivalent call here would be
Person.say_hi(p) # explicit self=p, also prints 'Hi my name is J.K.'
In your example you're using a non-static method then calling it through the class, then explicitly passing the first parameter. It happens to work but it doesn't make a lot of sense because you should be able to invoke a non-static method by saying
f = Foo()
f.bar() # numb = f, works, but numb isn't a number it's a Foo
If you want to put a function inside of a class that doesn't have a receiver, that's when you want to use #staticmethod (or, #classmethod more often)
class Person:
def __init__(self, name):
self.name = name
def say_hi(self):
print(f'Hi my name is {self.name}')
#staticmethod
def say_hello():
print('hello')
p = Person('J.K.')
Person.say_hello()
p.say_hello()
I am very new to python : I want to serialize and deserialize my custom object in python. Please guide me on the same. I have a sample class :
import pickle
import json
class MyClass():
variable = "blah"
num = 10
def function(self):
print("this is a message inside the class.")
def get_variable():
return variable
def get_num():
return num
def main():
myObj = MyClass()
with open('/opt/infi/deeMyObj.txt', 'w') as output:
pickle.dump(myObj, output,pickle.HIGHEST_PROTOCOL)
with open('/opt/infi/deeMyObj.txt', 'r') as input:
myObjread = pickle.load(input)
print myObjread.get_variable()
print myObjread.get_num()
main()
I am getting following error :
Traceback (most recent call last):
File "sample.py", line 30, in
main()
File "sample.py", line 27, in main
print myObjread.get_variable()
TypeError: get_variable() takes no arguments (1 given)
Main intention is to read the object back.
To expand on jasonharper's comment, your get_variable and get_num methods aren't referring to the class's member variables. They should take the object as their first argument, e.g.
class MyClass:
...
def get_variable(self):
return self.variable
I think your serialization code is OK, but I might be wrong.
(Aside)
This is a bit off-topic, but another thing to note: when you define variables directly within the class block, they're defined on the class, not on objects of that class. That happens to work out in this case, since Python will look for a class-level variable of the same name if it can't find one on the object. However, if you store, say, a list in one of them and start modifying it, you'd end up sharing it between objects, which is probably not what you want. Instead you want to define them on in an __init__ method:
class MyClass:
def __init__(self):
self.variable = "blah"
So I've looked around and read many postings covering the TypeError: message, where it "takes exactly X arguments but only 1 is given".
I know about self. I don't think I have an issue understanding self. Regardless, I was trying to to create a class with some properties and as long as I have #property in front of my function hwaddr, I get the following error:
Traceback (most recent call last):
File line 24, in <module>
db.hwaddr("aaa", "bbbb")
TypeError: hwaddr() takes exactly 3 arguments (1 given)
Here is the code. Why is #property messing me up? I take it out, and the code works as expected:
#!/usr/bin/env python2.7
class Database:
"""An instance of our Mongo systems database"""
#classmethod
def __init__(self):
pass
#property
def hwaddr(self, host, interface):
results = [ host, interface ]
return results
db = Database()
print db.hwaddr("aaa", "bbbb"
Process finished with exit code 1
With it gone, the output is:
File
['aaa', 'bbbb']
Process finished with exit code 0
Properties are used as syntactical sugar getters. So they expect that you only pass self. It would basically shorten:
print db.hwaddr()
to:
print db.hwaddr
There is no need to use a property here as you pass two arguments in.
Basically, what Dair said: properties don't take parameters, that's what methods are for.
Typically, you will want to use properties in the following scenarios:
To provide read-only access to an internal attribute
To implement a calculated field
To provide read/write access to an attribute, but control what happens when it is set
So the question would be, what does hwaddr do, and does it match any of those use cases? And what exactly are host and interface? What I think you want to do is this:
#!/usr/bin/env python2.7
class Database:
"""An instance of our Mongo systems database"""
def __init__(self, host, interface):
self._host = host
self._interface = interface
#property
def host(self):
return self._host
#property
def interface(self):
return self._interface
#property
def hwaddr(self):
return self._host, self._interface
db = Database("my_host", "my_interface")
print db.host
print db.interface
print db.hwaddr
Here, your Database class will have host and interface read-only properties, that can only be set when instantiating the class. A third property, hwaddr, will produce a tuple with the database full address, which may be convenient in some cases.
Also, note that I removed the classmethod decorator in init; constructors should be instance methods.
Below is just example code that provides the error I am hoping to get help on fixing, or getting an understanding of a better way to write this. I have a mysql "super" class called mysql_connection. In this class, the connection to the database is made. I also have a few methods within it. One that simply runs "select version()" to show that the connection/query works. I then have a "chktable" method which in this example instantiates a new subclass called "table" which inherits the super class. After instantiating the class, I then call a method within the subclass which attempts to use the the query method in the superclass to run "show tables like 'tbl name'". This is where I get an error.
import mysql.connector
from mysql.connector import errorcode
from mysql.connector.cursor import MySQLCursor
class mysql_connection(object):
def __init__(self, **kwargs):
self.connection_options = {}
self.connection_options['user'] = 'root'
self.connection_options['password'] = ''
self.connection_options['host'] = '192.168.33.10'
self.connection_options['port'] = '3306'
self.connection_options['database'] = "test"
self.connection_options['raise_on_warnings'] = True
self.connect()
def connect(self):
try:
self.cnx = mysql.connector.connect(**self.connection_options)
except mysql.connector.Error as err:
if err.errno == errorcode.ER_ACCESS_DENIED_ERROR:
print "Something is wrong with your user name or password"
elif err.errno == errorcode.ER_BAD_DB_ERROR:
print "Database does not exists"
else:
print err
def query(self, statement, data=''):
cursor = MySQLCursor(self.cnx)
cursor.execute(statement)
result = cursor.fetchall()
cursor.close
return result
def get_version(self):
print self.query("select version()")
def chktable(self, tb_name):
tab = table(name=tb_name)
tab.check_table()
class table(mysql_connection):
def __init__(self, **kwargs):
self.name = kwargs['name']
def check_table(self):
return super(table, self).query("show tables like '{}".format(self.name))
conn = mysql_connection()
conn.get_version()
conn.chktable("test")
The error that I get is:
$ python example.py
[(u'5.1.73',)]
Traceback (most recent call last):
File "example.py", line 50, in <module>
conn.chktable("test")
File "example.py", line 39, in chktable
tab.check_table()
File "example.py", line 46, in check_table
return super(table, self).query("show tables like '{}".format(self.name))
File "example.py", line 28, in query
cursor = MySQLCursor(self.cnx)
AttributeError: 'table' object has no attribute 'cnx'
I don't fully understand calling back to the super class and how it works with subclasses, so that is likely my issue. I'd also like to know if there is maybe a better way to accomplish this. I was thinking I could get rid of the subclass altogether, but I like the subclass I made so I feel there should be a way around it. A secondary thing I could try would be to put the subclass inside the master class, but I don't think that is correct.
As Jon points out, this is not an appropriate use of inheritance. That is for "is-a" relationships: ie Dog inherits from Animal, because a dog is an animal. But a table is not a connection: a table might use a connection, but that simply means you should assign an instance of the connection to an instance variable in table.
Also, in an inheritance relationship there is usually no good reason for a superclass to know about its subclasses, as you have in the chktable method.
(The actual bug you're seeing is because you haven't called the superclass method in table's __init__, but it's better to fix your structure.)
Trying to mock out calls to pyazure library for django testing, but I can't figure out how to mock out the PyAzure class constructor so that it doesn't cause a TypeError. Is there a better way to approach mocking out an access library that generates a connection object?
Anything I've tried other than None generates a TypeError, which means I can't really even begin to test any of the PyAzure connection methods with actual return values. What is the best way to replace a working class with a fake class using mock?
Test Error:
======================================================================
ERROR: test_management_certificate_connect (azure_cloud.tests.ViewsTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/bschott/Source/django-nimbis/apps/azure_cloud/tests.py", line 107, in test_management_certificate_connect
self.cert1.connect()
File "/Users/bschott/Source/django-nimbis/apps/azure_cloud/models.py", line 242, in connect
subscription_id=self.subscription.subscription_id)
TypeError: __init__() should return None, not 'FakeAzure'
----------------------------------------------------------------------
tests.py:
class ViewsTest(TestCase):
def setUp(self):
...
self.cert1 = ManagementCertificate.objects.create(
name="cert1",
subscription=self.subscription1,
management_cert=File(open(__file__), "cert1.pem"),
owner=self.user1)
...
class FakeAzure(object):
""" testing class for azure """
def list_services(self):
return ['service1', 'service2', 'service3']
def list_storages(self):
return ['storage1', 'storage2', 'storage3']
#mock.patch.object(pyazure.PyAzure, '__init__')
def test_management_certificate_connect(self, mock_pyazure_init):
mock_pyazure_init.return_value = self.FakeAzure()
self.cert1.connect()
assert mock_pyazure_init.called
models.py
class ManagementCertificate(models.Model):
# support connection caching to azure
_cached_connection = None
def connect(self):
"""
Connect to the management interface using these credentials.
"""
if not self._cached_connection:
self._cached_connection = pyazure.PyAzure(
management_cert_path=self.management_cert.path,
subscription_id=self.subscription.subscription_id)
logging.debug(self._cached_connection)
return self._cached_connection
You seem to have a misconception about what __init__() does. Its purpose is to initialise an instance that was already created earlier. The first argument to __init__() is self, which is the instance, so you can see it was already allocated when __init__() is called.
There is a method __new__() that is called before __init__() to create the actual instance. I think it would be much easier, though, to replace the whole class by a mock class, instead of mocking single methods.