Python: Compound functions inside class - python

I am trying to replicate something similar to model queries in Django.
# database.py
class ModelFactory(object):
def __init__(self, table):
self.table = table
def fields(self, *args):
str_columns = ''
for count, arg in enumerate(args):
if count == 0:
str_columns += arg
else:
str_columns += ', %s' % arg
self.str_columns = str_columns
def wheres(self, **kwargs):
str_wheres = ''
for count, (key, value) in enumerate(kwargs.items()):
if count == 0:
str_wheres += 'WHERE %s = %s' % (key, value)
else:
str_wheres += ' AND %s = %s' % (key, value)
self.str_wheres = str_wheres
My idea is to use it as follows:
from database import ModelFactory
myInstance = ModelFactory('myTable')
myQuery = myInstance.fields('column1', 'column2').wheres(column1 = 5)
I am not sure if I need a new class or function inside ModelFactory class that would take the results from 'fields' and 'wheres' to compile a SQL string to query? Like the following line:
cur.execute('SELECT column1, column2 from myTable WHERE column1 = 5')
I am also not sure if calling class.function1.function2 is correct? Django has the 'objects' word, e.g. Instance.objects.filter().exclude()
I have tried to change the code base as follows:
# database.py
class ModelFactory(object):
def __init__(self, table):
self.table = table
def objects(self):
def fields(self, **kwargs):
return self.f(**kwargs)
def wheres(self, *args):
return self.w(*args)
def f(self, *args):
str_columns = ''
for count, arg in enumerate(args):
if count == 0:
str_columns += arg
else:
str_columns += ', %s' % arg
self.str_columns = str_columns
def w(self, **kwargs):
str_wheres = ''
for count, (key, value) in enumerate(kwargs.items()):
if count == 0:
str_wheres += 'WHERE %s = %s' % (key, value)
else:
str_wheres += ' AND %s = %s' % (key, value)
self.str_wheres = str_wheres
But when I try the following:
from database import ModelFactory
myInstance = ModelFactory('myTable')
myQuery = myInstance.objects.fields('column1', 'column2').wheres(column1 = 5)
I get an AttributeError: 'function' object has no attribute 'fields'

If you want to chain object's method calls, you need to return that object from method. i.e. add return self to your methods.
So your class declaration probably should be something like the following:
class ModelFactory(object):
def __init__(self, table):
self.table = table
def fields(self, *args):
self.str_columns = ', '.join(args)
return self
def wheres(self, **kwargs):
str_wheres = ' AND '.join('{} = {}'.format(k, v) for k, v in kwargs.items())
self.str_wheres = 'WHERE {}'.format(str_wheres)
return self
def execute(self):
// ATTN! This code is prone to SQL injection. Do not use!
cur.execute('SELECT {columns} FROM {table} {wheres}'.format(columns=self.str_columns, table=self.table, wheres=self.wheres))

The problem is that you still have objects as a function:
def objects(self):
Currently, this means that you'll need to call it as a function - your myQuery line would need to look something like:
myQuery = myInstance.objects().fields(...
However, that still wouldn't be enough because fields and wheres are both only scoped within the objects function.
If you want to push down this route, then you will need to create a class that you instantiate inside your model under the attribute objects - Django uses QuerySet for this. If you check out the source you'll see how much magic is required to make something "simple" like objects work.
So a simple alternative?
You will have to make a new class similar to QuerySet which can provide the fields and wheres chainable functions - let's call it WernerfeuerSet:
class WernerfeuerSet:
def __init__(self, table):
self.table = table
def fields(self, **kwargs):
pass
def wheres(self, **kwargs):
pass
And now instantiate that within your ModelFactory - something like:
class ModelFactory:
def __init__(self, table):
self.objects = WernerfeuerSet(table)
Now your original query should be possible because objects is an attribute of the ModelFactory, rather than a function:
myQuery = myInstance.objects.fields('column1', 'column2').wheres(column1 = 5)

Related

Objects passing objects

I'm new to python and am currently trying to use an old module to output graphs. The code below is a excerpt from the module that uses rpy to design
standard celeration charts (don't look it up).
I'm having trouble understanding how the class Element and class Vector work together.
I've been trying to pass the a element object to the vector get_elements but I'm not sure if that's what I should be doing.
Any help would be appreciated. Thanks!
class Element(object):
"""Base class for Chartshare vector elements."""
def __init__(self, offset=0, value=0):
self.offset=offset
self.value=value
self.text=''
def setText(self, value):
self.value=value
def getText(self):
return self.value
text = property(getText, setText)
class Vector(object):
"""Base class for Chartshare Vectors."""
def __init__(self, name='', color='black', linetype='o', symbol=1, clutter=0, start=0, end=140, continuous=False, debug=False):
self.name=name
self.color=color
self.linetype=linetype
self.symbol=symbol
self.start=start
self.end=end
self.elements={}
self.debug=debug
self.continuous=continuous
if not self.continuous:
for i in range(self.start, self.end+1):
self.elements[i]='NaN'
def getSymbol(self):
return self._symbol
def setSymbol(self, value):
if (type(value) == int):
if (value >= 0) and (value <= 18):
self._symbol = value
else:
raise SymbolOutOfRange, "Symbol should be an integer between 0 and 18."
elif (type(value) == str):
try:
self._symbol = value[0]
except IndexError:
self._symbol=1
else:
self._symbol = 1
symbol = property(getSymbol, setSymbol)
def getLinetype(self):
return self._linetype
def setLinetype(self, value):
if (value == 'p') or (value == 'o') or (value == 'l'):
self._linetype = value
else:
raise InvalidLinetype, "Line type should be 'o', 'p', or 'l'"
linetype = property(getLinetype, setLinetype)
def get_elements(self):
"""Returns a list with the elements of a Vector."""
retval = []
for i in range(self.start, self.end+1):
if (not self.continuous):
retval.append(self.elements[i])
else:
if (self.elements[i] != 'NaN'):
retval.append(self.elements[i])
return retval
def get_offsets(self):
"""Returns a list of the offsets of a Vector."""
retval = []
for i in range(self.start, self.end+1):
if (not self.continuous):
retval.append(i)
else:
if (self.elements[i] == 'NaN'):
retval.append(i)
return retval
def to_xml(self, container=False):
"""Returns an xml representation of the Vector."""
if (container == False):
container = StringIO.StringIO()
xml = XMLGenerator(container)
attrs = {}
attrs[u'name'] = u"%s" % self.name
attrs[u'symbol'] = u"%s" % self.symbol
attrs[u'linetype'] = u"%s" % self.linetype
attrs[u'color'] = u"%s" % self.color
xml.startElement(u'vector', attrs)
for i in range(self.start, self.end+1):
if (self.elements[i] != 'NaN'):
attrs.clear()
attrs[u'offset'] = u"%s" % i
xml.startElement(u'element', attrs)
xml.characters(u"%s" % self.elements[i])
xml.endElement(u'element')
xml.endElement(u'vector')
def render(self):
"""Plots the current vector."""
if (self.debug):
print "Rendering Vector: %s" % self.name
print self.elements
r.points(x=range(self.start, self.end+1),
y=self.elements,
col=self.color,
type=self.linetype,
pch=self.symbol)
if (self.debug):
print "Finished rendering Vector: %s" % self.name
Vector's get_elements() doesn't take any arguments. Well, technically it does. It takes self. self is syntactic sugar that lets you do this:
vec = Vector()
vec.get_elements()
It's equivalent to this:
vec = Vector()
Vector.get_elements(vec)
Since get_elements() doesn't take any arguments, you can't pass a to it. Skimming the code, I don't see a set_elements() analog. This means you'll have to modify the vector's element's dictionary directly.
vec = Vector()
vec.elements[a] = ...
print(vec.get_elements()) # >>> [a,...]
As I can see, there is no place in this code where you are assigning self.elements with any input from a function. You are only initialising it or obtaining values
Also note that the .get_elements() function doesn't have any arguments (only self, that is the object where you are calling it in), so of course it won't work.
Unless you can do something such as the following, we would need more code to understand how to manipulate and connect these two objects.
element_obj = Element()
vector_obj = Vector()
position = 4
vector_obj.elements[4] = element_obj
I got to this answer with the following: as I can see, the elements property in the Vector class is a dictonary, that when you call vector_obj.get_elements() is casted to an array using the start and end parameters as delimiters.
Unless there is something else missing, this would be the only way I could think out of adding the an element into a vector object. Otheriwse, we would need some more code or context to understand how these classes behave with each other!
Hope it helps!

flask-sqlalchemy filter using text array

I'm trying to filter my flask-sqlalchemy query via strings. My procedure for creating the string results in the following array:
["user.name == 'Sid'", "user.role == 'admin'"]
It gets formed with something like this:
for i in myarray:
filter_string = "%s.%s == '%s'" % (self.model.__tablename__, i[0], i[2])
or_filters.append(filter_string)
Here is how I'm using it:
db = SQLAlchemy(app)
...
class myclass:
def __init(self, model):
self.model = model
self.q = db.session.query(self.model)
def get(self, cfg):
...
# the following line works
myfilter = [User.name == 'Sid', User.role == 'admin']
# the following line does not work, but I need it to. How to modify into the line above?
myfilter = ["user.name == 'Sid'", "user.role == 'admin'"]
if myfilter is not None:
self.q = self.apply_filter(myfilter)
items = self.q.all()
return items
def apply_filter(self, ftr):
self.q.filter(or_(*ftr))
Ilja had a good solution
myfilter = getattr(self.model, i[0]).is_(i[2])
if myfilter is not None:
self.q = self.apply_filter(myfilter)

NameError: name '_length' is not defined

I'm using python3 and when trying to run the following code, I'm facing the error:
NameError: name '_length' is not defined
The code itself:
class OFPHELLO(GenericStruct):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._length = self.get_size()
_msg_type = OFPType.OFPT_HELLO
_build_order = ('header', 'x')
header = OFPHeader(type = _msg_type, length = _length)
x = UBInt8()
The problem is the _length variable that I'm passing in OFPHeader, the value of which is computed in GenericStruct. How can I compute the _length variable inside the OFPHELLO class and use it as parameter in the OFPHeader class?
Following the GenericStruct code:
class GenericStruct(object):
def __init__(self, **kwargs):
for a in kwargs:
try:
field = getattr(self, a)
field.value = kwargs[a]
except AttributeError:
raise OFPException("Attribute error: %s" % a)
def build(self):
hexa = ""
for field in self._build_order:
hexa += getattr(self, field).build()
return hexa
def parse(self, buff):
begin = 0
for field in self._build_order:
size = getattr(self, field).get_size()
getattr(self,field).parse(buff, offset=begin)
begin += size
def get_size(self):
tot = 0
for field in self._build_order:
tot += getattr(self, field).get_size()
return tot
- how have you defined (GenericStruct)
- header = OFPHeader(type = _msg_type, length = _lenght)
- correct the spelling to _length
-- and please post the entire code next time

Python Mysql Class error

I'm trying to use this sql class https://github.com/nestordeharo/mysql-python-class to interact with mysql Local database ( server with easydevser, mysql version MySQL 5.7.10 ),but i'm always get an error msg when i try to make a select.
Here is the mysql class:
import MySQLdb, sys
from collections import OrderedDict
class MysqlPython(object):
"""
Python Class for connecting with MySQL server and accelerate development project using MySQL
Extremely easy to learn and use, friendly construction.
"""
__instance = None
__host = None
__user = None
__password = None
__database = None
__session = None
__connection = None
def __new__(cls, *args, **kwargs):
if not cls.__instance or not cls.__database:
cls.__instance = super(MysqlPython, cls).__new__(cls,*args,**kwargs)
return cls.__instance
## End def __new__
def __init__(self, host='localhost', user='root', password='', database=''):
self.__host = host
self.__user = user
self.__password = password
self.__database = database
## End def __init__
def __open(self):
try:
cnx = MySQLdb.connect(self.__host, self.__user, self.__password, self.__database)
self.__connection = cnx
self.__session = cnx.cursor()
except MySQLdb.Error as e:
print "Error %d: %s" % (e.args[0],e.args[1])
## End def __open
def __close(self):
self.__session.close()
self.__connection.close()
## End def __close
def select(self, table, where=None, *args, **kwargs):
result = None
query = 'SELECT '
keys = args
values = tuple(kwargs.values())
l = len(keys) - 1
for i, key in enumerate(keys):
query += "`"+key+"`"
if i < l:
query += ","
## End for keys
query += 'FROM %s' % table
if where:
query += " WHERE %s" % where
print(query)
## End if where
self.__open()
self.__session.execute(query, values)
number_rows = self.__session.rowcount
number_columns = len(self.__session.description)
if number_rows >= 1 and number_columns > 1:
result = [item for item in self.__session.fetchall()]
else:
result = [item[0] for item in self.__session.fetchall()]
self.__close()
return result
## End def select
def update(self, table, where=None, *args, **kwargs):
query = "UPDATE %s SET " % table
keys = kwargs.keys()
values = tuple(kwargs.values()) + tuple(args)
l = len(keys) - 1
for i, key in enumerate(keys):
query += "`"+key+"` = %s"
if i < l:
query += ","
## End if i less than 1
## End for keys
query += " WHERE %s" % where
self.__open()
self.__session.execute(query, values)
self.__connection.commit()
# Obtain rows affected
update_rows = self.__session.rowcount
self.__close()
return update_rows
## End function update
def insert(self, table, *args, **kwargs):
values = None
query = "INSERT INTO %s " % table
if kwargs:
keys = kwargs.keys()
values = tuple(kwargs.values())
query += "(" + ",".join(["`%s`"] * len(keys)) % tuple (keys) + ") VALUES (" + ",".join(["%s"]*len(values)) + ")"
elif args:
values = args
query += " VALUES(" + ",".join(["%s"]*len(values)) + ")"
self.__open()
self.__session.execute(query, values)
self.__connection.commit()
self.__close()
return self.__session.lastrowid
## End def insert
def delete(self, table, where=None, *args):
query = "DELETE FROM %s" % table
if where:
query += ' WHERE %s' % where
values = tuple(args)
self.__open()
self.__session.execute(query, values)
self.__connection.commit()
# Obtain rows affected
delete_rows = self.__session.rowcount
self.__close()
return delete_rows
## End def delete
def select_advanced(self, sql, *args):
od = OrderedDict(args)
query = sql
values = tuple(od.values())
self.__open()
self.__session.execute(query, values)
number_rows = self.__session.rowcount
number_columns = len(self.__session.description)
if number_rows >= 1 and number_columns > 1:
result = [item for item in self.__session.fetchall()]
else:
result = [item[0] for item in self.__session.fetchall()]
self.__close()
return result
## End def select_advanced
## End class
Here is the part of my code when i made the instance and use a select method:
db = MysqlPython(host='localhost', user='root', password='', database='mgdeal')
conditional_query = 'categorie = %s '
result = db.select('table 2', conditional_query, 'nom', 'url', categorie='Lego')
Then i get the followings error
SELECT `nom`,`url`FROM table 2 WHERE categorie = %s
raise errorclass, errorvalue
_mysql_exceptions.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'table 2 WHERE categorie = 'Lego'' at line 1")
Do you have any idea
I found the issue on the code, It's coming from this part for the select method.
query += 'FROM %s' % table
must be replace by
query += 'FROM `%s`' % table

Implementing a table in a PySNMP agent

I'm implementing a table using PySNMP as an SNMP agent.
I've followed the (PySNMP source) architecture of using an auto-generated TRS-MIB.py file, and a manually written __TRS-MIB.py file which contains the implementation.
I have made a working (2 row) table, but the code is really ugly, so there must be a better way of doing it. (Also, both rows will always have the same values, which is a bug.)
__TRS-MIB.py:
# Imported just in case new ASN.1 types would be created
from pyasn1.type import constraint, namedval
import time
# Imports
( Integer,
ObjectIdentifier,
OctetString, ) = mibBuilder.importSymbols(
"ASN1",
"Integer",
"ObjectIdentifier",
"OctetString"
)
( Bits,
Integer32,
ModuleIdentity,
MibIdentifier,
MibScalar,
MibScalarInstance,
TimeTicks, ) = mibBuilder.importSymbols(
"SNMPv2-SMI",
"Bits",
"Integer32",
"ModuleIdentity",
"MibIdentifier",
"MibScalar",
"MibScalarInstance",
"TimeTicks"
)
class TrsDeliveryTime(Integer32):
def clone(self, **kwargs):
if 'value' not in kwargs:
kwargs['value'] = int(time.time())
return Integer32.clone(self, **kwargs)
class TrsMessagesPerHour(Integer32):
def clone(self, **kwargs):
if 'value' not in kwargs:
kwargs['value'] = -int(time.time())
return Integer32.clone(self, **kwargs)
class TrsGatewayIndex(Integer32):
def clone(self, **kwargs):
if 'value' not in kwargs:
kwargs['value'] = 0
return Integer32.clone(self, **kwargs)
class TrsGatewayName(OctetString):
def clone(self, **kwargs):
if 'value' not in kwargs:
kwargs['value'] = 'SMG0'
return OctetString.clone(self, **kwargs)
class TrsGatewayState(OctetString):
def clone(self, **kwargs):
if 'value' not in kwargs:
kwargs['value'] = 'UP' + str(int(time.time()))
return OctetString.clone(self, **kwargs)
# Objects
( trsDeliveryTime,
trsMessagesPerHour,
trsGatewayTable,
trsGatewayEntry,
trsGatewayIndex,
trsGatewayName,
trsGatewayState, ) = mibBuilder.importSymbols(
'TRS-MIB',
'trsDeliveryTime',
'trsMessagesPerHour',
'trsGatewayTable',
'trsGatewayEntry',
'trsGatewayIndex',
'trsGatewayName',
'trsGatewayState',
)
__trsDeliveryTime = MibScalarInstance(trsDeliveryTime.name, (0,), TrsDeliveryTime(0))
__trsMessagesPerHour = MibScalarInstance(trsMessagesPerHour.name, (0,), TrsMessagesPerHour(0))
__trsGatewayIndex0 = MibScalarInstance(trsGatewayIndex.name, (0,), TrsGatewayIndex(0))
__trsGatewayName0 = MibScalarInstance(trsGatewayName.name, (0,), TrsGatewayName(0))
__trsGatewayState0 = MibScalarInstance(trsGatewayState.name, (0,), TrsGatewayState(0))
__trsGatewayIndex1 = MibScalarInstance(trsGatewayIndex.name, (1,), TrsGatewayIndex(0))
__trsGatewayName1 = MibScalarInstance(trsGatewayName.name, (1,), TrsGatewayName(0))
__trsGatewayState1 = MibScalarInstance(trsGatewayState.name, (1,), TrsGatewayState(0))
# Augmentions
# Exports
# Objects
mibBuilder.exportSymbols("__TRS-MIB",
trsDeliveryTime=__trsDeliveryTime,
trsMessagesPerHour=__trsMessagesPerHour,
trsGatewayTable=trsGatewayTable,
trsGatewayIndex0=__trsGatewayIndex0,
trsGatewayName0=__trsGatewayName0,
trsGatewayState0=__trsGatewayState0,
trsGatewayIndex1=__trsGatewayIndex1,
trsGatewayName1=__trsGatewayName1,
trsGatewayState1=__trsGatewayState1,
)
Not pretending this is a beautiful code, here's some optimization to your initial version. It's not tested as I do not have your TRS-MIB file at hand.
The idea is to specialize MibScalarInstance class (to make it serving different columns) by overriding its readGet() method which returns a var-bind pair to be reported back to SNMP Manager.
You should be able to run this MIB with the stock CommandResponder, just make sure to load up your MIB on startup.
import time
# Import managed objects
( trsDeliveryTime,
trsMessagesPerHour,
trsGatewayIndex,
trsGatewayName,
trsGatewayState, ) = mibBuilder.importSymbols(
'TRS-MIB',
'trsDeliveryTime',
'trsMessagesPerHour',
'trsGatewayIndex',
'trsGatewayName',
'trsGatewayState',
)
# Columnar managed objects instances implementation
class TrsDeliveryTimeInstance(MibScalarInstance):
def readGet(self, name, val, *args):
if name[-1] == 0: # Row #0
return self.name, self.syntax(int(time.time()))
elif name[-1] == 1: # Row #1
return self.name, self.syntax(time.time()//2)
else:
MibScalarInstance.readGet(self, name, val, *args)
class TrsMessagesPerHourInstance(MibScalarInstance):
def readGet(self, name, val, *args):
if name[-1] == 0: # Row #0
return self.name, self.syntax(-int(time.time()))
elif name[-1] == 1: # Row #1
return self.name, self.syntax(-time.time()//2)
else:
MibScalarInstance.readGet(self, name, val, *args)
class TrsGatewayIndexInstance(MibScalarInstance):
def readGet(self, name, val, *args):
if name[-1] == 0: # Row #0
return self.name, self.syntax(0)
elif name[-1] == 1: # Row #1
return self.name, self.syntax(1)
else:
MibScalarInstance.readGet(self, name, val, *args)
class TrsGatewayNameInstance(MibScalarInstance):
def readGet(self, name, val, *args):
if name[-1] == 0: # Row #0
return self.name, self.syntax('SMG0')
elif name[-1] == 1: # Row #1
return self.name, self.syntax('SMG1')
else:
MibScalarInstance.readGet(self, name, val, *args)
class TrsGatewayStateInstance(MibScalarInstance):
def readGet(self, name, val, *args):
if name[-1] == 0: # Row #0
return self.name, self.syntax('UP' + str(time.time()))
elif name[-1] == 1: # Row #1
return self.name, self.syntax('DOWN' + str(time.time()))
else:
MibScalarInstance.readGet(self, name, val, *args)
# Instantiate and export managed objects instances
mibBuilder.exportSymbols(
"__TRS-MIB",
# Row #0
TrsDeliveryTimeInstance(trsDeliveryTime.getName(), 0, trsDeliveryTime.getSyntax()),
TrsMessagesPerHourInstance(trsMessagesPerHour.getName(), 0, trsMessagesPerHour.getSyntax()),
TrsGatewayIndexInstance(trsGatewayIndex.getName(), 0, trsGatewayIndex.getSyntax()),
TrsGatewayNameInstance(trsGatewayName.getName(), 0, trsGatewayName.getSyntax()),
TrsGatewayStateInstance(trsGatewayState.getName(), 0, trsGatewayState.getSyntax()),
# Row #1
TrsDeliveryTimeInstance(trsDeliveryTime.getName(), 1, trsDeliveryTime.getSyntax()),
TrsMessagesPerHourInstance(trsMessagesPerHour.getName(), 1, trsMessagesPerHour.getSyntax()),
TrsGatewayIndexInstance(trsGatewayIndex.getName(), 1, trsGatewayIndex.getSyntax()),
TrsGatewayNameInstance(trsGatewayName.getName(), 1, trsGatewayName.getSyntax()),
TrsGatewayStateInstance(trsGatewayState.getName(), 1, trsGatewayState.getSyntax())
)

Categories