Sprint Challenge: Software Engineering

Sprint Challenge Overview

This sprint challenge will assess your understanding of the concepts covered throughout this sprint on Software Engineering. You'll demonstrate your ability to create Python modules, apply object-oriented programming principles, write clean code following PEP 8 standards, and implement comprehensive testing for your applications.

Challenge Instructions

Software Engineering - the Acme Way

Introduction

In this sprint challenge you will write code to demonstrate competency in writing your own Python modules, object-oriented programming, code style, and testing. You may use any tools and references you wish, but your final code should reflect your own work and be saved in .py files (not notebooks).

For all your code, you may only import/use the following:

 

Part 1 - Keeping it Classy

As an employee of Acme Corporation, you're always looking for ways to better organize the vast quantities and variety of goods your company manages and sells. Everything Acme sells is considered a "Product", and must have the following attributes (variables that live "inside" the class):

  • name (string with no default)
  • price (integer with default value 10)
  • weight (integer with default value 20)
  • flammability (float with default value 0.5)
  • identifier (integer – a randomly generated number from a uniform distribution ranging from 1000000 to 9999999.) Both ends of this range are inclusive, meaning that it should be possible for the random generation to result in exactly 1000000 or 9999999 (although the probability of either of these being chosen is very small)

Write a Python class to model the above data. Make sure you are precise in
your field names and types, and that your class has an __init__ constructor
method with appropriate defaults (or lack thereof).

Save the class in a file titled acme.py, and you can test your code in a Python REPL as
follows:
>>> from acme import Product
>>> prod = Product('A Cool Toy')
>>> prod.name
'A Cool Toy'
>>> prod.price
10
>>> prod.weight
20
>>> prod.flammability
0.5
>>> prod.identifier
2812086 # your value will vary

Part 2 - Objects that Go!


The class you wrote in part 1 is nice, but it doesn't do anything –that is, it doesn't have any methods. So let's add some! Add the following two methods:

  • stealability(self) - calculates the price divided by the weight, and then returns a message:
    • if the ratio is less than 0.5 return "Not so stealable..."
    • if it is greater or equal to 0.5 but less than 1.0 return "Kinda stealable."
    • otherwise return "Very stealable!"
  • explode(self) - calculates the flammability times the weight, and then returns a message:
    • if the product (result of the multiplication operation) is less than 10 return "...fizzle."
    • if it is greater or equal to 10 but less than 50 return "...boom!"
    • and otherwise return "...BABOOM!!"

Save your code, and you can test as follows:

>>> from acme import Product
>>> prod = Product('A Cool Toy')
>>> prod.stealability()
'Kinda stealable.'
>>> prod.explode()
'...boom!'

Part 3 - A Proper Inheritance


Of course, Acme doesn't just sell generic products - it sells all sorts of special specific things!

Make a child class called BoxingGlove that inherits from Product named BoxingGlove and does the following:

Example test to run in a REPL:
>>> from acme import BoxingGlove
>>> glove = BoxingGlove('Punchy the Third')
>>> glove.price
10
>>> glove.weight
10
>>> glove.punch()
'Hey that hurt!'
>>> glove.explode()
"...it's a glove."

Part 4 - Class Report

Now that you can represent your inventory as Product and BoxingGlove objects, let's use these classes to write an acme_report.py module (Python file) to generate random products and print a summary of them. For the purposes of these functions we will only use the Product class.

Your module should include two functions:


For the purposes of generation, "random" means uniform - all possible values should vary uniformly (have the same likelihood of being chosen) across the following possibilities:


Please use the random module from the Python standard library to assist you in generating the above values. Since the random module is included in the Python standard library, you shouldn't need to install anything in order to use it, you can import it at the top of your file without having to do anything else.
You will also need to import your Product class from acme.py. You will want to generate a set of random values and then pass those values as parameters to the Product() class constructor function. This function will return back to you a new product object that you can append to a list. You will want to do this many times over, so a for loop might help you repeat this process as many times as is required.
CodeGrade will try and pass in a different number of products (different than 30) to your generate_products() function to override the default value, so don't forget to include the default parameter.

For the inventory_report(), you should calculate the following values in regards to the product list generated by your generate_products() function:

Once you have calculated these values, combine the four numbers into a tuple and return the tuple from the function.

 

The following is useful starting code for acme_report.py:
import random
from acme import Product 

# Useful to use with random.sample or random.choice to generate names
ADJECTIVES = ['Awesome', 'Shiny', 'Impressive', 'Portable', 'Improved']
NOUNS = ['Anvil', 'Catapult', 'Disguise', 'Mousetrap', '???']

def generate_products(num_products=30):
    products = []
    # TODO - your code! Generate and add random products to the list
    return products

def inventory_report(products):
    pass # TODO - your code! Use the products list to calculate the report.
    
if __name__ == '__main__':
    print(inventory_report(generate_products()))

The last lines let you test by running `python acme_report.py`. You should see
output like:

$ python acme_report.py
(19, 56.8, 54.166666666666664, 1.258097155966675)

Hint - a great way to figure out how many unique things you have is to use a set (a collection where all items are unique, and inserting an existing item just doesn't do anything).

>>> s = set()
>>> s.add(1)
>>> s.add(2)
>>> s
{1, 2}
>>> s.add(3)
>>> s.add(1)
>>> s
{1, 2, 3}
>>> len(s)
3
You can also take a list of items and cast it to a set to remove any duplicates.
>>> my_list = [1,3,4,2,4,3,2,3]
>>> my_set = set(my_list)
>>> my_set
{1, 2, 3, 4}

Part 5 - Measure twice, Test once


Make a file acme_test.py starting from the following code:
import pytest
from acme import Product
from acme_report import generate_products, ADJECTIVES, NOUNS

def test_default_product_price():
    '''Test default product price being 10.'''
    prod = Product('Test Product')
    assert prod.price == 10
Complete the following:


Part 6 - Style it Up


If you did the earlier parts in a text editor that had a Python linter enabled and you followed the linter's advice, then you're likely already done with this step. Once you have submitted your work, CodeGrade you will give you additional on any PEP8 style improvements.

If not, go back and fix things! If you don't have a built-in tool for checking,
you can use the PEP8 Style Guide.

Part 7 - Turn it in!


Provide submit the following files:

Await feedback from Acme Corporation management. Thanks for your hard work!

Bonus! 
Got this far? Read up on the history of the fine Acme Corporation, with decades of quality products and many satisfied customers (mostly coyotes).

Challenge Expectations

The Sprint Challenge is designed to test your mastery of the following key concepts:

What to Expect

In this sprint challenge, you'll apply everything you've learned about software engineering to build a complete Python application for Acme Corporation. This challenge will test your ability to:

Remember to demonstrate your understanding of the concepts from all four modules in this sprint!

Sprint Challenge Resources

Object-Oriented Programming

Testing

Code Style and Standards

Python Standard Library