1212product across different orders, so that the row explosion and
1313ordering behavior of the inventory report can be verified end-to-end.
1414
15- Run from the project root:
16-
17- python scripts/load_inventory_demo.py --verbose
18-
1915The script appends to the currently configured MongoDB database. No
2016existing data is removed.
21- """
2217
23- import logging
24- import random
18+ Run from the project root with:
19+ python scripts/load_inventory_demo.py [options]
20+
21+ Options:
22+ --orders=N Number of orders to create (default: 12)
23+ --paid-ratio=R Fraction of orders that should be marked paid
24+ (default: 0.75)
25+ --seed=N Seed for the pseudo random generator
26+ (default: 42)
27+ --verbose, -v Enable verbose output
28+
29+ Examples:
30+ python scripts/load_inventory_demo.py
31+ python scripts/load_inventory_demo.py -v
32+ python scripts/load_inventory_demo.py --orders=30 -v
33+ python scripts/load_inventory_demo.py --orders=20 --paid-ratio=0.5 -v
34+ python scripts/load_inventory_demo.py --seed=1234 -v
35+
36+ Requires:
37+ Python 3.10+
38+ """
2539
40+ from argparse import ArgumentParser , Namespace
41+ from logging import ERROR
42+ from random import Random
2643from sys import exit
2744from traceback import print_exc
28- from argparse import ArgumentParser , Namespace
29-
30- import appier
45+ from typing import Any
3146
32- import budy
47+ from budy import Address , BudyApp , Order , OrderLine , Product
3348
3449
3550class InventoryDemoLoader :
@@ -38,7 +53,7 @@ class InventoryDemoLoader:
3853 of products and orders, tailored to exercise the inventory report.
3954 """
4055
41- PRODUCTS = (
56+ PRODUCTS : tuple [ dict [ str , Any ], ...] = (
4257 dict (
4358 sku = "SHIRT-BLUE" ,
4459 short_description = "Blue Cotton Shirt" ,
@@ -97,17 +112,17 @@ class InventoryDemoLoader:
97112 """ The catalog of demo products, spread across the supported
98113 genders and with enough on-hand stock to absorb any order mix """
99114
100- SIZES = (36 , 38 , 40 , 42 , 44 )
115+ SIZES : tuple [ int , ...] = (36 , 38 , 40 , 42 , 44 )
101116 """ The set of sizes randomly assigned to order lines, picked
102117 small enough so that collisions across lines are common """
103118
104119 def __init__ (
105120 self ,
106- orders_count = 12 ,
107- paid_ratio = 0.75 ,
108- seed = 42 ,
109- verbose = True ,
110- ):
121+ orders_count : int = 12 ,
122+ paid_ratio : float = 0.75 ,
123+ seed : int = 42 ,
124+ verbose : bool = True ,
125+ ) -> None :
111126 """
112127 Initializes the inventory demo loader.
113128
@@ -120,12 +135,12 @@ def __init__(
120135
121136 self .orders_count = orders_count
122137 self .paid_ratio = paid_ratio
123- self .random = random . Random (seed )
138+ self .random = Random (seed )
124139 self .verbose = verbose
125- self .app = None
126- self .products = []
140+ self .app : BudyApp | None = None
141+ self .products : list [ Product ] = []
127142
128- def log (self , message , level = "INFO" ):
143+ def log (self , message : str , level : str = "INFO" ) -> None :
129144 """
130145 Logs a message if verbose mode is enabled.
131146
@@ -136,30 +151,30 @@ def log(self, message, level="INFO"):
136151 if not self .verbose :
137152 return
138153 for part in message .split ("\n " ):
139- print ("[%s] %s" % ( level , part ) )
154+ print (f"[ { level } ] { part } " )
140155
141- def init_app (self ):
156+ def init_app (self ) -> None :
142157 """
143158 Initializes the underlying Budy application so that model
144159 operations can be executed against the configured database.
145160 """
146161
147162 self .log ("Initializing Budy application..." )
148- self .app = budy . BudyApp (level = logging . ERROR )
163+ self .app = BudyApp (level = ERROR )
149164 self .log ("Budy application initialized successfully" )
150165
151- def stop_app (self ):
166+ def stop_app (self ) -> None :
152167 """
153168 Unloads the Budy application, ensuring that any open
154169 resources (scheduler, database connection) are released.
155170 """
156171
157- if self .app == None :
172+ if self .app is None :
158173 return
159174 self .app .unload ()
160175 self .app = None
161176
162- def load_products (self ):
177+ def load_products (self ) -> None :
163178 """
164179 Loads the demo products into the database.
165180 """
@@ -173,12 +188,12 @@ def load_products(self):
173188 for key , value in product_data .items ()
174189 if key not in ("thumbnail_url" , "image_url" )
175190 }
176- product = budy . Product (** base_data )
191+ product = Product (** base_data )
177192 product .save ()
178193 self .products .append (product )
179- self .log (" + Created Product: %s (%s)" % ( product .sku , product .gender ) )
194+ self .log (f " + Created Product: { product .sku } ( { product .gender } )" )
180195
181- def load_orders (self ):
196+ def load_orders (self ) -> None :
182197 """
183198 Loads the demo orders into the database, creating a mix of
184199 paid and unpaid orders and exploding multi-size product
@@ -193,7 +208,7 @@ def load_orders(self):
193208 paid = index < paid_count
194209 self ._create_order (index , paid )
195210
196- def load_product_images (self ):
211+ def load_product_images (self ) -> None :
197212 """
198213 Applies the pre-defined thumbnail and full-size image URLs to
199214 each product by bypassing the normal save pipeline, so that
@@ -204,10 +219,10 @@ def load_product_images(self):
204219 self .log ("\n " + "=" * 60 )
205220 self .log ("Loading Product Images" )
206221 self .log ("=" * 60 )
207- collection = budy . Product ._collection ()
208- by_sku = dict (
209- ( product_data ["sku" ], product_data ) for product_data in self .PRODUCTS
210- )
222+ collection = Product ._collection ()
223+ by_sku : dict [ str , dict [ str , Any ]] = {
224+ product_data ["sku" ]: product_data for product_data in self .PRODUCTS
225+ }
211226 for product in self .products :
212227 data = by_sku .get (product .sku , {})
213228 thumbnail_url = data .get ("thumbnail_url" )
@@ -220,9 +235,9 @@ def load_product_images(self):
220235 )
221236 product .thumbnail_url = thumbnail_url
222237 product .image_url = image_url
223- self .log (" + Applied Images: %s" % product .sku )
238+ self .log (f " + Applied Images: { product .sku } " )
224239
225- def _create_order (self , index , paid ) :
240+ def _create_order (self , index : int , paid : bool ) -> None :
226241 """
227242 Creates a single demo order with a random set of lines and,
228243 if requested, marks it as paid so that it shows up under the
@@ -233,7 +248,7 @@ def _create_order(self, index, paid):
233248 :param paid: Whether the order should end up in the paid state.
234249 """
235250
236- order = budy . Order ()
251+ order = Order ()
237252 order .save ()
238253
239254 lines_count = self .random .randint (2 , 4 )
@@ -245,10 +260,10 @@ def _create_order(self, index, paid):
245260 if self .random .random () < 0.35 :
246261 self ._add_line (order , product )
247262
248- address = budy . Address (
263+ address = Address (
249264 first_name = "Demo" ,
250- last_name = "Customer %d" % ( index + 1 ) ,
251- address = "Rua Demo %d" % ( index + 1 ) ,
265+ last_name = f "Customer { index + 1 } " ,
266+ address = f "Rua Demo { index + 1 } " ,
252267 city = "Lisboa" ,
253268 postal_code = "1000-001" ,
254269 country = "PT" ,
@@ -258,24 +273,23 @@ def _create_order(self, index, paid):
258273
259274 order .shipping_address = address
260275 order .billing_address = address
261- order .email = "demo%d@budy.test" % ( index + 1 )
276+ order .email = f "demo{ index + 1 } @budy.test"
262277 order .save ()
263278
264279 if not paid :
265280 self .log (
266- " + Created Order: %s (%d lines, unpaid) "
267- % ( order . reference , len (order .lines ))
281+ f " + Created Order: { order . reference } "
282+ f"( { len (order .lines )} lines, unpaid)"
268283 )
269284 return
270285
271286 order .mark_waiting_payment_s ()
272287 order .mark_paid_s ()
273288 self .log (
274- " + Created Order: %s (%d lines, paid)"
275- % (order .reference , len (order .lines ))
289+ f" + Created Order: { order .reference } " f"({ len (order .lines )} lines, paid)"
276290 )
277291
278- def _add_line (self , order , product ) :
292+ def _add_line (self , order : Order , product : Product ) -> None :
279293 """
280294 Appends a new order line for the given product into the
281295 provided order, assigning a random quantity and size.
@@ -284,14 +298,14 @@ def _add_line(self, order, product):
284298 :param product: The product associated with the new line.
285299 """
286300
287- line = budy . OrderLine (quantity = float (self .random .randint (1 , 3 )))
301+ line = OrderLine (quantity = float (self .random .randint (1 , 3 )))
288302 line .product = product
289303 line .size = self .random .choice (self .SIZES )
290304 line .size_s = str (line .size )
291305 line .save ()
292306 order .add_line_s (line )
293307
294- def load_all_data (self ):
308+ def load_all_data (self ) -> bool :
295309 """
296310 Loads all demo data into the database, ensuring that
297311 dependencies are loaded in the correct order.
@@ -310,18 +324,18 @@ def load_all_data(self):
310324 self .log ("Demo Data Loading Complete!" )
311325 self .log ("=" * 60 )
312326 self .log ("\n Summary:" )
313- self .log (" - Products created: %d" % len (self .products ))
314- self .log (" - Orders created: %d" % self .orders_count )
327+ self .log (f " - Products created: { len (self .products )} " )
328+ self .log (f " - Orders created: { self .orders_count } " )
315329 return True
316330 except Exception as exception :
317- self .log ("Error loading demo data: %s" % exception , "ERROR" )
331+ self .log (f "Error loading demo data: { exception } " , "ERROR" )
318332 print_exc ()
319333 return False
320334 finally :
321335 self .stop_app ()
322336
323337
324- def parse_args ():
338+ def parse_args () -> Namespace :
325339 """
326340 Parses command line arguments.
327341 """
@@ -353,7 +367,7 @@ def parse_args():
353367 return parser .parse_args ()
354368
355369
356- def main ():
370+ def main () -> None :
357371 """
358372 Main entry point for the CLI.
359373 """
0 commit comments