4. Country Catalogue
Worth: 5%
DUE: Monday December 1, 2025 at 11:55pm; submitted on MOODLE.
Files:
asn4.ipynb/asn4.pyandcountry_data.csv
4.1. Task
The goal is to create a collection of Country objects. The collection, called a CountryCatalogue, will provide
functionality to store (add/remove) the Country objects in addition to making inquiries about the data in the
collection.
You will
Create a
Countryclass to store details about a countryCreate a
CountryCatalogueclassProvide a way to add and remove
CountryobjectsSearch through the catalogue
Ask questions about the data in the catalogue
Filter data in the catalogue
Use the written classes to build a
CountryCatalogueRead data from a file
Write data to a file
4.2. Provided Files
You are provided with
A notebook file called
asn4.ipynpcontaining the starting point of the assignmentThis file is to be uploaded to Google Colab
The notebook contains the start of the
CountryandCountryCatalogueclassesThe notebook contains unit tests for the
CountryandCountryCatalogueclassesThe notebook contains already written code that will make use of the classes you are to write
The notebook also includes a special if statement
if __name__ == "__main__":at the endThis is included to help with marking and unit tests
More details on this line are provided below
Alternatively, if you prefer to complete the assignment with an IDE on your own computer, you may download and use the
asn4.pyfile
A data file called
country_data.csvcontaining information about countries that will be used to populate theCountryCatalogue
Warning
Do not alter the function details in the provided .ipynb/.py files
Do not change the name of the functions
Do not remove the function description
Do not remove or add to the parameter list
4.3. Part 0 — Read the Assignment
Read the assignment description in its entirety before starting.
4.4. Part 1 — Uploading Files to Colab
After downloading the notebook and data files above, you will need to upload them to Colab to get started. See the respective section from assignment 1 for an example on how to do this. I recommend saving a copy of this notebook file and csv data file to your Google drive and then work with that one. You don’t have to, but you will have to re-upload the project every time you want to work on it.
4.5. Country Class
The Country class is simply going to represent an individual country. For our purposes, a Country will know its
name, continent, population, and land area. In addition to the attributes, a Country will also be
able to determine it’s population density (population/area). A method for determining equality (__eq__) and
generating a nice, human readable string representation of the Country object (__repr__) will be written.
4.5.1. Part 2 — Country Constructor
Write the constructor (__init__) for the Country class. The constructor will take a country name, which
continent it’s on, its population, and the total land area as parameters. The constructor will assign the
values passed as parameters to their respective attributes — name, continent, population, and area.
4.5.2. Part 3 — Population Density
Write a method population_density that returns the population density of the Country object. The population
density should be a float.
4.5.3. Part 4 — Equals and Repr
Write the __eq__ magic method for the Country class. For our purposes, two Country objects will be
considered equal if all their attributes are equal.
Write the __repr__ magic method for the Country class. For our needs, we will simply follow the pattern
ClassName(attribute=value, attribute=value, ...). For example, representing the country Canada as a string would
be Country(name=Canada, continent=North America, population=34207000, area=9976140.00).
4.5.4. Part 5 — Testing Country Class
To help ensure correctness, run the CountryTest class and ensure all unit tests pass. If any of the tests fail, read
which test failed and under which condition. The output of the tests will help guide your debugging.
To run the tests, run the cell in the notebook containing the following
# Run this cell to run all unit tests unittest.main(argv=[''], verbosity=2, exit=False)
4.6. Country Catalogue Class
The CountryCatalogue class holds reference to a collection of Country objects. Additionally, the
CountryCatalogue provides some functionality to ask questions about the collection of data.
The CountryCatalogue is effectively a list keeping track of the Country objects with additional proprietary
methods. Details on the functionality is provided below.
Although the description of this class is provided with an order and each part is numbered, one should feel free to
complete the methods in any order they see fit. For example, the __len__ magic method, which is described last, may
be helpful when writing the other methods. This may motivate one to write it earlier.
4.6.1. Part 6 — Country Catalogue Constructor
Write the constructor (__init__) for the CountryCatalogue class. The constructor for the class is simple —
initialize the object with an attribute assigned to a reference to an empty list. It is recommended to call the
attribute _catalogue. The underscore is included before since this attribute is not intended to be accessed directly
from outside the clas.
4.6.2. Part 7 — Private Find Method
Write a method _find that takes a reference to a Country object and returns the index of the first occurrence of
an equivalent Country within the catalogue. If no matching Country exists, the method will return -1.
This method is “private”, which means that it should not be accessed/used except from inside the object. In Python,
this “private” property is not enforced, but for methods or attributes that are intended to be “private”, the convention
is to start the method name with an underscore (_), thus the name _find.
4.6.3. Part 8 — Contains
Write a method called contains that takes a reference to a Country object as a parameter and returns True if
an equivalent Country object exists within the collection, and False otherwise.
4.6.4. Part 9 — Add
Write a method add that takes a Country object as a parameter and adds the provided Country to the
collection. In other words, append the provided Country to the CountryCatalogue object’s attribute referencing
a list. This method returns nothing.
4.6.5. Part 10 — Remove
Write a method remove that takes a Country object as a parameter and removes the first occurrence of an
equivalent Country object from the CountryCatalogue. This method returns a reference to the removed Country
object. If no equivalent Country object is found within the CountryCatalogue, then the method will raise a
ValueError exception.
4.6.6. Part 11 — Largest Density
Write a method country_with_largest_population_density that returns a reference to the Country object within the
CountryCatalogue that has the largest population density. If the CountryCatalogue is empty, this method will
raise an IndexError exception.
4.6.7. Part 12 — Smallest Density
Write a method country_with_smallest_population_density that returns a reference to the Country object within
the CountryCatalogue that has the smallest population density. If the CountryCatalogue is empty, this method
will raise an IndexError exception.
4.6.8. Part 13 — Filter by Density
Write a method filter_countries_by_population_density that takes a range of population density values as parameters
and returns a new CountryCatalogue object with references to Country objects that fall within the specified
population density range. The range specified will be \([low, high)\); the Country objects with a population
density greater-than or equal to the low and strictly less-than the high will be included in the filtered
CountryCatalogue. If no Country objects fall within the specified range, this method will return an empty
CountryCatalogue.
For example, calling some_catalogue.filter_countries_by_population_density(200, 250) would return a new
CountryCatalogue containing references to all the Country objects within some_catalogue that have a
population density \(\ge 200\) and \(< 250\).
4.6.9. Part 14 — Most Populous Continent
Write a method most_populous_continent that returns the name of the continent (as a string) that has the largest
population based on information within the CountryCatalogue. If the the CountryCatalogue is empty, this method
raises an IndexError exception.
This method will only consider the Country objects contained within the CountryCatalogue. In other words,
although Asia has a large population, if no Country objects from Asia were included in the CountryCatalogue,
then those populations are not considered in the calculation.
Further, this method should work on any arbitrary planet within our universe that may have unusual continent names (do not hard code any details about continents based on Earth).
Hint: Consider using a dictionary within this method to help with determining each continent’s population.
4.6.10. Part 15 — Equals, Repr, get item, and Length
Write the __eq__ magic method for the CountryCatalogue class. For our purposes, two CountryCatalogue objects
will be considered equal if their attributes (list of Country objects) are equal.
Write the __repr__ magic method for the CountryCatalogue class. For our needs, the string should be an aggregate
of each individual Country object’s string representation, each on their own line. For example
Country(name=Canada, continent=North America, population=34207000, area=9976140.00) Country(name=China, continent=Asia, population=1339190000, area=9596960.00) Country(name=Egypt, continent=Africa, population=93383574, area=1000000.00) Country(name=France, continent=Europe, population=64668129, area=541656.76)
Write the __getitem__ magic method for the CountryCatalogue class. This method takes an index as a parameter and
returns a reference to the Country object at ths specified index. For more details on this method,
see the relevant documentation.
Write the __len__ magic method for the CountryCatalogue class. This method returns the number of Country
objects stored within the CountryCatalogue.
4.6.11. Part 16 — Testing Country Catalogue Class
To help ensure correctness, run the CountryCatalogueTest class and ensure all unit tests pass. If any of the tests
fail, read which test failed and under which condition. The output of the tests will help guide your debugging.
To run the tests, run the cell in the notebook containing the following
# Run this cell to run all unit tests unittest.main(argv=[''], verbosity=2, exit=False)
4.7. Part 17 — Putting it Together
The main portion of the code that was provided is what puts everything together. This code
Opens a file and loads the data into a
CountryCatalogueMakes changes to the contents of the
CountryCatalogueAsks questions of the data in the
CountryCatalogueFilters the
CountryCataloguebased on population densitySaves the filtered data to a file
If everything was implemented correctly, this code should run with no issue. Although no unit tests are provided for this portion of code, you can likely determine if everything worked correctly by checking the output of the program.
4.8. Part 18 — Testing
Unlike previous assignments, no assertion tests are provided. Instead, to help ensure that your program is correct, run the provided unittests. There is no guarantee that if your code passes all the tests that you will be correct, but it certainly helps provide peace of mind that things are working as they should.
There are no unittests for the main portion of the assignment discussed in the previous part.
Realistically you should have been running tests after you complete each of the above parts, but this part is here to remind you. Remember, we are lucky that we get to test our solutions for correctness ourselves; you don’t need to wait for the marker to return your assignment before you have an idea of if it works correctly.
To run the tests, run the cell in the notebook containing the following
# Run this cell to run all unit tests unittest.main(argv=[''], verbosity=2, exit=False)
4.9. Some Hints
Work on one function at a time
Get each function working perfectly before you go on to the next one
Test each function as you write it
This is a really nice thing about programming; you can call your functions and see what result gets returned
Mentally test before you even write — what does this function do? What problem is it solving?
If you need help, ask
Drop by office hours
4.10. Some Marking Details
Warning
Just because your program produces the correct output, that does not necessarily mean that you will get perfect, or even that your program is correct.
Below is a list of both quantitative and qualitative things we will look for:
Correctness?
Did you follow instructions?
Comments?
Variable Names?
Style?
Did you do just weird things that make no sense?
4.11. What to Submit to Moodle
Make sure your NAME and STUDENT NUMBER appear in a comment at the top of the program
Submit your version of
asn4.pyto MoodleDo not submit the .ipynb file
To get the
asn4.pyfile from Colab, see the example image in Assignment 1
Warning
Verify that your submission to Moodle worked. If you submit incorrectly, you will get a 0.