1+ """
2+ Module to handle the traits database
3+ """
4+
5+ import logging
16import sqlite3
27import os
38import yaml
4- from pathtraits .pathpair import *
5- from dataclasses import dataclass
6- import logging
9+ from pathtraits .pathpair import PathPair
710
811logger = logging .getLogger (__name__ )
912
1013
1114class TraitsDB :
15+ """
16+ Database of pathtrait in 3NF with view of all joined trait tables
17+ """
18+
1219 cursor = None
1320 traits = []
1421
@@ -32,16 +39,31 @@ def __init__(self, db_path):
3239 self .update_traits ()
3340
3441 def execute (self , query ):
42+ """
43+ Execute a SQLite query
44+
45+ :param self: this database
46+ :param query: SQLite query string
47+ """
3548 try :
3649 res = self .cursor .execute (query )
3750 return res
38- except Exception as e :
39- logger .debug (f "Ignore failed query { query } " )
51+ except sqlite3 . DatabaseError :
52+ logger .debug ("Ignore failed query %s" , query )
4053
4154 def get (self , table , cols = "*" , condition = None , ** kwargs ):
55+ """
56+ Get a row from a table
57+
58+ :param self: this database
59+ :param table: table name
60+ :param cols: colums to get as a string to be put after SELECT. All by default.
61+ :param condition: SQL condition string to be put after WHERE. Will overweite kwargs
62+ """
4263 if not condition :
4364 escaped_kwargs = {
44- k : v if type (v ) != str else f"'{ v } '" for (k , v ) in kwargs .items ()
65+ k : v if not isinstance (v , str ) else f"'{ v } '"
66+ for (k , v ) in kwargs .items ()
4567 }
4668 condition = " AND " .join ([f"{ k } ={ v } " for (k , v ) in escaped_kwargs .items ()])
4769 get_row_query = f"SELECT { cols } FROM { table } WHERE { condition } LIMIT 1;"
@@ -56,6 +78,12 @@ def get(self, table, cols="*", condition=None, **kwargs):
5678 return res
5779
5880 def get_dict (self , path ):
81+ """
82+ Get traits for a path as a Python dictionary
83+
84+ :param self: this database
85+ :param path: path to get traits for
86+ """
5987 abs_path = os .path .abspath (path )
6088 leaf_dir = os .path .dirname (abs_path ) if os .path .isfile (abs_path ) else abs_path
6189 dirs = leaf_dir .split ("/" )
@@ -80,24 +108,43 @@ def get_dict(self, path):
80108 return res
81109
82110 def put_path_id (self , path ):
111+ """
112+ Docstring for put_path_id
113+
114+ :param self: this database
115+ :param path: path to put to the data base
116+ :returns: the id of that path
117+ """
83118 get_row_query = f"SELECT id FROM path WHERE path = '{ path } ' LIMIT 1;"
84119 res = self .execute (get_row_query ).fetchone ()
85120 if res :
86121 return res [0 ]
87- else :
88- # create
89- self .put ("path" , path = path )
90- path_id = self .get ("path" , path = path , cols = "id" )["id" ]
91- return path_id
122+ # create
123+ self .put ("path" , path = path )
124+ path_id = self .get ("path" , path = path , cols = "id" )["id" ]
125+ return path_id
92126
127+ @staticmethod
93128 def escape (value ):
94- if type (value ) == str :
129+ """
130+ Escape a python value for SQL insertion
131+
132+ :param value: value to be escaped
133+ """
134+ if isinstance (value , str ):
95135 return f"'{ value } '"
96- if type (value ) == bool :
136+ if isinstance (value , bool ) :
97137 return "TRUE" if value else "FALSE"
98138 return value
99139
140+ @staticmethod
141+ # pylint: disable=R1710
100142 def sql_type (value_type ):
143+ """
144+ Translate a Python type to a SQLite type
145+
146+ :param value_type: python type to translate
147+ """
101148 if value_type == list :
102149 return
103150 if value_type == dict :
@@ -163,6 +210,9 @@ def put_data_view(self):
163210 self .execute (create_view_query )
164211
165212 def update_traits (self ):
213+ """
214+ Get all traits from the database
215+ """
166216 get_traits_query = """
167217 SELECT name
168218 FROM sqlite_master
@@ -175,40 +225,62 @@ def update_traits(self):
175225 self .traits = [x [0 ] for x in traits ]
176226 self .put_data_view ()
177227
178- def create_trait_table (self , key , value_type ):
179- if key in self .traits :
228+ def create_trait_table (self , trait_name , value_type ):
229+ """
230+ Create a trait table if it does not exist
231+
232+ :param self: this database
233+ :param key: trait name
234+ :param value_type: trait value
235+ """
236+ if trait_name in self .traits :
180237 return
181238 if value_type == list :
182- logger .debug (f "ignore list trait { key } " )
239+ logger .debug ("ignore list trait %s" , trait_name )
183240 return
184241 if value_type == dict :
185- logger .debug (f "ignore dict trait { key } " )
242+ logger .debug ("ignore dict trait %s" , trait_name )
186243 return
187244 sql_type = TraitsDB .sql_type (value_type )
188245 add_table_query = f"""
189- CREATE TABLE { key } (
246+ CREATE TABLE { trait_name } (
190247 path INTEGER,
191- { key } { sql_type } ,
248+ { trait_name } { sql_type } ,
192249 FOREIGN KEY(path) REFERENCES path(id)
193250 );
194251 """
195252 self .execute (add_table_query )
196253 self .update_traits ()
197254
198- def put_trait (self , path_id , key , value ):
199- kwargs = {"path" : path_id , key : value }
200- self .put (key , condition = f"path = { path_id } " , ** kwargs )
255+ def put_trait (self , path_id , trait_name , value ):
256+ """
257+ Put a trait to the database
258+
259+ :param self: this database
260+ :param path_id: id of the path in the path table
261+ :param key: trait name
262+ :param value: trait value
263+ """
264+ kwargs = {"path" : path_id , trait_name : value }
265+ self .put (trait_name , condition = f"path = { path_id } " , ** kwargs )
201266
202267 def add_pathpair (self , pair : PathPair ):
203- with open (pair .meta_path , "r" ) as f :
268+ """
269+ Add a PathPair to the database
270+
271+ :param self: this database
272+ :param pair: the pathpair to be added
273+ :type pair: PathPair
274+ """
275+ with open (pair .meta_path , "r" , encoding = "utf-8" ) as f :
204276 try :
205277 traits = yaml .safe_load (f )
206- except Exception as e :
207- logging .debug (f "ignore meta file { f } . Error message: { e } " )
278+ except ( yaml . YAMLError , OSError ) as e :
279+ logging .debug ("ignore meta file %s . Error message: %s" , f , e )
208280 return
209281
210282 # invalid trait yml file e.g. empty or no key-value pair
211- if type (traits ) != dict :
283+ if not isinstance (traits , dict ) :
212284 return
213285
214286 # put path in db only if there are traits
0 commit comments