Exemplo n.º 1
0
 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
Exemplo n.º 2
0
    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)
Exemplo n.º 3
0
 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)
Exemplo n.º 4
0
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))
Exemplo n.º 5
0
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()