def dfs(self, starting_vertex, destination_vertex): """ Return a list containing a path from starting_vertex to destination_vertex in depth-first order. """ # create an empty stack and push a list containing the starting vertex stack = Stack() stack.push([starting_vertex]) # create a set to store the visited vertices visited = set() # while the stack is not empty while not stack.is_empty(): # pop to the path path = stack.pop() # set a vertex to the last item in the path vertex = path[-1] # if that vertex has not been visited if vertex not in visited: # if vertex is equal to target value if vertex == destination_vertex: # return path return path # mark vertex as visited visited.add(vertex) # loop over next vertex in the set of vertices for the current vertex for next_vertex in self.vertices[vertex]: # set a new path equal to a new list of the path new_path = list(path) # append next vertex to new path new_path.append(next_vertex) # push the new path stack.push(new_path) # return None if it breaks out of the while loop return None
def dft(self, starting_vertex): """ Print each vertex in depth-first order beginning from starting_vertex. """ # Validate parameter: is the passed vertex valid? if starting_vertex not in self.vertices: # vertex not found, nothing to do print("vertex {vtx} not found, nothing to do".format( vtx=starting_vertex)) return False # Define a vertex search queue - "vertexes to search" vert_stack = Stack() # Define a vertex search status map - "status of the vertex's search" vert_status = {} # Set the search status for each vertex as "not_started" for vtx in self.vertices: vert_status[vtx] = "search_not_started" # Place the start vertex in our stack vert_stack.push(starting_vertex) # Process while there are vertices in the stack while not vert_stack.is_empty(): # Pop the vertex at the top of the stack tmp_vtx = vert_stack.pop() # Indicate we have started the search on the popped vertex vert_status[tmp_vtx] = "search_started" # Print out the vertex print(tmp_vtx) # Indicate we have completed the search on the popped vertex vert_status[tmp_vtx] = "search_completed" # Push the current vertex's child vertices if len(self.vertices[tmp_vtx]) != 0: # Push this vertex's children on the stack lst_set = list(self.vertices[tmp_vtx]) lst_set.reverse() for v_elm in lst_set: # Has this vertex been processed? if vert_status[v_elm] != "search_not_started": # This vertex has already been processed - skip continue # Vertex to be processed, push on the stack vert_stack.push(v_elm)
def dft(self, starting_vertex): """ Print each vertex in depth-first order beginning from starting_vertex. """ # create an empty stack and push the starting vertex stack = Stack() stack.push(starting_vertex) # create a set to store the visited vertices visited = set() # while the stack is not empty while not stack.is_empty(): # pop the first vertex v = stack.pop() # if that vertex has not been visited if v not in visited: # mark it as visited and print for traversal visualization visited.add(v) print(v) # then push all of its direct neighbour(s) for next_vertex in self.vertices[v]: stack.push(next_vertex)
class RESTServer(HTTPServer): def __init__(self, config, **kwargs): addr = ("", config["port"]) super().__init__(addr, RequestHandler, **kwargs) self.endpoints = [] self.plugins = [] self.load_plugins() self._endpoints_to_register = None self._errors = Stack() self._error_lock = Lock() logging.info("Running server.") try: self.serve_forever() except KeyboardInterrupt: self.shutdown() def load_plugins(self): # import for el in pkgutil.iter_modules([PLUGINDIR]): plugin = el[1] try: p = pkgutil.importlib.import_module("{}.{}".format( PLUGINDIR, plugin)) except Exception as e: logging.error("Unable to load plugin: {} ({})".format( plugin, e)) continue else: self.plugins.append(p) # load failed = [] for i in range(len(self.plugins)): module = self.plugins[i] try: self._endpoints_to_register = [] plugin = module.Plugin(self) logging.info("Loaded Plugin: {}".format(plugin.name)) except (AttributeError, TypeError, Exception) as e: failed.append(module) logging.error("Unable to load plugin: {} ({})".format( module, e)) continue self.plugins[i] = plugin for endpoint in self._endpoints_to_register: self.endpoints.append((endpoint, plugin)) logging.info("Registered endpoint: {}".format(endpoint.path)) self._endpoints_to_register = None for el in failed: self.plugins.remove(el) def match_endpoints(self, path): """ Finds the endpoint that matches best with path. If path is "/a/b/c", it matches "/a/b" better than "/a". It does not match "/b". :param path: path that is to be matched :return: endpoint object that matches; None if no match is found """ path = sanitize_path(path).split("/") candidates = [] for el in self.endpoints: candidates.append(el[0]) matches = [] todel = [] # comparison loop for i in range(len(path)): if not candidates: break for el in candidates: if len(el.pathlist) == i: matches.append(el) todel.append(el) elif el.pathlist[i] != path[i]: todel.append(el) elif i == len(el.pathlist) - 1: matches.append(el) for el in todel: candidates.remove(el) todel = [] if not matches: return None # get best match best = matches[0] for el in matches: if len(el.pathlist) > len(best.pathlist): best = el return best def register_endpoint(self, endpoint): """ Registers and endpoint. :param endpoint: Endpoint object """ if self._endpoints_to_register is None: logging.error( "Endpoints must be registered in the Plugin constructor ({})". format(endpoint.path)) return if endpoint not in self.endpoints and endpoint not in self._endpoints_to_register: self._endpoints_to_register.append(endpoint) else: logging.error("Endpoint already registered: {}".format( endpoint.path)) def report_error(self, endpoint, msg, timestamp=None): """ Reports an error to the server error stack. :param endpoint: Endpoint object the error occured in. :param msg: Error message. :param timestamp: Error timestamp; uses now if ommited. :return: """ error = Error(endpoint, msg, timestamp) self._error_lock.acquire() self._errors.push(error) self._error_lock.release() def consume_errors(self): """ Generator for all errors on the server error stack. Errors are removed from the stack (popped). """ self._error_lock.acquire() while True: try: yield self._errors.pop() except IndexError: break self._error_lock.release() def consume_error(self): """ Pops one error from the server error stack (read and remove). :return: Last error """ self._error_lock.acquire() r = self._errors.pop() self._error_lock.release() return r def has_error(self): return not self._errors.is_empty() def last_error(self): """ Reads the last error from the error stack. Does not remove it. :return: Last error """ self._error_lock.acquire() r = self._errors.top() self._error_lock.release() return r def shutdown(self): for plugin in self.plugins: try: plugin.shutdown() except AttributeError: logging.info( "Plugin {} has no shutdown method.".format(plugin)) pass except Exception as e: logging.error("Plugin {} failed to shut down ({})".format( plugin, e)) logging.info("Shutting down.") try: self.shutdown() except Exception as e: logging.error("Clean shutdown failed ({})".format(e))
class User: """ User class serves as an abstraction for users. Users are only allowed to shop at only one store. User instances are treated as regular users. """ ##### Part 4.1 ##### user_counter = 0 def __init__(self, name, store): """ Constructor for User instances. Each instance is initialized with the user's username and the store they shop at. Instance attributes are: name, store, balance, their user ID, purchase history, and shopping cart. """ # YOUR CODE GOES HERE # self.name = name self.store = store self.balance = 0 self.id = User.user_counter User.user_counter += 1 self.purchase_history = Stack() self.cart = Queue() self.store.add_user(self) def __str__(self): """ Return the string representation as: "standard user: {name} - {balance}$" """ # YOUR CODE GOES HERE # return "standard user: {} - {}$".format(self.name, self.balance) def __repr__(self): """ Return the string representation as: "USER<{id}>" """ # YOUR CODE GOES HERE # return "USER<{}>".format(self.id) def set_name(self, new_name): """ Replaces a user's old name to new_name """ # YOUR CODE GOES HERE # self.name = new_name def get_name(self): """ Returns the user's current name """ # YOUR CODE GOES HERE # return self.name def set_balance(self, amount): """ Set the user's current balance to the given amount """ # YOUR CODE GOES HERE # self.balance = amount def get_balance(self): """ Returns the user's current balance """ # YOUR CODE GOES HERE # return self.balance def add_balance(self, amount): """ Add the given amount to the current balance """ # YOUR CODE GOES HERE # self.balance += amount def last_purchase(self): """ Return the user's most recent purchase """ # YOUR CODE GOES HERE # return self.purchase_history.peek() def view_history(self): """ Print the user's entire purchase history """ # YOUR CODE GOES HERE # print(self.purchase_history) def view_cart(self): """ Print all items in the user's cart """ # YOUR CODE GOES HERE # print(self.cart) def clear_cart(self): """ Remove all items from the user's cart """ # YOUR CODE GOES HERE # self.cart = Queue() ##### Part 5.2 ##### def add_cart(self, product_id): """ Add the product with the given product id to the user's cart """ # YOUR CODE GOES HERE # item = self.store.get_product(product_id) if item == None: pass else: self.cart.enqueue(item) def checkout(self): """ Purchase all items in the user's cart and return a list of all purchased products. As soon as a product cannot be purchased, purchasing is stopped. Anything that was purchased successfully is returned in a list. """ # YOUR CODE GOES HERE # purchases = [] while not(self.cart.is_empty()): product = self.cart.peek() purchase = self.store.order(self.id, product.id) if purchase: self.cart.dequeue() purchases.append(purchase.product) self.purchase_history.push(purchase) else: break return purchases ##### Part 5.3 ##### def undo_purchase(self): """ Undo the user's most recent purchase. If there is no shopping history, print "USER: no purchase history" and do nothing else. Else, attempt to undo the purchase. If the store allows the request, remove that purchase from the user's purchase history. """ # YOUR CODE GOES HERE # if self.purchase_history.is_empty(): print("USER: no purchase history") else: last_purchase = self.purchase_history.peek() user = last_purchase.user user_id = user.id product = last_purchase.product request = self.store.undo_order(user_id, product) if request: user.purchase_history.pop()