alfraser commited on
Commit
d50e68d
·
1 Parent(s): eb8e0a0

Reviewed comments and type hints

Browse files
Files changed (1) hide show
  1. src/datatypes.py +73 -17
src/datatypes.py CHANGED
@@ -1,10 +1,22 @@
 
 
 
 
 
 
 
 
 
1
  import sqlite3
2
- from typing import List
3
 
4
  from src.common import *
5
 
6
 
7
  class DataLoader:
 
 
 
8
  active_db = "02_baseline_products_dataset"
9
  db_dir = os.path.join(data_dir, 'sqlite')
10
  db_file = os.path.join(db_dir, f"{active_db}.db")
@@ -12,6 +24,9 @@ class DataLoader:
12
 
13
  @classmethod
14
  def set_db_name(cls, name: str):
 
 
 
15
  if name != cls.active_db:
16
  new_file = os.path.join(data_dir, 'sqlite', f"{name}.db")
17
  cls.db_file = os.path.join(DataLoader.db_dir, f"{name}.db")
@@ -20,14 +35,26 @@ class DataLoader:
20
 
21
  @staticmethod
22
  def current_db() -> str:
 
 
 
23
  return DataLoader.active_db[:-3]
24
 
25
  @staticmethod
26
  def available_dbs() -> List[str]:
 
 
 
27
  return [f[:-3] for f in os.listdir(DataLoader.db_dir) if ('products' in f) and f.endswith('.db')]
28
 
29
  @staticmethod
30
  def load_data(reload=False):
 
 
 
 
 
 
31
  if DataLoader.loaded and not reload:
32
  return
33
 
@@ -71,16 +98,26 @@ class DataLoader:
71
 
72
 
73
  class Category:
74
- all = {}
 
 
 
 
75
 
76
  @staticmethod
77
- def all_sorted():
 
 
 
78
  all_cats = list(Category.all.values())
79
  all_cats.sort(key=lambda x: x.name)
80
  return all_cats
81
 
82
  @staticmethod
83
- def by_name(name: str):
 
 
 
84
  all_cats = list(Category.all.values())
85
  for c in all_cats:
86
  if c.name == name:
@@ -93,28 +130,37 @@ class Category:
93
  self.products = []
94
 
95
  @property
96
- def feature_count(self):
97
  return len(self.features)
98
 
99
  @property
100
- def product_count(self):
101
  return len(self.products)
102
 
103
  @property
104
- def singular_name(self):
 
 
 
105
  if self.name[-1] == "s":
106
  return self.name[:-1] # Clip the s
107
  return self.name
108
 
109
  @property
110
  def lower_singular_name(self):
 
 
 
111
  if self.name[-1] == "s":
112
  return self.name[:-1].lower() # Clip the s
113
  return self.name.lower()
114
 
115
 
116
  class Feature:
117
- all = {}
 
 
 
118
 
119
  def __init__(self, id, name, category):
120
  self.id = id
@@ -123,15 +169,19 @@ class Feature:
123
  self.products = []
124
 
125
  @property
126
- def product_count(self):
127
  return len(self.products)
128
 
129
- def __repr__(self):
130
  return self.name
131
 
132
 
133
  class Product:
134
- all = {}
 
 
 
 
135
 
136
  def __init__(self, id, name, description, price, category):
137
  self.id = id
@@ -143,30 +193,36 @@ class Product:
143
  self.reviews = []
144
 
145
  @property
146
- def feature_count(self):
147
  return len(self.features)
148
 
149
  @property
150
- def review_count(self):
151
  return len(self.reviews)
152
 
153
  @property
154
- def average_rating(self, decimals=2):
155
  if self.review_count == 0:
156
  return 0.0
157
  return float(round(sum([r.rating for r in self.reviews]) / self.review_count, decimals))
158
 
159
  @staticmethod
160
- def for_ids(ids: List[str]):
 
 
 
161
  return[Product.all[i] for i in ids]
162
 
163
  @staticmethod
164
- def all_as_list():
165
  return list(Product.all.values())
166
 
167
 
168
  class Review:
169
- all = {}
 
 
 
170
 
171
  def __init__(self, id, rating, review_text, product):
172
  self.id = id
 
1
+ """
2
+ This file contains all the code to load the business/private datatypes from the database and interact with them.
3
+ i.e. the product categories, products, reviews etc.... including utility methods to find them, render them etc...
4
+ It is all implemented as a very simple read-only Object-Relational mapping type layer to grant access to read and
5
+ use the data in the database. DB updates are all done by offline processes and the data setup.
6
+ """
7
+
8
+ from __future__ import annotations # For referencing own class
9
+
10
  import sqlite3
11
+ from typing import List, Dict
12
 
13
  from src.common import *
14
 
15
 
16
  class DataLoader:
17
+ """
18
+ Class which controls the loading of all the data in the system from the database
19
+ """
20
  active_db = "02_baseline_products_dataset"
21
  db_dir = os.path.join(data_dir, 'sqlite')
22
  db_file = os.path.join(db_dir, f"{active_db}.db")
 
24
 
25
  @classmethod
26
  def set_db_name(cls, name: str):
27
+ """
28
+ Programatically switch the database in use.
29
+ """
30
  if name != cls.active_db:
31
  new_file = os.path.join(data_dir, 'sqlite', f"{name}.db")
32
  cls.db_file = os.path.join(DataLoader.db_dir, f"{name}.db")
 
35
 
36
  @staticmethod
37
  def current_db() -> str:
38
+ """
39
+ Get the name of the current database in use
40
+ """
41
  return DataLoader.active_db[:-3]
42
 
43
  @staticmethod
44
  def available_dbs() -> List[str]:
45
+ """
46
+ Get the names of all the available databases in the sqlite folder
47
+ """
48
  return [f[:-3] for f in os.listdir(DataLoader.db_dir) if ('products' in f) and f.endswith('.db')]
49
 
50
  @staticmethod
51
  def load_data(reload=False):
52
+ """
53
+ Load (or reload) all the data classes across the system from the database. Fills out all the
54
+ class variables holding the list of all of each type, and then completes also the cross-references
55
+ between objects so they are aware of each other (e.g. putting reviews into products and linking the reviews
56
+ to their products)
57
+ """
58
  if DataLoader.loaded and not reload:
59
  return
60
 
 
98
 
99
 
100
  class Category:
101
+ """
102
+ A category of products (e.g. "Dishwashers"). Holds also a list of Features relevant to this
103
+ category and a list of Products in this category
104
+ """
105
+ all: Dict[str, Category] = {} # All categories by ID
106
 
107
  @staticmethod
108
+ def all_sorted() -> List[Category]:
109
+ """
110
+ Gets a list of all the catgories, sorted by name
111
+ """
112
  all_cats = list(Category.all.values())
113
  all_cats.sort(key=lambda x: x.name)
114
  return all_cats
115
 
116
  @staticmethod
117
+ def by_name(name: str) -> Category:
118
+ """
119
+ Look up a single category by name
120
+ """
121
  all_cats = list(Category.all.values())
122
  for c in all_cats:
123
  if c.name == name:
 
130
  self.products = []
131
 
132
  @property
133
+ def feature_count(self) -> int:
134
  return len(self.features)
135
 
136
  @property
137
+ def product_count(self) -> int:
138
  return len(self.products)
139
 
140
  @property
141
+ def singular_name(self) -> str:
142
+ """
143
+ Get the name of this category, stripping the trailing s if there is one
144
+ """
145
  if self.name[-1] == "s":
146
  return self.name[:-1] # Clip the s
147
  return self.name
148
 
149
  @property
150
  def lower_singular_name(self):
151
+ """
152
+ Get the name of this ctaegory in lower case, removing any trailing s
153
+ """
154
  if self.name[-1] == "s":
155
  return self.name[:-1].lower() # Clip the s
156
  return self.name.lower()
157
 
158
 
159
  class Feature:
160
+ """
161
+ A feature available to Products in a given Category (e.g. "Quiet operation")
162
+ """
163
+ all: Dict[str, Feature] = {} # All features by ID
164
 
165
  def __init__(self, id, name, category):
166
  self.id = id
 
169
  self.products = []
170
 
171
  @property
172
+ def product_count(self) -> int:
173
  return len(self.products)
174
 
175
+ def __repr__(self) -> str:
176
  return self.name
177
 
178
 
179
  class Product:
180
+ """
181
+ A product specification with its price, description, features, and a list of associated
182
+ customer reviews.
183
+ """
184
+ all: Dict[str, Product] = {} # All products by ID
185
 
186
  def __init__(self, id, name, description, price, category):
187
  self.id = id
 
193
  self.reviews = []
194
 
195
  @property
196
+ def feature_count(self) -> int:
197
  return len(self.features)
198
 
199
  @property
200
+ def review_count(self) -> int:
201
  return len(self.reviews)
202
 
203
  @property
204
+ def average_rating(self, decimals=2) -> float:
205
  if self.review_count == 0:
206
  return 0.0
207
  return float(round(sum([r.rating for r in self.reviews]) / self.review_count, decimals))
208
 
209
  @staticmethod
210
+ def for_ids(ids: List[str]) -> List[Product]:
211
+ """
212
+ Get a set of products based on a set of IDs
213
+ """
214
  return[Product.all[i] for i in ids]
215
 
216
  @staticmethod
217
+ def all_as_list() -> List[Product]:
218
  return list(Product.all.values())
219
 
220
 
221
  class Review:
222
+ """
223
+ A single customer review with its star rating and the review text
224
+ """
225
+ all: Dict[str, Review] = {}
226
 
227
  def __init__(self, id, rating, review_text, product):
228
  self.id = id