Python Mysql Class error - python

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

Related

Django rest framework and PostgreSQL best practice

I am using Django and PostgreSQL (psycopg2) for one of our web REST API projects.
Basically, the app is driven by the django-rest-framework library for all REST API-centric tasks such as authentication, permission, serialization and API views. However, since our database tables are not created thru Django's migration system (rather created manually and directly thru DBeaver), our modeling and serialization can actually be considered as highly customized and is no longer following Django's ORM standard (although we try to write our custom ORM design to feel as close as Django's as possible so that the pattern will still feel familiar).
The way I communicate CRUD actions to and from the database is by creating one (1) custom manager class mapped to each custom model class that it's supposed to manage. So in my manager I have like get(), insert(), update(), delete(), force_delete() methods which contain logic for actually sending queries to the database.
For all methods responsible for fetching data i.e. get() all() filter(), they communicate through a database view instead of directly sending a query to the concerned table that may contain JOINs which may be too expensive for the DB server.
This design works fine for us, but I still ask myself if this is actually ideal or at least an acceptable approach specially on real-world, daily consumption of our API by potentially millions of clients.
Or is there any best practice which I should strictly follow? Or any better approach anyone may suggest?
Here are the sample classes for one of our API resources - API version:
DB table
Model Class
class ApiVersionModel:
objects = ApiVersionManager()
def __init__(self):
self.version = None
self.version_info = None
self.date_released = None
self.development = None
self.production = None
def save(self, initial=False):
if not initial:
self.objects.update(self)
else:
self.objects.insert(self)
def delete(self, force_delete=False):
if force_delete:
self.objects.delete(self)
else:
self.objects.soft_delete(self)
Serializer Class
class ApiVersionSerializer(serializers.Serializer):
version = serializers.CharField(max_length=15)
version_info = serializers.CharField(max_length=255, required=False, allow_null=True)
date_released = serializers.DateField()
development = serializers.BooleanField(default=True, required=False, allow_null=True)
production = serializers.BooleanField(default=False, required=False, allow_null=True)
def create(self, validated_data):
c = ApiVersionModel()
c.version = validated_data.get("version")
c.version_info = validated_data.get("version_info")
c.date_released = validated_data.get("date_released")
c.development = validated_data.get("development")
c.production = validated_data.get("production")
c.save(initial=True)
return c
def update(self, c, validated_data):
c.version = validated_data.get("version")
c.version_info = validated_data.get("version_info")
c.date_released = validated_data.get("date_released")
c.development = validated_data.get("development")
c.production = validated_data.get("production")
c.save()
return c
def delete(self, c, validated_data, force_delete=False):
c.version = validated_data.get("version")
c.version_info = validated_data.get("version_info")
c.date_released = validated_data.get("date_released")
c.development = validated_data.get("development")
c.production = validated_data.get("production")
c.delete(force_delete=force_delete)
return c
Manager Class
import traceback
from config.utils import (raw_sql_select, raw_sql_select_enhanced, raw_sql_insert, raw_sql_update, raw_sql_delete)
from unit2_app.utils.ModelUtil import where
class ApiVersionManager():
def __init__(self):
pass
#staticmethod
def all(**kwargs):
query = None
x = None
where_clause = where(**kwargs)
query = ("""
SELECT *
FROM sample_schema.api_version {};
""".format(where_clause))
x = raw_sql_select_enhanced(query, "slave", list(kwargs.values()))
if x is not None:
objects = []
from unit2_app.models.Sys import ApiVersionModel
for col in x[1]:
c = ApiVersionModel()
c.version = col.version
c.version_info = col.version_info
c.date_released = col.date_released
c.development = col.development
c.production = col.production
objects.append(c)
return [] if len(objects) == 0 else objects
return []
#staticmethod
def get(**kwargs):
query = None
x = None
where_clause = where(**kwargs)
query = ("""
SELECT *
FROM sample_schema.api_version {};
""".format(where_clause))
x = raw_sql_select_enhanced(query, "slave", list(kwargs.values()))
if x is not None:
objects = []
from unit2_app.models.Sys import ApiVersionModel
for col in x[1]:
c = ApiVersionModel()
c.version = col.version
c.version_info = col.version_info
c.date_released = col.date_released
c.development = col.development
c.production = col.production
objects.append(c)
return None if len(objects) == 0 else objects[0]
return None
#staticmethod
def filter(**kwargs):
query = None
x = None
where_clause = where(**kwargs)
query = ("""
SELECT *
FROM sample_schema.api_version {};
""".format(where_clause))
x = raw_sql_select_enhanced(query, "slave", list(kwargs.values()))
if x is not None:
objects = []
from unit2_app.models.Sys import ApiVersionModel
for col in x[1]:
c = ApiVersionModel()
c.version = col.version
c.version_info = col.version_info
c.date_released = col.date_released
c.development = col.development
c.production = col.production
objects.append(c)
return [] if len(objects) == 0 else objects
return []
#staticmethod
def insert(c):
try:
query = ("""
START TRANSACTION;
INSERT INTO sample_schema.api_version
(version, version_info, date_released, development, production)
VALUES (%(version)s, %(version_info)s, %(date_released)s, %(development)s, %(production)s);
""")
raw_sql_insert(query, "master", c.__dict__)
except Exception:
traceback.print_exc()
raise Exception("Unexpected manager exception has been encountered.")
#staticmethod
def update(c):
try:
query = ("""
START TRANSACTION;
UPDATE sample_schema.api_version SET
version_info = %(version_info)s,
date_released = %(date_released)s,
development = %(development)s,
production = %(production)s
WHERE version = %(version)s;
""")
raw_sql_update(query, "master", c.__dict__)
except Exception:
raise Exception("Unexpected manager exception has been encountered.")
#staticmethod
def delete(c):
try:
print(c.__dict__)
query = ("""
START TRANSACTION;
DELETE FROM sample_schema.api_version WHERE version=%(version)s;
""")
raw_sql_delete(query, "master", c.__dict__)
except Exception:
raise Exception("Something went wrong with the database manager.")
#staticmethod
def soft_delete(c):
pass
API View Class
class APIView_ApiVersion(views.APIView):
try:
serializer_class = ApiVersionSerializer
permission_classes = (IsAuthenticatedOrReadOnly,)
authentication_classes = ()
except:
traceback.print_exc()
def get_queryset(self, **fltr):
return self.serializer_class(ApiVersionModel.objects.all(**fltr), many=True).data
def get(self, request, **kwargs):
try:
fltr = {k:v[0] for k,v in dict(self.request.GET).items()}
return_data = None
url_path_param_version = None
return_data = self.get_queryset(**fltr)
# perform filtering for version if <version> path param
# ... is present in the URL
if request.resolver_match.kwargs and request.resolver_match.kwargs["version"]:
url_path_param_version = request.resolver_match.kwargs["version"]
return_data = ApiVersionModel.objects.get(version=url_path_param_version, **fltr)
else:
return_data = ApiVersionModel.objects.all(**fltr)
if isinstance(return_data, list):
if len(return_data) > 0:
return Response({
"success": True,
"message": "API version has been fetched successfully.",
"data": self.serializer_class(return_data, many=True).data
}, status=status.HTTP_200_OK)
else:
return Response({
"success": True,
"message": HTTPNotFound.resource_empty(None, obj="API version"),
"data": []
}, status=status.HTTP_200_OK)
else:
if return_data:
return Response({
"success": True,
"message": "API version has been fetched successfully.",
"data": self.serializer_class(return_data).data
}, status=status.HTTP_200_OK)
else:
return Response({
"success": False,
"message": HTTPNotFound.object_unknown(None, obj="API version")
}, status=HTTPNotFound.status_code)
except Exception as e:
return Response({
"success": False,
"message": str(HTTPServerError.unknown_error(None)) + " DETAIL: {}".format(str(e))
}, status=HTTPServerError.status_code)
# Other METHODS also go here i.e. post(), update(), etc.
Custom utility for dynamic API resource filtering / dynamic WHERE CLAUSE
Since our ORM is highly customized, it hinders us from using DRF's inbuilt filtering classes. So I created my own simple utility to optionally allow filtering of SELECT queries via a query string. When applied, the value that the where() method generates gets injected into the DB query in our custom managers.
def filter(key, val):
f = []
c = ""
operator = "="
if len(key.split('__')) > 1:
dus = key.split('__')
for x in range(len(dus)):
f.append(str('{}' if x == 0 else "'{}'").format(dus[x]))
else:
f.append(key)
c = c.join(f) + " {} {} ".format(operator, str(val))
if len(key.split('___')) > 1:
tus = key.split('___')
for x in range(len(tus)):
if tus[x] == "lt":
operator = "<"
elif tus[x] == "lte":
operator = "<="
elif tus[x] == "gt":
operator = ">"
elif tus[x] == "gte":
operator = ">="
for y in f:
if tus[x] in y:
f.remove(y)
y = ""
if len(f) > 2:
for x in range(len(f)):
if x < len(f)-2:
y += f[x] + "->"
elif x <= len(f)-2:
y += f[x] + "->>"
elif x >= len(f)-2:
y += f[x]
else:
y += "->>".join(f)
if val is not None:
if isinstance(val, bool):
c = y + " {} '{}' ".format(operator, str(val).lower())
else:
c = y + " {} '{}' ".format(operator, str(val))
else:
c = y + " IS NULL "
return c
def where(**kwargs):
fields = []
if bool(kwargs):
for key, val in kwargs.items():
# fields.append(filter_nest(key, val))
fields.append(filter(key,val))
return ' WHERE ' + ' AND '.join(fields) if bool(kwargs) else ""

Kivy AttributeError: 'NoneType' object has no attribute 'get_screen'

I'm trying to get a Screen initialised with a number of Buttons depending on the result from a query to my database but I'm getting an AttributeError. I think this is because when I initialise my app there is no Information Screen and reading this answer: AttributeError: 'NoneType' object has no attribute 'current'
I need to use Clock to delay the initialisation of my Finder class so my Information class has time to be created but I'm not quite sure how I go about doing this in the __init__ method, or if this is even the right approach?
class Finder(Screen):
layout_profiles = ObjectProperty(None)
def __init__(self, **kwargs):
super(Finder, self).__init__(**kwargs)
self.mydb = mysql.connector.connect(host="localhost", user="root", passwd="", database="")
self.cur = self.mydb.cursor(buffered=True)
self.cur.execute("SELECT gender, age, name FROM users WHERE location = %s AND date_of_visit = %s",
(self.manager.get_screen('information').location.text,
self.manager.get_screen('information').date))
self.mydb.commit()
self.results = cur.fetchall()
self.cur.close()
self.mydb.close()
if self.results:
for result in self.results:
if result[0] == "male":
male_btn = MaleButton(text="{}, {}".format(result[1], result[2]))
self.layout_profiles.add_widget(male_btn)
elif result[0] == "female":
female_btn = FemaleButton(text="{}, {}".format(result[1], result[2]))
self.layout_profiles.add_widget(female_btn)
else:
unknown_btn = NoGenderButton(text="{}, {}".format(result[1], result[2]))
self.layout_profiles.add_widget(unknown_btn)
Error
line 249, in __init__
(self.manager.get_screen('information').location.text,
AttributeError: 'NoneType' object has no attribute 'get_screen'
, dtThis is a way to execute all the stuff after the screen's initialization
class Finder(Screen):
layout_profiles = ObjectProperty(None)
def __init__(self, **kwargs):
super(Finder, self).__init__(**kwargs)
self.mydb = mysql.connector.connect(host="localhost", user="root", passwd="", database="")
self.cur = self.mydb.cursor(buffered=True)
Clock.schedule_once(self.do_stuff)
def do_stuff(self, dt):
self.cur.execute("SELECT gender, age, name FROM users WHERE location = %s AND date_of_visit = %s",
(self.manager.get_screen('information').location.text,
self.manager.get_screen('information').date))
self.mydb.commit()
self.results = self.cur.fetchall()
self.cur.close()
self.mydb.close()
if self.results:
for result in self.results:
if result[0] == "male":
male_btn = MaleButton(text="{}, {}".format(result[1], result[2]))
self.layout_profiles.add_widget(male_btn)
elif result[0] == "female":
female_btn = FemaleButton(text="{}, {}".format(result[1], result[2]))
self.layout_profiles.add_widget(female_btn)
else:
unknown_btn = NoGenderButton(
text="{}, {}".format(result[1], result[2]))
self.layout_profiles.add_widget(unknown_btn)

Python: Compound functions inside class

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)

AttributeError: database instance has no attribute '_db'

I copied this code from some place in internet , i was trying to learn python from some video tutorial and i found this code ..
When i am trying to compile it with python2.7 its given below errro
ERROR-OUTPUT
In [23]: %run "C:\Users\Developer\Canopy\DevDir\aaa.py"
Create table test
AttributeError Traceback (most recent call last)
C:\Users\Developer\Canopy\DevDir\aaa.py in <module>()
101 for row in db: print(row)
102
--> 103 if __name__ == "__main__": main()
C:\Users\Developer\Canopy\DevDir\aaa.py in main()
78
79 print('Create table test')
---> 80 db.sql_do('drop table if exists test')
81 db.sql_do('create table test ( t1 text, i1 int )')
82
C:\Users\Developer\Canopy\DevDir\aaa.py in sql_do(self, sql, *params)
13
14 def sql_do(self, sql, *params):
---> 15 self._db.execute(sql, params)
16 self._db.commit()
17
AttributeError: database instance has no attribute '_db'
Code
#!/usr/bin/python3
import sqlite3
class database:
def __init__(self, **kwargs):
self.filename = kwargs.get('filename')
self.table = kwargs.get('table', 'test')
def sql_do(self, sql, *params):
self._db.execute(sql, params)
self._db.commit()
def insert(self, row):
self._db.execute('insert into {} (t1, i1) values (?, ?)'.format(self._table), (row['t1'], row['i1']))
self._db.commit()
def retrieve(self, key):
cursor = self._db.execute('select * from {} where t1 = ?'.format(self._table), (key,))
return dict(cursor.fetchone())
def update(self, row):
self._db.execute(
'update {} set i1 = ? where t1 = ?'.format(self._table),
(row['i1'], row['t1']))
self._db.commit()
def delete(self, key):
self._db.execute('delete from {} where t1 = ?'.format(self._table), (key,))
self._db.commit()
def disp_rows(self):
cursor = self._db.execute('select * from {} order by t1'.format(self._table))
for row in cursor:
print(' {}: {}'.format(row['t1'], row['i1']))
def __iter__(self):
cursor = self._db.execute('select * from {} order by t1'.format(self._table))
for row in cursor:
yield dict(row)
#property
def filename(self):
return self._filename
#filename.setter
def filename(self, fn):
self._filename = fn
self._db = sqlite3.connect(fn)
self._db.row_factory = sqlite3.Row
#filename.deleter
def filename(self): self.close()
#property
def table(self): return self._table
#table.setter
def table(self, t): self._table = t
#table.deleter
def table(self): self._table = 'test'
def close(self):
self._db.close()
del self._filename
def main():
db = database(filename = 'test.db', table = 'test')
print('Create table test')
db.sql_do('drop table if exists test')
db.sql_do('create table test ( t1 text, i1 int )')
print('Create rows')
db.insert(dict(t1 = 'one', i1 = 1))
db.insert(dict(t1 = 'two', i1 = 2))
db.insert(dict(t1 = 'three', i1 = 3))
db.insert(dict(t1 = 'four', i1 = 4))
for row in db: print(row)
print('Retrieve rows')
print(db.retrieve('one'), db.retrieve('two'))
print('Update rows')
db.update(dict(t1 = 'one', i1 = 101))
db.update(dict(t1 = 'three', i1 = 103))
for row in db: print(row)
print('Delete rows')
db.delete('one')
db.delete('three')
for row in db: print(row)
if __name__ == "__main__": main()
There is no indention error
I am not able to figure out how to make it work
Any Help ?
in python2.7 properties are less elegant (and this is not too well programmed imho. it is usually good practice to define all members in the constructor; among other things):
import sqlite3
class database:
def __init__(self, **kwargs):
self._set_filename(kwargs.get('filename'))
self._set_table( kwargs.get('table', 'test') )
def sql_do(self, sql, *params):
self._db.execute(sql, params)
self._db.commit()
def insert(self, row):
self._db.execute('insert into {} (t1, i1) values (?, ?)'.format(self._table), (row['t1'], row['i1']))
self._db.commit()
def retrieve(self, key):
cursor = self._db.execute('select * from {} where t1 = ?'.format(self._table), (key,)) print 'SETTER'
return dict(cursor.fetchone())
def update(self, row):
self._db.execute(
'update {} set i1 = ? where t1 = ?'.format(self._table),
(row['i1'], row['t1']))
self._db.commit()
def delete(self, key):
self._db.execute('delete from {} where t1 = ?'.format(self._table), (key,))
self._db.commit()
def disp_rows(self):
cursor = self._db.execute('select * from {} order by t1'.format(self._table))
for row in cursor:
print(' {}: {}'.format(row['t1'], row['i1']))
def __iter__(self):
cursor = self._db.execute('select * from {} order by t1'.format(self._table))
for row in cursor:
yield dict(row)
def _get_filename(self):
return self._filename
def _set_filename(self, fn):
self._filename = fn
self._db = sqlite3.connect(fn)
self._db.row_factory = sqlite3.Row
def _del_filename(self): self.close()
filename = property(_get_filename, _set_filename, _del_filename)
def _get_table(self): return self._table
def _set_table(self, t): self._table = t
def _del_table(self): self._table = 'test'
table = property(_get_table, _set_table, _del_table)
def close(self):
self._db.close()
del self._filename
def main():
db = database(filename = 'test.db', table = 'test')
print('Create table test')
db.sql_do('drop table if exists test')
db.sql_do('create table test ( t1 text, i1 int )')
print('Create rows')
db.insert(dict(t1 = 'one', i1 = 1))
db.insert(dict(t1 = 'two', i1 = 2))
db.insert(dict(t1 = 'three', i1 = 3))
db.insert(dict(t1 = 'four', i1 = 4))
for row in db: print(row)
print('Retrieve rows')
print(db.retrieve('one'), db.retrieve('two'))
print('Update rows')
db.update(dict(t1 = 'one', i1 = 101))
db.update(dict(t1 = 'three', i1 = 103))
for row in db: print(row)
print('Delete rows')
db.delete('one')
db.delete('three')
for row in db: print(row)
if __name__ == "__main__": main()

Python compiler for simple language to java vm code algorithm

I have a simple language that I am trying to write a compiler for (yes it is homework) to compile a simple language I shall describe if necessary to java vm code.
It currently works pretty well I've just hit a bump with logical AND's and OR's.
Each work fine in a single if/while condition, but if I try and chain them things go wrong, correct me if I am wrong but I believe that AND has precedence, but I was wondering if there are logical ways of arranging them? I think is what I'm trying to ask, the java vm code output just has the compare and jump statements one after the other (which seems wrong). I realise it's quite abstract so maybe what I'm after is a pseudo code/algorithm for how to structure chained AND's and OR's.
EDIT: Currently just treats any combination of AND and OR as AND's. Comparing the factor/term/expression connection (compared to booleanfactor etc) I believe that AND has precedence? Just a thought.
Apologies if this is poorly understood :/
So i figure ill include relevant info just incase.
compiler
import re
import sys
# Restrictions:
# Integer constants must be short.
# Stack size must not exceed 1024.
# Integer is the only type.
# Logical operators cannot be nested.
class Scanner:
'''The interface comprises the methods lookahead and consume.
Other methods should not be called from outside of this class.'''
def __init__(self, input_file):
'''Reads the whole input_file to input_string.'''
# source code of the program to be compiled
self.input_string = input_file.read()
# index where the unprocessed part of input_string starts
self.current_char_index = 0
# a pair (most recently read token, matched substring of input_string)
self.current_token = self.get_token()
def skip_white_space(self):
'''Consumes all characters in input_string up to the next
non-white-space character.'''
if (self.current_char_index >= len(self.input_string) - 1):
# bad fix for it over-running the end of the file
return
while self.input_string[self.current_char_index].isspace():
self.current_char_index += 1
return
def get_token(self):
'''Returns the next token and the part of input_string it matched.
Returns None if there is no next token.
The characters up to the end of the token are consumed.'''
self.skip_white_space()
# find the longest prefix of input_string that matches a token
token, longest = None, ''
for (t, r) in Token.token_regexp:
match = re.match(r, self.input_string[self.current_char_index:])
if match and match.end() > len(longest):
token, longest = t, match.group()
# consume the token by moving the index to the end of the matched part
self.current_char_index += len(longest)
return (token, longest)
def lookahead(self):
'''Returns the next token without consuming it.
Returns None if there is no next token.'''
return self.current_token[0]
def consume(self, *tokens):
'''Returns the next token and consumes it, if it is in tokens.
Raises an exception otherwise.
If the token is a number or an identifier, its value is returned.'''
if self.current_token[0] not in tokens:
print('Token ' + self.current_token[0] + ' isn\'t in the tokens: ')
for token in tokens:
print(token)
raise Exception('Token is not in tokens this shouldn\'t happen much')
if self.current_token[0] == 'ID':
symbol_table.location(self.current_token[1])
value = self.current_token[1]
elif (self.current_token[0] == 'NUM'):
value = self.current_token[1]
else:
value = self.current_token[0]
self.current_token = self.get_token()
return value
class Token:
DO = 'DO';
ELSE = 'ELSE';
END = 'END';
IF = 'IF';
THEN = 'THEN';
WHILE = 'WHILE';
SEM = 'SEM';
BEC = 'BEC';
LESS = 'LESS';
EQ = 'EQ';
GRTR = 'GRTR';
LEQ = 'LEQ';
NEQ = 'NEQ';
GEQ = 'GEQ';
ADD = 'ADD';
SUB = 'SUB';
MUL = 'MUL';
DIV = 'DIV';
LPAR = 'LPAR';
RPAR = 'RPAR';
NUM = 'NUM';
ID = 'ID';
READ = 'READ';
WRITE = 'WRITE';
OR = 'OR';
AND = 'AND';
NOT = 'NOT';
# The following list gives the regular expression to match a token.
# The order in the list matters for mimicking Flex behaviour.
# Longer matches are preferred over shorter ones.
# For same-length matches, the first in the list is preferred.
token_regexp = [
(DO, 'do'),
(ELSE, 'else'),
(END, 'end'),
(IF, 'if'),
(THEN, 'then'),
(WHILE, 'while'),
(READ, 'read'),
(WRITE, 'write'),
(OR, 'or'),
(AND, 'and'),
(NOT, 'not'),
(SEM, ';'),
(BEC, ':='),
(LESS, '<'),
(EQ, '='),
(NEQ, '!='),
(GRTR, '>'),
(LEQ, '<='),
(GEQ, '>='),
(ADD, '[+]'), # + is special in regular expressions
(SUB, '-'),
(MUL, '[*]'),
(DIV, '/'),
(LPAR, '[(]'), # ( is special in regular expressions
(RPAR, '[)]'), # ) is special in regular expressions
(ID, '[a-z]+'),
(NUM, '[0-9]+'),
]
class Symbol_Table:
'''A symbol table maps identifiers to locations.'''
def __init__(self):
self.symbol_table = {}
def size(self):
'''Returns the number of entries in the symbol table.'''
return len(self.symbol_table)
def location(self, identifier):
'''Returns the location of an identifier. If the identifier is not in
the symbol table, it is entered with a new location. Locations are
numbered sequentially starting with 0.'''
if identifier in self.symbol_table:
return self.symbol_table[identifier]
index = len(self.symbol_table)
self.symbol_table[identifier] = index
return index
class Label:
def __init__(self):
self.current_label = 0
def next(self):
'''Returns a new, unique label.'''
self.current_label += 1
return 'l' + str(self.current_label)
def indent(s, level):
return ' '*level + s + '\n'
# Each of the following classes is a kind of node in the abstract syntax tree.
# indented(level) returns a string that shows the tree levels by indentation.
# code() returns a string with JVM bytecode implementing the tree fragment.
# true_code/false_code(label) jumps to label if the condition is/is not true.
# Execution of the generated code leaves the value of expressions on the stack.
class Program_AST:
def __init__(self, program):
self.program = program
def __repr__(self):
return repr(self.program)
def indented(self, level):
return self.program.indented(level)
def code(self):
program = self.program.code()
local = symbol_table.size()
java_scanner = symbol_table.location('Java Scanner')
return '.class public Program\n' + \
'.super java/lang/Object\n' + \
'.method public <init>()V\n' + \
'aload_0\n' + \
'invokenonvirtual java/lang/Object/<init>()V\n' + \
'return\n' + \
'.end method\n' + \
'.method public static main([Ljava/lang/String;)V\n' + \
'.limit locals ' + str(local) + '\n' + \
'.limit stack 1024\n' + \
'new java/util/Scanner\n' + \
'dup\n' + \
'getstatic java/lang/System.in Ljava/io/InputStream;\n' + \
'invokespecial java/util/Scanner.<init>(Ljava/io/InputStream;)V\n' + \
'astore ' + str(java_scanner) + '\n' + \
program + \
'return\n' + \
'.end method\n'
class Statements_AST:
def __init__(self, statements):
self.statements = statements
def __repr__(self):
result = repr(self.statements[0])
for st in self.statements[1:]:
result += '; ' + repr(st)
return result
def indented(self, level):
result = indent('Statement(s)', level)
for st in self.statements:
result += st.indented(level+1)
return result
def code(self):
result = ''
for st in self.statements:
result += st.code()
return result
class If_AST:
def __init__(self, boolean_expression, then):
self.boolean_expression = boolean_expression
self.then = then
def __repr__(self):
return 'if ' + repr(self.boolean_expression) + ' then ' + \
repr(self.then) + ' end'
def indented(self, level):
return indent('If-Then', level) + \
self.boolean_expression.indented(level+1) + \
self.then.indented(level+1)
def code(self):
l1 = label_generator.next()
return self.boolean_expression.code(l1) + \
self.then.code() + \
l1 + ':\n'
class If_Else_AST:
def __init__(self, boolean_expression, then, _else):
self.boolean_expression = boolean_expression;
self.then = then;
self._else = _else;
def __repr__(self):
return 'if ' + repr(self.boolean_expression) + ' then ' + \
repr(self.then) + ' else ' + \
repr(self._else) + ' end'
def indented(self, level):
return indent('If-Then-Else', level) + \
self.boolean_expression.indented(level+1) + \
self.then.indented(level+1) + \
indent('Else', level+1) + \
self._else.indented(level+1)
def code(self):
l1 = label_generator.next()
l2 = label_generator.next()
return self.boolean_expression.code(l1) + \
self.then.code() + \
'goto ' + l2 + '\n' + \
l1 + ':\n' + \
self._else.code() + \
l2 + ':\n'
class While_AST:
def __init__(self, boolean_term, body):
self.boolean_term = boolean_term
self.body = body
def __repr__(self):
return 'while ' + repr(self.boolean_term) + ' do ' + \
repr(self.body) + ' end'
def indented(self, level):
return indent('While-Do', level) + \
self.boolean_term.indented(level+1) + \
self.body.indented(level+2)
def code(self):
l1 = label_generator.next()
l2 = label_generator.next()
return l1 + ':\n' + \
self.boolean_term.code(l2) + \
self.body.code() + \
'goto ' + l1 + '\n' + \
l2 + ':\n'
class Assign_AST:
def __init__(self, identifier, expression):
self.identifier = identifier
self.expression = expression
def __repr__(self):
return repr(self.identifier) + ':=' + repr(self.expression)
def indented(self, level):
return indent('Assign', level) + \
self.identifier.indented(level+1) + \
self.expression.indented(level+1)
def code(self):
loc = symbol_table.location(self.identifier.identifier)
return self.expression.code() + \
'istore ' + str(loc) + '\n'
class Write_AST:
def __init__(self, expression):
self.expression = expression
def __repr__(self):
return 'write ' + repr(self.expression)
def indented(self, level):
return indent('Write', level) + self.expression.indented(level+1)
def code(self):
return 'getstatic java/lang/System/out Ljava/io/PrintStream;\n' + \
self.expression.code() + \
'invokestatic java/lang/String/valueOf(I)Ljava/lang/String;\n' + \
'invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V\n'
class Read_AST:
def __init__(self, identifier):
self.identifier = identifier
def __repr__(self):
return 'read ' + repr(self.identifier)
def indented(self, level):
return indent('Read', level) + self.identifier.indented(level+1)
def code(self):
java_scanner = symbol_table.location('Java Scanner')
loc = symbol_table.location(self.identifier.identifier)
return 'aload ' + str(java_scanner) + '\n' + \
'invokevirtual java/util/Scanner.nextInt()I\n' + \
'istore ' + str(loc) + '\n'
class Comparison_AST:
def __init__(self, left, op, right):
self.left = left
self.op = op
self.right = right
def __repr__(self):
op = { Token.LESS:'<', Token.EQ:'=', Token.GRTR:'>',
Token.LEQ:'<=', Token.NEQ:'!=', Token.GEQ:'>=' }
return repr(self.left) + op[self.op] + repr(self.right)
def indented(self, level):
return indent(self.op, level) + \
self.left.indented(level+1) + \
self.right.indented(level+1)
def true_code(self, label):
op = { Token.LESS:'if_icmplt', Token.EQ:'if_icmpeq',
Token.GRTR:'if_icmpgt', Token.LEQ:'if_icmple',
Token.NEQ:'if_icmpne', Token.GEQ:'if_icmpge' }
return self.left.code() + \
self.right.code() + \
op[self.op] + ' ' + label + '\n'
def false_code(self, label):
# Negate each comparison because of jump to "false" label.
op = { Token.LESS:'if_icmpge', Token.EQ:'if_icmpne',
Token.GRTR:'if_icmple', Token.LEQ:'if_icmpgt',
Token.NEQ:'if_icmpeq', Token.GEQ:'if_icmplt' }
return self.left.code() + \
self.right.code() + \
op[self.op] + ' ' + label + '\n'
class Expression_AST:
def __init__(self, left, op, right):
self.left = left
self.op = op
self.right = right
def __repr__(self):
op = { Token.ADD:'+', Token.SUB:'-', Token.MUL:'*', Token.DIV:'/' }
return '(' + repr(self.left) + op[self.op] + repr(self.right) + ')'
def indented(self, level):
return indent(self.op, level) + \
self.left.indented(level+1) + \
self.right.indented(level+1)
def code(self):
op = { Token.ADD:'iadd', Token.SUB:'isub',
Token.MUL:'imul', Token.DIV:'idiv' }
return self.left.code() + \
self.right.code() + \
op[self.op] + '\n'
class Number_AST:
def __init__(self, number):
self.number = number
def __repr__(self):
return self.number
def indented(self, level):
return indent(self.number, level)
def code(self): # works only for short numbers
return 'sipush ' + self.number + '\n'
class Identifier_AST:
def __init__(self, identifier):
self.identifier = identifier
def __repr__(self):
return self.identifier
def indented(self, level):
return indent(self.identifier, level)
def code(self):
loc = symbol_table.location(self.identifier)
return 'iload ' + str(loc) + '\n'
class BooleanFactor_AST:
def __init__(self, condition, logic):
self.condition = condition
self.logic = logic
def __repr__(self):
if self.logic == False:
return 'NOT ' + repr(self.condition)
else:
return repr(self.condition)
def indented(self, level):
if self.logic == False:
return indent('NOT ', level) + self.condition.indented(level + 1)
else:
return self.condition.indented(level)
def false_code(self, label):
if self.logic == True:
return self.condition.false_code(label)
else:
return self.condition.true_code(label)
return
def true_code(self, label):
if self.logic == True:
return self.condition.true_code(label)
else:
return self.condition.false_code(label)
class BooleanTerm_AST:
def __init__(self, terms):
self.terms = terms
def __repr__(self):
result = repr(self.terms[0])
for term in self.terms[1:]:
result = result + ' AND ' + repr(term)
return result
def indented(self, level):
result = self.terms[0].indented(level)
for term in self.terms[1:]:
result = result + indent('AND', level)
result = result + term.indented(level)
return result
def code(self, label):
result = ''
for term in self.terms:
result = result + term.false_code(label)
return result
class BooleanExpression_AST:
def __init__(self, expressions):
self.expressions = expressions
def __repr__(self):
result = repr(self.expressions[0])
for expression in self.expressions[1:]:
result = result + ' OR ' + repr(expression)
return result
def indented(self, level):
result = self.expressions[0].indented(level)
indentation = 0
for expression in self.expressions[1:]:
indentation += 1
result = result + indent('OR', level + indentation)
result = result + expression.indented(level + indentation)
return result
def code(self, label):
result = ''
for expression in self.expressions:
result = result + expression.code(label)
return result
# The following methods comprise the recursive-descent parser.
def program():
sts = statements()
return Program_AST(sts)
def statements():
result = [statement()]
while scanner.lookahead() == Token.SEM:
scanner.consume(Token.SEM)
st = statement()
result.append(st)
return Statements_AST(result)
def statement():
if scanner.lookahead() == Token.IF:
return if_statement()
elif scanner.lookahead() == Token.WHILE:
return while_statement()
elif scanner.lookahead() == Token.ID:
return assignment()
elif scanner.lookahead() == Token.READ:
return read();
elif scanner.lookahead() == Token.WRITE:
return write();
else: # error
return scanner.consume(Token.IF, Token.WHILE, Token.ID)
def if_statement():
scanner.consume(Token.IF)
condition = boolean_expression()
scanner.consume(Token.THEN)
then = statements()
if scanner.lookahead() == Token.END:
scanner.consume(Token.END)
return If_AST(condition, then)
else:
scanner.consume(Token.ELSE)
_else = statements()
scanner.consume(Token.END)
return If_Else_AST(condition, then, _else)
def while_statement():
scanner.consume(Token.WHILE)
condition = boolean_expression()
scanner.consume(Token.DO)
body = statements()
scanner.consume(Token.END)
return While_AST(condition, body)
def assignment():
ident = identifier()
scanner.consume(Token.BEC)
expr = expression()
return Assign_AST(ident, expr)
def read():
scanner.consume(Token.READ)
variable = identifier()
return Read_AST(variable)
def write():
scanner.consume(Token.WRITE)
expr = expression()
return Write_AST(expr)
def comparison():
left = expression()
op = scanner.consume(Token.LESS, Token.EQ, Token.GRTR,
Token.LEQ, Token.NEQ, Token.GEQ)
right = expression()
return Comparison_AST(left, op, right)
def expression():
result = term()
while scanner.lookahead() in [Token.ADD, Token.SUB]:
op = scanner.consume(Token.ADD, Token.SUB)
tree = term()
result = Expression_AST(result, op, tree)
return result
def term():
result = factor()
while scanner.lookahead() in [Token.MUL, Token.DIV]:
op = scanner.consume(Token.MUL, Token.DIV)
tree = factor()
result = Expression_AST(result, op, tree)
return result
def factor():
if scanner.lookahead() == Token.LPAR:
scanner.consume(Token.LPAR)
result = expression()
scanner.consume(Token.RPAR)
return result
elif scanner.lookahead() == Token.NUM:
value = scanner.consume(Token.NUM)
return Number_AST(value)
elif scanner.lookahead() == Token.ID:
return identifier()
else: # error
return scanner.consume(Token.LPAR, Token.NUM, Token.ID)
def identifier():
value = scanner.consume(Token.ID)
return Identifier_AST(value)
def boolean_factor():
if scanner.lookahead() == Token.NOT:
scanner.consume(Token.NOT)
logic = False
else:
logic = True
result = comparison()
return BooleanFactor_AST(result, logic)
def boolean_term():
result = [boolean_factor()]
while scanner.lookahead() in [Token.AND]:
scanner.consume(scanner.lookahead())
temp = boolean_factor()
result.append(temp)
return BooleanTerm_AST(result)
def boolean_expression():
result = [boolean_term()]
while scanner.lookahead() in [Token.OR]:
scanner.consume(scanner.lookahead())
temp = boolean_term()
result.append(temp)
return BooleanExpression_AST(result)
# Initialise scanner, symbol table and label generator.
#scanner = Scanner(open('test.txt'))
scanner = Scanner(sys.stdin)
symbol_table = Symbol_Table()
symbol_table.location('Java Scanner') # fix a location for the Java Scanner
label_generator = Label()
# Uncomment the following to test the scanner without the parser.
# This shows a list of all tokens in the input.
#
#token = scanner.lookahead()
#while token != None:
# print(token)
# scanner.consume(token)
# token = scanner.lookahead()
#exit()
# Call the parser.
ast = program()
assert scanner.lookahead() == None
# Uncomment the following to test the parser without the code generator.
# The first line gives back the program by calling __repr__ of the AST classes.
# The second line shows the syntax tree with levels indicated by indentation.
#
#print(ast)
#print(ast.indented(0))
#exit()
# Call the code generator.
# This translates the abstract syntax tree to JVM bytecode.
# It can be assembled to a class file by Jasmin: http://jasmin.sourceforge.net/
print(ast.code())
testing bat file
python compiler.py <test.txt> Program.j
java -Xmx100m -jar jasmin.jar Program.j
java -Xmx100m Program < testInput.txt > test_output.txt
and language (BNF)
Program = Statements
Statements = Statement (; Statement)
Statement = If | While | Assignment
If = if Comparison then Statements end
While = while Comparison do Statements end
Assignment = identifier := Expression
Comparison = Expression Relation Expression
Relation = = | != | < | <= | > | >=
Expression = Term ((+ | -) Term)
Term = Factor ((* | /) Factor)
Factor = (Expression) | number | identifier
BooleanExpression = BooleanTerm (or BooleanTerm)*
BooleanTerm = BooleanFactor (and BooleanFactor)*
BooleanFactor = not BooleanFactor | Comparison
I think thats all that is relevant, cheers if you take a go at helping me on this
if you want a method to chain OR's and AND'syou can use this property:
p v q === ¬p ^ ¬q
Is equivalent, you can process all in the AND form. for example.
p v q ^ r v s === ¬p ^ ¬q ^ ¬r ^ ¬s
So evaluate the expression in AND form is simple with an algorithm.
I guess the expression doesn't have any parenthesis, in other way you need prioritize the grouping symbols (), [], {}.

Categories