0% found this document useful (0 votes)
5 views35 pages

Python OOP: Modules and Inheritance

Uploaded by

sgavon
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views35 pages

Python OOP: Modules and Inheritance

Uploaded by

sgavon
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Foundations of Programming

(Python)
by Dirk Biesinger

Module 09 of 10
Introduction
In the last module we worked with objects. Almost all programs so far have worked with single objects. This is a good
way to get started with OOP. The true power of OOP lies in objects working together.

In this Module, we’ll work with modules (no pun intended). Modules are a way to organize classes and functions. We’ll
also look how to inherit from one class into another. We’ll look at documenting the relationship using UML.

• We’ll create objects of different classes in the same program.


• Allow objects to communicate with each other.
• Derive new classes from existing ones.
• Create more complex objects by combining simpler ones.
• Extend the definition of existing classes.
• Override method definitions of existing classes.

We will be using spyder as our IDE.

Index
Module 09 of 10 ...................................................................................................................................................................... 1
Introduction ........................................................................................................................................................................ 1
Index.................................................................................................................................................................................... 1
Modules .............................................................................................................................................................................. 2
Importing Modules ......................................................................................................................................................... 2
The Main Module ................................................................................................................................................................ 4
The __name__ System Variable...................................................................................................................................... 4
Organizing Modules ............................................................................................................................................................ 5
Testing Code........................................................................................................................................................................ 9
LAB 09-A ............................................................................................................................................................................ 11
Classes and Modules for the greater Good! ..................................................................................................................... 12
CD class: ........................................................................................................................................................................ 12
Track Class: .................................................................................................................................................................... 12
IO Screen Class: ............................................................................................................................................................. 12
IO File Class: .................................................................................................................................................................. 12
Main file: ....................................................................................................................................................................... 12
Processing classes: ........................................................................................................................................................ 12
LAB 09-B: ........................................................................................................................................................................... 13

Module 09 Page 1
Inheritance ........................................................................................................................................................................ 15
UML (UNIFIED MODELING LANGUAGE): ........................................................................................................................... 17
Summary ........................................................................................................................................................................... 18
Appendix: .......................................................................................................................................................................... 19
Sample solution for LAB09-A ........................................................................................................................................ 19
Sample solution LAB09-B .............................................................................................................................................. 24
Note: Put effort into the Labs; they will come in handy in the assignment!

Modules
Modules are a way to organize code. Same as classes and functions, modules make your code easier to organize, read
and re-use! Modules contain classes and functions. Each module can have many classes, just as each class can have
many methods. The following listing shows a principle module.

Listing 1 - Modules 1

Creating a Module is very similar to creating a regular script: The main difference is that a module script is not run
directly. Instead, code from modules is being used indirectly from another script.

Importing Modules
The import command is used in order to make a module script available in a script. Using the syntax

• import module_name makes the module available under the synonym module_name
• import module_name as mn makes the module available under the alias mn.

Module 09 Page 2
Listing 2 - Modules 2

Figure 1 - Modules 2

Listing 3 - Modules 3

Figure 2 - Modules 3
Module 09 Page 3
On an import statement, Python first searches for the module in the current working directory followed by registered
modules and directories, followed by directories in the system environment. For this course, we will be only using the
current working directory variant.

The Main Module


Python applications (programs) often uses two or more files. However, typically only one file is run directly. Any script
run directly at the start of a program is called the “main” module.

The __name__ System Variable


The system variable __name__ returns the name of the module on which level it is executed. In the main script, it
returns ‘__main__’. Inside a module, it returns the module name.

Checking that the __name__ system variable equals __main__ is synonymous with running the script as the main
executed script. Or, you can use this to raise an error if a module file is being executed as the main script.

Listing 4 - Modules 4 module script

Module 09 Page 4
Listing 5 - Modules 4 module script - Modules 4 main script

Figure 3 - Modules 4

Trying to run the module script results in an error message:

Figure 4 - Modules 4 - run module script

Upon importing a module, python automatically creates a ‘__pycache__’ folder. In this folder, you’ll find a binary version
of your Python code. If you delete this file, it will be re-created when you run your code the next time.

Note: please exclude the __pycache__ folder from your assignment submissions.

Organizing Modules
Often, Modules hold classes or functions organizing tasks around data, processing or presentation (separation of
concerns). The following is a listing showing a module designed for data:

Module 09 Page 5
1. #------------------------------------------#
2. # Title: Data Classes
3. # Desc: A Module for Data Classes
4. # Change Log: (Who, When, What)
5. # DBiesinger, 2030-Jan-01, Created File
6. #------------------------------------------#
7.
8. if __name__ == '__main__':
9. raise Exception('This file is not meant to ran by itself')
10.
11. class CD:
12. """Stores data about a CD:
13.
14. properties:
15. cd_id: (int) with CD ID
16. cd_title: (string) with the title of the CD
17. cd_artist: (string) with the artist of the CD
18. methods:
19. get_record() -> (str):
20.
21. """
22. # -- Constructor -- #
23. def __init__(self, cd_id: int, cd_title: str, cd_artist: str) -> None:
24. """Set ID, Title and Artist of a new CD Object"""
25. # -- Attributes -- #
26. try:
27. self.__cd_id = int(cd_id)
28. self.__cd_title = str(cd_title)
29. self.__cd_artist = str(cd_artist)
30. except Exception as e:
31. raise Exception('Error setting initial values:\n' + str(e))
32.
33. # -- Properties -- #
34. # CD ID
35. @property
36. def cd_id(self):
37. return self.__cd_id
38.
39. @cd_id.setter
40. def cd_id(self, value):
41. try:
42. self.__cd_id = int(value)
43. except Exception:
44. raise Exception('ID needs to be Integer')
45.
46. # CD title
47. @property
48. def cd_title(self):
49. return self.__cd_title
50.
51. @cd_title.setter
52. def cd_title(self, value):
53. try:
54. self.__cd_title = str(value)
55. except Exception:
56. raise Exception('Title needs to be String!')
57.
58. # CD artist
59. @property
60. def cd_artist(self):
61. return self.__cd_artist
62.
63. @cd_artist.setter
64. def cd_artist(self, value):
65. try:
66. self.__cd_artist = str(value)
67. except Exception:
Module 09 Page 6
68. raise Exception('Artist needs to be String!')
69. # TODone Add Code to the CD class
70.
71. def __str__(self):
72. """Returns: CD details as formatted string"""
73. return '{:>2}\t{} (by: {})'.format(self.cd_id, self.cd_title, self.cd_artist)
74.
75. def get_record(self):
76. """Returns: CD record formatted for saving to file"""
77. return '{},{},{}\n'.format(self.cd_id, self.cd_title, self.cd_artist)

Listing 6 - Data Module

The following is a listing of module with multiple classes designed for I/O:

1. #------------------------------------------#
2. # Title: IO Classes
3. # Desc: A Module for IO Classes
4. # Change Log: (Who, When, What)
5. # DBiesinger, 2030-Jan-01, Created File
6. #------------------------------------------#
7.
8. if __name__ == '__main__':
9. raise Exception('This file is not meant to ran by itself')
10.
11. import DataClasses as DC
12.
13. class FileIO:
14. """Processes data to and from file:
15.
16. properties:
17.
18. methods:
19. save_inventory(file_name, lst_Inventory): -> None
20. load_inventory(file_name): -> (a list of CD objects)
21.
22. """
23. @staticmethod
24. def save_inventory(file_name: str, lst_Inventory: list) -> None:
25. """
26.
27.
28. Args:
29. file_name (str): name of file that holds the data.
30. lst_Inventory (list): list of CD objects.
31.
32. Returns:
33. None.
34.
35. """
36.
37. try:
38. with open(file_name, 'w') as file:
39. for disc in lst_Inventory:
40. [Link](disc.get_record())
41. except Exception as e:
42. print('There was a general error!', e, e.__doc__, type(e), sep='\n')
43.
44. @staticmethod
45. def load_inventory(file_name: str) -> list:
46. """
47.
48.
49. Args:
50. file_name (str): name of file that holds the data.
51.
Module 09 Page 7
52. Returns:
53. list: list of CD objects.
54.
55. """
56.
57. lst_Inventory = []
58. try:
59. with open(file_name, 'r') as file:
60. for line in file:
61. data = [Link]().split(',')
62. row = [Link](data[0], data[1], data[2])
63. lst_Inventory.append(row)
64. except Exception as e:
65. print('There was a general error!', e, e.__doc__, type(e), sep='\n')
66. return lst_Inventory
67.
68. class ScreenIO:
69. """Handling Input / Output"""
70.
71. @staticmethod
72. def print_menu():
73. """Displays a menu of choices to the user
74.
75. Args:
76. None.
77.
78. Returns:
79. None.
80. """
81.
82. print('Menu\n\n[l] load Inventory from file\n[a] Add CD\n[i] Display Current Inventory')
83. print('[s] Save Inventory to file\n[x] exit\n')
84.
85. @staticmethod
86. def menu_choice():
87. """Gets user input for menu selection
88.
89. Args:
90. None.
91.
92. Returns:
93. choice (string): a lower case sting of the users input out of the choices l, a, i, d, s o
r x
94.
95. """
96. choice = ' '
97. while choice not in ['l', 'a', 'i', 's', 'x']:
98. choice = input('Which operation would you like to perform? [l, a, i, s or x]: ').lower().
strip()
99. print() # Add extra space for layout
100. return choice
101.
102. @staticmethod
103. def show_inventory(table):
104. """Displays current inventory table
105.
106.
107. Args:
108. table (list of dict): 2D data structure (list of dicts) that holds the data during
runtime.
109.
110. Returns:
111. None.
112.
113. """
114. print('======= The Current Inventory: =======')
115. print('ID\tCD Title (by: Artist)\n')
Module 09 Page 8
116. for row in table:
117. print(row)
118. print('======================================')
119.
120. @staticmethod
121. def get_CD_info():
122. """function to request CD information from User to add CD to inventory
123.
124.
125. Returns:
126. cdId (string): Holds the ID of the CD dataset.
127. cdTitle (string): Holds the title of the CD.
128. cdArtist (string): Holds the artist of the CD.
129.
130. """
131.
132. cdId = input('Enter ID: ').strip()
133. cdTitle = input('What is the CD\'s title? ').strip()
134. cdArtist = input('What is the Artist\'s name? ').strip()
135. return cdId, cdTitle, cdArtist

Listing 7 – IO Module

The following depicts a module designed for Data Processing:

1. #------------------------------------------#
2. # Title: Processing Classes
3. # Desc: A Module for processing Classes
4. # Change Log: (Who, When, What)
5. # DBiesinger, 2030-Jan-01, Created File
6. #------------------------------------------#
7.
8. if __name__ == '__main__':
9. raise Exception('This file is not meant to ran by itself')
10.
11. import DataClasses as DC
12.
13. class DataProcessor:
14. """Processing the data in the application"""
15. @staticmethod
16. def add_CD(CDInfo, table):
17. """function to add CD info in CDinfo to the inventory table.
18.
19.
20. Args:
21. CDInfo (tuple): Holds information (ID, CD Title, CD Artist) to be added to inventory.
22. table (list of CD Objects): 2D data structure (list of CD Objects) that holds the data du
ring runtime.
23.
24. Returns:
25. None.
26.
27. """
28.
29. cdId, title, artist = CDInfo
30. cdId = int(cdId)
31. row = [Link](cdId, title, artist)
32. [Link](row)

Listing 8 - DataProcessing Module

Testing Code
Typically, modules (and classes / functions) are tested as they are created. It is a good practice (and preparation for test
driven development) is, to create a Test Harness. This is script that is run directly and uses specific testcases against the
Module 09 Page 9
Modules, Classes and Functions. A test harness can be kept with the project and re-run easily whenever changes are
made / the programmer wants to ascertain that the functionality is given.

1. #------------------------------------------#
2. # Title: Test Harness
3. # Desc: A Module to test the Modules
4. # Change Log: (Who, When, What)
5. # DBiesinger, 2030-Jan-01, Created File
6. #------------------------------------------#
7.
8. import DataClasses as DC
9. import ProcessingClasses as PC
10. import IOClasses as IO
11.
12. lstOfCDObjects = []
13.
14. print('\n\nTesting CD class')
15. print([Link].__doc__)
16. cd1 = [Link](1, 'test_title', 'cd_artist')
17. print(cd1)
18. [Link](cd1)
19.
20. print('\n\nTesting of class FileIO')
21. file_name = '[Link]'
22. [Link].save_inventory(file_name, lstOfCDObjects)
23. print([Link].load_inventory(file_name))
24.
25. print('\n\nTesting IO class')
26. [Link].print_menu()
27. print('selection in menu: {}'.format([Link].menu_choice()))
28. print('Inventory:')
29. [Link].show_inventory(lstOfCDObjects)
30. cd2 = [Link](2, 'test_title_2', 'cd_artist_2')
31. [Link](cd2)
32. print('Inventory:')
33. for item in lstOfCDObjects:
34. print(item)
35.
36. print('\n\nTesting Processing Classes')
37. [Link].add_CD((3, 'Foreigner', 'Foreigner'), lstOfCDObjects)
38. print('Inventory:')
39. for item in lstOfCDObjects:
40. print(item)

Listing 9 - Test Harness

Which results in the following output:

Module 09 Page 10
Figure 5 - output of Test Harness

LAB 09-A
In this Lab, you’ll create multiple modules that work together. We’ll re-implement the functionality of last module’s
assignment using modules. You’ll also add a test harness to test your modules.

Note: You do not need to type all the code. You can re-purpose code from last week’s assignment.

Important: create a sub-directory Mod09_A in your _FDProgramming directory for this. (will get important in the next
step!)
Module 09 Page 11
1. Create a script called ‘[Link]’
2. Create a script module ‘[Link]’
3. Add the code in listing 6 to the [Link] script.
4. Add code to your [Link] script to test your [Link] script
5. Create a script module ‘[Link]’
6. Add the code in listing 7 to the [Link] script
7. Add code to your [Link] script to test your [Link] script
8. Create a script module ‘[Link]’
9. Add the code in listing 8 to the [Link] script
10. Add code to your [Link] script to test your [Link] script
11. Create a script ‘[Link]’
12. Add code to your script to run the application (former main section)
13. Ensure that all test cases in the test harness work
14. Ensure that all functionality in the application work.

Classes and Modules for the greater Good!


The real power of OOP comes from the use of objects to organize your data, logic and code. The explore this, we will be
adding the class we created in LAB08_E to our application. This class holds info about CD / Album tracks. Now in order to
be able to make full use of this, we need to incorporate several changes / additions:

CD class:
- The attributes need to be extended to store the tracks
- A method to add tracks
- A method to delete tracks
- A method to sort tracks by position
- A method to display album data including tracks
- A method to print track info for saving

Track Class:
- Add the class

IO Screen Class:
- Add a menu item to select a CD / Album and offer a sub menu
- Sub menu needs to allow adding, deleting and displaying of track info and exit back to main menu

IO File Class:
- Change the csv file format to accommodate the changed data structure. This can be either by adding a second
csv for the track info or by saving the data as pickle.

Main file:
- Changing the logic to allow sub menu

Processing classes:
- Add processing of selecting a CD / Album
- Add processing of adding a track

As you can see, this is a lot. Let’s have a look at some fundamentals:

Saving the data can be done in two ways we have covered so far: pickling the complete main table and save it binary or
‘treating’ every data row and save it as plain text in a human readable file. For this project, we choose the latter:

Module 09 Page 12
Data is to be saved in two csv files: One for the CD / Album info (uses csv format). One for track info (needs to include
for each row a reference to the CD / Album it is linked to (uses csv format).

This sounds like more work, so why do it this way? Multiple reasons:

- This approach works fine for now using two csv files. If this application evolves, it is easy to save the data into a
database without changing the preparation / formatting of the data.
- It is easy to do “bulk entry” into these files. You couldn’t do that with pickles.

Note: Make a copy of your LAB09-A folder (Mod09_A) and save it as Mod09_B.

Important Note: Due to python’s internal optimization, make sure to close all files in the _A folder and restart your
kernel. Otherwise, you will see the code reloaded from the previous files. This is due to us re-using the same file names
and class names, so python assumes it to be the same files. To force a reload off the right files, restarting the kernel
flushes out all information.

LAB 09-B:
I included a LAB 09-B starter code. Solve the TODOs to make the application work as described above.

(A sample solution is in the appendix, peek at your own risk)

The included TestHarness should produce an output like this:

Module 09 Page 13
Figure 6 - output Test Harness post LAB 09-B

Module 09 Page 14
Inheritance
So far, we have assumed that all CDs / Albums are by one artist. But what if we also have Compilation Albums? – We’d
need a different Data Type for the CD / Album as well as for the Track:

For the CD we would not have an artist, but a Genre or Publisher. For the Track we’d need to add the artist. Now instead
of re-inventing the wheel and making a copy of the existing class, we can re-use the existing class and expand on it. (We
will not be implementing this in a full version into our app, but rather discuss the principle.) I’ll be using the Track class
and expand it to a Compilation Track class:

We simply add the artist attribute to the Track class and can leave the rest of the attributes alone.

Our [Link] looks like this (limited to Track and CompTrack):

1. #------------------------------------------#
2. # Title: Data Classes
3. # Desc: A Module for Data Classes
4. # Change Log: (Who, When, What)
5. # DBiesinger, 2030-Jan-01, Created File
6. # DBiesinger, 2030-Jan-02, Modified to add Track class, added methods to CD class to handle tracks
7. # DBiesinger, 2030-Jan-03, Modified to add CompTrack class
8. #------------------------------------------#
9.
10. if __name__ == '__main__':
11. raise Exception('This file is not meant to run by itself')
12.
13. class Track():
14. """Stores Data about a single Track:
15.
16. properties:
17. position: (int) with Track position on CD / Album
18. title: (str) with Track title
19. length: (str) with length / playtime of Track
20. methods:
21. get_record() -> (str)
22.
23. """
24. # -- Constructor -- #
25. def __init__(self, pos, ttl, lgth):
26. # -- Attributes -- #
27. self.__position = pos
28. self.__title = ttl
29. self.__length = lgth
30.
31. # -- Properties -- #
32. # Track position
33. @property
34. def position(self):
35. return self.__position
36.
37. @[Link]
38. def position(self, value):
39. if type(value) == int:
40. if value < 1:
41. raise Exception('Position can\'t be less than 1!')
42. self.__position = value
43. else:
44. raise Exception('Position needs to be integer')
45.
46. # Track title
47. @property
48. def title(self):

Module 09 Page 15
49. return self.__title
50.
51. @[Link]
52. def title(self, value):
53. if type(value) == str:
54. self.__title = value
55. else:
56. raise Exception('Title needs to be string')
57.
58. # Track length
59. @property
60. def length(self):
61. return self.__length
62.
63. @[Link]
64. def length(self, value):
65. if type(value) == str:
66. self.__length = value
67. else:
68. raise Exception('Length needs to be string')
69.
70. # -- Methods -- #
71. def __str__(self):
72. """Returns Track details as formatted string"""
73. return '{:>2}. {} ({})'.format([Link], [Link], [Link])
74.
75. def get_record(self) -> str:
76. """Returns: Track record formatted for saving to file"""
77. return '{},{},{}\n'.format([Link], [Link], [Link])
78.
79.
80. class CompTrack(Track):
81. """Stores Data about a single Compilation Track:
82.
83. properties:
84. position: (int) with Track position on CD / Album
85. artist: (str) with Track artists
86. title: (str) with Track title
87. length: (str) with length / playtime of Track
88. methods:
89. get_record() -> (str)
90.
91. """
92.
93. # -- Constructor -- #
94. def __init__(self, pos, artist, ttl, lgth):
95. # -- Attributes -- #
96. super().__init__(pos, ttl, lgth)
97. self.__artist = artist
98.
99. # -- Properties -- #
100. # Track Artist
101. @property
102. def artist(self):
103. return self.__artist
104.
105. @[Link]
106. def artist(self, value):
107. if type(value) == str:
108. self.__artist = value
109. else:
110. raise Exception('Artist needs to be string')
111.
112. # -- Methods -- #
113. def __str__(self):
114. """Returns Track details as formatted string"""

Module 09 Page 16
115. return '{:>2}. {} by: {} ({})'.format([Link], [Link], [Link], [Link]
gth)
116.
117. def get_record(self) -> str:
118. """Returns: Track record formatted for saving to file"""
119. return '{},{},{},{}\n'.format([Link], [Link], [Link], [Link])

Listing 10 - DataClasses for Inheritance

A TestHarness for only the Track / CompTrack classes:

1. #------------------------------------------#
2. # Title: Test Harness
3. # Desc: A Module to test the Modules
4. # Change Log: (Who, When, What)
5. # DBiesinger, 2030-Jan-01, Created File
6.
7.
8. import DataClasses as DC
9.
10. trk1 = [Link](1, 'text.track1', '01:29')
11. trk2 = [Link](2, 'test.track2', '02:29')
12. trk3 = [Link](3, '[Link]', 'test.track3', '03:29')
13.
14. print(trk1)
15. print(trk2)
16. print(trk3)
17. print(trk1.get_record())
18. print(trk2.get_record())
19. print(trk3.get_record())
20. [Link] = '[Link]'
21. [Link] = 4
22. [Link] = 'verify.track3'
23. print(trk3)
24. print(trk3.get_record())

Listing 11 - TestHarness for DataClasses for Inheritance

which results in:

Figure 7 - TestHarness for DataClasses for Inheritance

UML (UNIFIED MODELING LANGUAGE):


As you can imagine, in order to plan a larger scale application, or to describe such an application, a standardized form
would be helpful. One such language is UML (Unified Modeling Language). It has been around for some time.

Module 09 Page 17
A good overview can be found here: [Link]

You can find more detailed information here: [Link]

We will not be diving deeper into this topic. I felt it important to mention it, so that you have heard about it, and have a
starting point in case you need it.

Summary
In this Module, we continued exploring Object Oriented Programming. We created objects of different classes in the
same program, allowed objects to communicate with each other. Derived new classes from existing ones. Created more
complex objects by combining simpler ones. Extended the definition of existing classes. Overrode method definitions of
existing classes.

We used spyder as our IDE.

At this point you should be able to answer the following questions from memory. For the ones you can’t, please review
the subject. It might help to imagine being asked these questions by a co-worker or in an interview setting.

• What is the difference between a class and module?


• What is the "main" module?
• What is the "__name__ " System Variable?
• How do you connect one module to another?
• What is class inheritance?

When you can answer all of these from memory, it’s time to complete the assignment and move to the next module.

1
[Link] retrieved 2020-Feb-16
2
[Link] retrieved 2020-Feb-16
Module 09 Page 18
Appendix:
Sample solution for LAB09-A
CD_Inventory.py

1. #------------------------------------------#
2. # Title: CD_Inventory.py
3. # Desc: main Application File
4. # Change Log: (Who, When, What)
5. # DBiesinger, 2030-Jan-01, Created File
6. #------------------------------------------#
7.
8. import ProcessingClasses as PC
9. import IOClasses as IO
10.
11. strFileName = '[Link]'
12. lstOfCDObjects = [Link].load_inventory(strFileName)
13.
14. while True:
15. [Link].print_menu()
16. strChoice = [Link].menu_choice()
17.
18. if strChoice == 'x':
19. break
20. if strChoice == 'l':
21. print('WARNING: If you continue, all unsaved data will be lost and the Inventory re-
loaded from file.')
22. strYesNo = input('type \'yes\' to continue and reload from file. otherwise reload will be can
celed. ')
23. if [Link]() == 'yes':
24. print('reloading...')
25. lstOfCDObjects = [Link].load_inventory(strFileName)
26. [Link].show_inventory(lstOfCDObjects)
27. else:
28. input('canceling... Inventory data NOT reloaded. Press [ENTER] to continue to the menu.')

29. [Link].show_inventory(lstOfCDObjects)
30. continue # start loop back at top.
31. elif strChoice == 'a':
32. tplCdInfo = [Link].get_CD_info()
33. [Link].add_CD(tplCdInfo, lstOfCDObjects)
34. [Link].show_inventory(lstOfCDObjects)
35. continue # start loop back at top.
36. elif strChoice == 'd':
37. [Link].show_inventory(lstOfCDObjects)
38. continue # start loop back at top.
39. elif strChoice == 's':
40. [Link].show_inventory(lstOfCDObjects)
41. strYesNo = input('Save this inventory to file? [y/n] ').strip().lower()
42. if strYesNo == 'y':
43. [Link].save_inventory(strFileName, lstOfCDObjects)
44. else:
45. input('The inventory was NOT saved to file. Press [ENTER] to return to the menu.')
46. continue # start loop back at top.
47. else:
48. print('General Error')

Listing 12 - Lab 09A CD_Inventory.py

[Link]:

1. #------------------------------------------#
2. # Title: Test Harness
3. # Desc: A Module to test the Modules
4. # Change Log: (Who, When, What)
Module 09 Page 19
5. # DBiesinger, 2030-Jan-01, Created File
6. #------------------------------------------#
7.
8. import DataClasses as DC
9. import ProcessingClasses as PC
10. import IOClasses as IO
11.
12. lstOfCDObjects = []
13.
14. print('\n\nTesting CD class')
15. print([Link].__doc__)
16. cd1 = [Link](1, 'test_title', 'cd_artist')
17. print(cd1)
18. [Link](cd1)
19.
20. print('\n\nTesting of class FileIO')
21. file_name = '[Link]'
22. [Link].save_inventory(file_name, lstOfCDObjects)
23. print([Link].load_inventory(file_name))
24.
25. print('\n\nTesting IO class')
26. [Link].print_menu()
27. print('selection in menu: {}'.format([Link].menu_choice()))
28. print('Inventory:')
29. [Link].show_inventory(lstOfCDObjects)
30. cd2 = [Link](2, 'test_title_2', 'cd_artist_2')
31. [Link](cd2)
32. print('Inventory:')
33. for item in lstOfCDObjects:
34. print(item)
35.
36. print('\n\nTesting Processing Classes')
37. [Link].add_CD((3, 'Foreigner', 'Foreigner'), lstOfCDObjects)
38. print('Inventory:')
39. for item in lstOfCDObjects:
40. print(item)

Listing 13 - Lab 09A [Link]

[Link]:

1. #------------------------------------------#
2. # Title: Data Classes
3. # Desc: A Module for Data Classes
4. # Change Log: (Who, When, What)
5. # DBiesinger, 2030-Jan-01, Created File
6. #------------------------------------------#
7.
8. if __name__ == '__main__':
9. raise Exception('This file is not meant to ran by itself')
10.
11. class CD:
12. """Stores data about a CD:
13.
14. properties:
15. cd_id: (int) with CD ID
16. cd_title: (string) with the title of the CD
17. cd_artist: (string) with the artist of the CD
18. methods:
19. get_record() -> (str):
20.
21. """
22. # -- Constructor -- #
23. def __init__(self, cd_id: int, cd_title: str, cd_artist: str) -> None:
24. """Set ID, Title and Artist of a new CD Object"""
25. # -- Attributes -- #
Module 09 Page 20
26. try:
27. self.__cd_id = int(cd_id)
28. self.__cd_title = str(cd_title)
29. self.__cd_artist = str(cd_artist)
30. except Exception as e:
31. raise Exception('Error setting initial values:\n' + str(e))
32.
33. # -- Properties -- #
34. # CD ID
35. @property
36. def cd_id(self):
37. return self.__cd_id
38.
39. @cd_id.setter
40. def cd_id(self, value):
41. try:
42. self.__cd_id = int(value)
43. except Exception:
44. raise Exception('ID needs to be Integer')
45.
46. # CD title
47. @property
48. def cd_title(self):
49. return self.__cd_title
50.
51. @cd_title.setter
52. def cd_title(self, value):
53. try:
54. self.__cd_title = str(value)
55. except Exception:
56. raise Exception('Title needs to be String!')
57.
58. # CD artist
59. @property
60. def cd_artist(self):
61. return self.__cd_artist
62.
63. @cd_artist.setter
64. def cd_artist(self, value):
65. try:
66. self.__cd_artist = str(value)
67. except Exception:
68. raise Exception('Artist needs to be String!')
69.
70. # -- Methods -- #
71. def __str__(self):
72. """Returns: CD details as formatted string"""
73. return '{:>2}\t{} (by: {})'.format(self.cd_id, self.cd_title, self.cd_artist)
74.
75. def get_record(self):
76. """Returns: CD record formatted for saving to file"""
77. return '{},{},{}\n'.format(self.cd_id, self.cd_title, self.cd_artist)

Listing 14 - Lab 09A [Link]

[Link]

1. #------------------------------------------#
2. # Title: IO Classes
3. # Desc: A Module for IO Classes
4. # Change Log: (Who, When, What)
5. # DBiesinger, 2030-Jan-01, Created File
6. #------------------------------------------#
7.
8. if __name__ == '__main__':
9. raise Exception('This file is not meant to ran by itself')
Module 09 Page 21
10.
11. import DataClasses as DC
12.
13. class FileIO:
14. """Processes data to and from file:
15.
16. properties:
17.
18. methods:
19. save_inventory(file_name, lst_Inventory): -> None
20. load_inventory(file_name): -> (a list of CD objects)
21.
22. """
23. @staticmethod
24. def save_inventory(file_name: str, lst_Inventory: list) -> None:
25. """
26.
27.
28. Args:
29. file_name (str): name of file that holds the data.
30. lst_Inventory (list): list of CD objects.
31.
32. Returns:
33. None.
34.
35. """
36.
37. try:
38. with open(file_name, 'w') as file:
39. for disc in lst_Inventory:
40. [Link](disc.get_record())
41. except Exception as e:
42. print('There was a general error!', e, e.__doc__, type(e), sep='\n')
43.
44. @staticmethod
45. def load_inventory(file_name: str) -> list:
46. """
47.
48.
49. Args:
50. file_name (str): name of file that holds the data.
51.
52. Returns:
53. list: list of CD objects.
54.
55. """
56.
57. lst_Inventory = []
58. try:
59. with open(file_name, 'r') as file:
60. for line in file:
61. data = [Link]().split(',')
62. row = [Link](data[0], data[1], data[2])
63. lst_Inventory.append(row)
64. except Exception as e:
65. print('There was a general error!', e, e.__doc__, type(e), sep='\n')
66. return lst_Inventory
67.
68. class ScreenIO:
69. """Handling Input / Output"""
70.
71. @staticmethod
72. def print_menu():
73. """Displays a menu of choices to the user
74.
75. Args:
76. None.
Module 09 Page 22
77.
78. Returns:
79. None.
80. """
81.
82. print('Main Menu\n\n[l] load Inventory from file\n[a] Add CD / Album\n[d] Display Current Inv
entory')
83. print('[s] Save Inventory to file\n[x] exit\n')
84.
85. @staticmethod
86. def menu_choice():
87. """Gets user input for menu selection
88.
89. Args:
90. None.
91.
92. Returns:
93. choice (string): a lower case sting of the users input out of the choices l, a, d, s or x

94.
95. """
96. choice = ' '
97. while choice not in ['l', 'a', 'd', 's', 'x']:
98. choice = input('Which operation would you like to perform? [l, a, d, s or x]: ').lower().
strip()
99. print() # Add extra space for layout
100. return choice
101.
102. @staticmethod
103. def show_inventory(table):
104. """Displays current inventory table
105.
106.
107. Args:
108. table (list of dict): 2D data structure (list of dicts) that holds the data during
runtime.
109.
110. Returns:
111. None.
112.
113. """
114. print('======= The Current Inventory: =======')
115. print('ID\tCD Title (by: Artist)\n')
116. for row in table:
117. print(row)
118. print('======================================')
119.
120.
121. @staticmethod
122. def get_CD_info():
123. """function to request CD information from User to add CD to inventory
124.
125.
126. Returns:
127. cdId (string): Holds the ID of the CD dataset.
128. cdTitle (string): Holds the title of the CD.
129. cdArtist (string): Holds the artist of the CD.
130.
131. """
132.
133. cdId = input('Enter ID: ').strip()
134. cdTitle = input('What is the CD\'s title? ').strip()
135. cdArtist = input('What is the Artist\'s name? ').strip()
136. return cdId, cdTitle, cdArtist

Listing 15 - Lab 09A [Link]

Module 09 Page 23
[Link]:

1. #------------------------------------------#
2. # Title: Processing Classes
3. # Desc: A Module for processing Classes
4. # Change Log: (Who, When, What)
5. # DBiesinger, 2030-Jan-01, Created File
6. #------------------------------------------#
7.
8. if __name__ == '__main__':
9. raise Exception('This file is not meant to ran by itself')
10.
11. import DataClasses as DC
12.
13. class DataProcessor:
14. """Processing the data in the application"""
15. @staticmethod
16. def add_CD(CDInfo, table):
17. """function to add CD info in CDinfo to the inventory table.
18.
19.
20. Args:
21. CDInfo (tuple): Holds information (ID, CD Title, CD Artist) to be added to inventory.
22. table (list of CD Objects): 2D data structure (list of CD Objects) that holds the data du
ring runtime.
23.
24. Returns:
25. None.
26.
27. """
28.
29. cdId, title, artist = CDInfo
30. try:
31. cdId = int(cdId)
32. except:
33. raise Exception('ID must be an Integer!')
34. row = [Link](cdId, title, artist)
35. [Link](row)

Listing 16 - Lab 09A [Link]

Sample solution LAB09-B


CD_Inventory.py

1. #------------------------------------------#
2. # Title: CD_Inventory.py
3. # Desc: The CD Inventory App main Module
4. # Change Log: (Who, When, What)
5. # DBiesinger, 2030-Jan-01, Created File
6. # DBiesinger, 2030-Jan-02, Extended functionality to add tracks
7. #------------------------------------------#
8.
9. import ProcessingClasses as PC
10. import IOClasses as IO
11.
12. lstFileNames = ['[Link]', '[Link]']
13. lstOfCDObjects = [Link].load_inventory(lstFileNames)
14.
15. while True:
16. [Link].print_menu()
17. strChoice = [Link].menu_choice()
18.
19. if strChoice == 'x':
20. break

Module 09 Page 24
21. if strChoice == 'l':
22. print('WARNING: If you continue, all unsaved data will be lost and the Inventory re-
loaded from file.')
23. strYesNo = input('type \'yes\' to continue and reload from file. otherwise reload will be can
celed')
24. if [Link]() == 'yes':
25. print('reloading...')
26. lstOfCDObjects = [Link].load_inventory(lstFileNames)
27. [Link].show_inventory(lstOfCDObjects)
28. else:
29. input('canceling... Inventory data NOT reloaded. Press [ENTER] to continue to the menu.')

30. [Link].show_inventory(lstOfCDObjects)
31. continue # start loop back at top.
32. elif strChoice == 'a':
33. tplCdInfo = [Link].get_CD_info()
34. [Link].add_CD(tplCdInfo, lstOfCDObjects)
35. [Link].show_inventory(lstOfCDObjects)
36. continue # start loop back at top.
37. elif strChoice == 'd':
38. [Link].show_inventory(lstOfCDObjects)
39. continue # start loop back at top.
40. elif strChoice == 'c':
41. [Link].show_inventory(lstOfCDObjects)
42. cd_idx = input('Select the CD / Album index: ')
43. cd = [Link].select_cd(lstOfCDObjects, cd_idx)
44. while True:
45. [Link].print_CD_menu()
46. strChoice = [Link].menu_CD_choice()
47. if strChoice == 'x':
48. break
49. if strChoice == 'a':
50. tplTrkInfo = [Link].get_track_info()
51. [Link].add_track(tplTrkInfo, cd)
52. elif strChoice == 'd':
53. [Link].show_tracks(cd)
54. elif strChoice == 'r':
55. [Link].show_tracks(cd)
56. trk_idx = input('Select the Track index: ')
57. cd.rmv_track(trk_idx)
58. else:
59. print('General Error')
60. elif strChoice == 's':
61. [Link].show_inventory(lstOfCDObjects)
62. strYesNo = input('Save this inventory to file? [y/n] ').strip().lower()
63. if strYesNo == 'y':
64. [Link].save_inventory(lstFileNames, lstOfCDObjects)
65. else:
66. input('The inventory was NOT saved to file. Press [ENTER] to return to the menu.')
67. continue # start loop back at top.
68. else:
69. print('General Error')

Listing 17 - Lab 09B CD_Inventory.py

[Link]:

1. #------------------------------------------#
2. # Title: Test Harness
3. # Desc: A Module to test the Modules
4. # Change Log: (Who, When, What)
5. # DBiesinger, 2030-Jan-01, Created File
6. # DBiesinger, 2030-Jan-02, Extended functionality to add tracks
7.
8.
9. import DataClasses as DC
Module 09 Page 25
10. import ProcessingClasses as PC
11. import IOClasses as IO
12.
13. lstOfCDObjects = []
14. file_name = ['[Link]', '[Link]']
15.
16. print('\n\nTesting Track class')
17. print([Link].__doc__)
18. trk1 = [Link](1, 'test.track1', '01:59')
19. trk2 = [Link](2, 'test.track2', '02:59')
20. print(trk1)
21. print('record for file:', trk1.get_record())
22.
23. print('\n\nTesting CD class')
24. print([Link].__doc__)
25. cd1 = [Link](1, 'test_title', 'cd_artist')
26. print(cd1)
27. print('record for file:', cd1.get_record())
28. print('adding tracks...')
29. cd1.add_track(trk1)
30. cd1.add_track(trk2)
31. print('get tracks:\n', cd1.get_tracks())
32. print('get long record:\n', cd1.get_long_record())
33. print('removing track 2...')
34. cd1.rmv_track(2)
35. print('get long record:\n', cd1.get_long_record())
36. [Link](cd1)
37.
38. print('\n\nTesting of class FileIO')
39. [Link].save_inventory(file_name, lstOfCDObjects)
40. print([Link].load_inventory(file_name))
41.
42. print('\n\nTesting ScreenIO class')
43. print('Main menu:')
44. [Link].print_menu()
45. print('selection in menu: {}'.format([Link].menu_choice()))
46. print('Inventory:')
47. [Link].show_inventory(lstOfCDObjects)
48. cd2 = [Link](2, 'test_title_2', 'cd_artist_2')
49. [Link](cd2)
50. print('Inventory:')
51. for item in lstOfCDObjects:
52. print(item)
53. cd_idx = 1
54. cd = [Link].select_cd(lstOfCDObjects, cd_idx)
55. print('\nSub Menu')
56. [Link].print_CD_menu()
57. print('selection in sub menu: {}'.format([Link].menu_CD_choice()))
58. print('Tracks:')
59. [Link].show_tracks(cd)
60.
61. print('\n\nTesting Processing Classes')
62. [Link].add_CD((3, 'Foreigner', 'Foreigner'), lstOfCDObjects)
63. print('Inventory:')
64. for item in lstOfCDObjects:
65. print(item)

Listing 18 - Lab 09B [Link]

[Link]:

1. #------------------------------------------#
2. # Title: Data Classes
3. # Desc: A Module for Data Classes
4. # Change Log: (Who, When, What)
5. # DBiesinger, 2030-Jan-01, Created File
Module 09 Page 26
6. # DBiesinger, 2030-Jan-02, Modified to add Track class, added methods to CD class to handle tracks
7. #------------------------------------------#
8.
9. if __name__ == '__main__':
10. raise Exception('This file is not meant to run by itself')
11.
12. class Track():
13. """Stores Data about a single Track:
14.
15. properties:
16. position: (int) with Track position on CD / Album
17. title: (str) with Track title
18. length: (str) with length / playtime of Track
19. methods:
20. get_record() -> (str)
21.
22. """
23. # -- Constructor -- #
24. def __init__(self, pos, ttl, lgth):
25. # -- Attributes -- #
26. self.__position = pos
27. self.__title = ttl
28. self.__length = lgth
29.
30. # -- Properties -- #
31. # Track position
32. @property
33. def position(self):
34. return self.__position
35.
36. @[Link]
37. def position(self, value):
38. if type(value) == int:
39. if value < 1:
40. raise Exception('Position can\'t be less than 1!')
41. self.__position = value
42. else:
43. raise Exception('Position needs to be integer')
44.
45. # Track title
46. @property
47. def title(self):
48. return self.__title
49.
50. @[Link]
51. def title(self, value):
52. if type(value) == str:
53. self.__title = value
54. else:
55. raise Exception('Title needs to be string')
56.
57. # Track length
58. @property
59. def length(self):
60. return self.__length
61.
62. @[Link]
63. def length(self, value):
64. if type(value) == str:
65. self.__length = value
66. else:
67. raise Exception('Length needs to be string')
68.
69. # -- Methods -- #
70. def __str__(self):
71. """Returns Track details as formatted string"""
72. return '{:>2}. {} ({})'.format([Link], [Link], [Link])
Module 09 Page 27
73.
74. def get_record(self) -> str:
75. """Returns: Track record formatted for saving to file"""
76. return '{},{},{}\n'.format([Link], [Link], [Link])
77.
78.
79. class CD:
80. """Stores data about a CD / Album:
81.
82. properties:
83. cd_id: (int) with CD / Album ID
84. cd_title: (string) with the title of the CD / Album
85. cd_artist: (string) with the artist of the CD / Album
86. cd_tracks: (list) with track objects of the CD / Album
87. methods:
88. get_record() -> (str)
89. add_track(track) -> None
90. rmv_track(int) -> None
91. get_tracks() -> (str)
92. get_long_record() -> (str)
93.
94. """
95. # -- Constructor -- #
96. def __init__(self, cd_id: int, cd_title: str, cd_artist: str) -> None:
97. """Set ID, Title and Artist of a new CD Object"""
98. # -- Attributes -- #
99. try:
100. self.__cd_id = int(cd_id)
101. self.__cd_title = str(cd_title)
102. self.__cd_artist = str(cd_artist)
103. self.__tracks = []
104. except Exception as e:
105. raise Exception('Error setting initial values:\n' + str(e))
106.
107. # -- Properties -- #
108. # CD ID
109. @property
110. def cd_id(self):
111. return self.__cd_id
112.
113. @cd_id.setter
114. def cd_id(self, value):
115. try:
116. self.__cd_id = int(value)
117. except Exception:
118. raise Exception('ID needs to be Integer')
119.
120. # CD title
121. @property
122. def cd_title(self):
123. return self.__cd_title
124.
125. @cd_title.setter
126. def cd_title(self, value):
127. try:
128. self.__cd_title = str(value)
129. except Exception:
130. raise Exception('Title needs to be String!')
131.
132. # CD artist
133. @property
134. def cd_artist(self):
135. return self.__cd_artist
136.
137. @cd_artist.setter
138. def cd_artist(self, value):
139. try:
Module 09 Page 28
140. self.__cd_artist = str(value)
141. except Exception:
142. raise Exception('Artist needs to be String!')
143.
144. # CD tracks
145. @property
146. def cd_tracks(self):
147. return self.__tracks
148.
149. # -- Methods -- #
150. def __str__(self):
151. """Returns: CD details as formatted string"""
152. return '{:>2}\t{} (by: {})'.format(self.cd_id, self.cd_title, self.cd_artist)
153.
154. def get_record(self):
155. """Returns: CD record formatted for saving to file"""
156. return '{},{},{}\n'.format(self.cd_id, self.cd_title, self.cd_artist)
157.
158. def add_track(self, track: Track) -> None:
159. """Adds a track to the CD / Album
160.
161.
162. Args:
163. track (Track): Track object to be added to CD / Album.
164.
165. Returns:
166. None.
167.
168. """
169. self.__tracks.append(track)
170. self.__sort_tracks()
171.
172. def rmv_track(self, track_id: int) -> None:
173. """Removes the track identified by track_id from Album
174.
175.
176. Args:
177. track_id (int): ID of track to be removed.
178.
179. Returns:
180. None.
181.
182. """
183. del self.__tracks[track_id - 1]
184. self.__sort_tracks()
185.
186. def __sort_tracks(self):
187. """Sorts the tracks using [Link]. Fills blanks with None"""
188. n = len(self.__tracks)
189. for track in self.__tracks:
190. if (track is not None) and (n < [Link]):
191. n = [Link]
192. tmp_tracks = [None] * n
193. for track in self.__tracks:
194. if track is not None:
195. tmp_tracks[[Link] - 1] = track
196. self.__tracks = tmp_tracks
197.
198. def get_tracks(self) -> str:
199. """Returns a string list of the tracks saved for the Album
200.
201. Raises:
202. Exception: If no tracks are saved with album.
203.
204. Returns:
205. result (string):formatted string of tracks.
206.
Module 09 Page 29
207. """
208. self.__sort_tracks()
209. if len(self.__tracks) < 1:
210. raise Exception('No tracks saved for this Album')
211. result = ''
212. for track in self.__tracks:
213. if track is None:
214. result += 'No Information for this track\n'
215. else:
216. result += str(track) + '\n'
217. return result
218.
219. def get_long_record(self) -> str:
220. """gets a formatted long record of the Album: Album information plus track details
221.
222.
223. Returns:
224. result (string): Formatted information about ablum and its tracks.
225.
226. """
227. result = self.get_record() + '\n'
228. result += self.get_tracks() + '\n'
229. return result

Listing 19 - Lab 09B [Link]

[Link]

1. #------------------------------------------#
2. # Title: IO Classes
3. # Desc: A Module for IO Classes
4. # Change Log: (Who, When, What)
5. # DBiesinger, 2030-Jan-01, Created File
6. # DBiesinger, 2030-Jan-02, Extended functionality to add tracks
7. #------------------------------------------#
8.
9. if __name__ == '__main__':
10. raise Exception('This file is not meant to run by itself')
11.
12. import DataClasses as DC
13. import ProcessingClasses as PC
14.
15. class FileIO:
16. """Processes data to and from file:
17.
18. properties:
19.
20. methods:
21. save_inventory(file_name, lst_Inventory): -> None
22. load_inventory(file_name): -> (a list of CD objects)
23.
24. """
25. @staticmethod
26. def save_inventory(file_name: list, lst_Inventory: list) -> None:
27. """
28.
29.
30. Args:
31. file_name (list): list of file names [CD Inventory, Track Inventory] that hold the data.
32. lst_Inventory (list): list of CD objects.
33.
34. Returns:
35. None.
36.
37. """
38.
Module 09 Page 30
39. file_name_CD = file_name[0]
40. file_name_trk = file_name[1]
41. try:
42. with open(file_name_CD, 'w') as file:
43. for disc in lst_Inventory:
44. [Link](disc.get_record())
45. with open(file_name_trk, 'w') as file:
46. for disc in lst_Inventory:
47. tracks = disc.cd_tracks
48. disc_id = disc.cd_id
49. for trk in tracks:
50. if trk is not None:
51. record = '{},{}'.format(disc_id, trk.get_record())
52. [Link](record)
53. except Exception as e:
54. print('There was a general error!', e, e.__doc__, type(e), sep='\n')
55.
56. @staticmethod
57. def load_inventory(file_name: list) -> list:
58. """
59.
60.
61. Args:
62. file_name (list): list of file names [CD Inventory, Track Inventory] that hold the data.
63.
64. Returns:
65. list: list of CD objects.
66.
67. """
68.
69. lst_Inventory = []
70. file_name_CD = file_name[0]
71. file_name_trk = file_name[1]
72. try:
73. with open(file_name_CD, 'r') as file:
74. for line in file:
75. data = [Link]().split(',')
76. row = [Link](data[0], data[1], data[2])
77. lst_Inventory.append(row)
78. with open(file_name_trk, 'r') as file:
79. for line in file:
80. data = [Link]().split(',')
81. cd = [Link].select_cd(lst_Inventory, int(data[0]))
82. track = [Link](int(data[1]), data[2], data[3])
83. cd.add_track(track)
84. except Exception as e:
85. print('There was a general error!', e, e.__doc__, type(e), sep='\n')
86. return lst_Inventory
87.
88. class ScreenIO:
89. """Handling Input / Output"""
90.
91. @staticmethod
92. def print_menu():
93. """Displays a menu of choices to the user
94.
95. Args:
96. None.
97.
98. Returns:
99. None.
100. """
101.
102. print('Main Menu\n\n[l] load Inventory from file\n[a] Add CD / Album\n[d] Display Curr
ent Inventory')
103. print('[c] Choose CD / Album\n[s] Save Inventory to file\n[x] exit\n')
104.
Module 09 Page 31
105. @staticmethod
106. def menu_choice():
107. """Gets user input for menu selection
108.
109. Args:
110. None.
111.
112. Returns:
113. choice (string): a lower case sting of the users input out of the choices l, a, d,
c, s or x
114.
115. """
116. choice = ' '
117. while choice not in ['l', 'a', 'd', 'c', 's', 'x']:
118. choice = input('Which operation would you like to perform? [l, a, d, c, s or x]: '
).lower().strip()
119. print() # Add extra space for layout
120. return choice
121.
122. @staticmethod
123. def print_CD_menu():
124. """Displays a sub menu of choices for CD / Album to the user
125.
126. Args:
127. None.
128.
129. Returns:
130. None.
131. """
132.
133. print('CD Sub Menu\n\n[a] Add track\n[d] Display cd / Album details\n[r] Remove track\
n[x] exit to Main Menu')
134.
135. @staticmethod
136. def menu_CD_choice():
137. """Gets user input for CD sub menu selection
138.
139. Args:
140. None.
141.
142. Returns:
143. choice (string): a lower case sting of the users input out of the choices a, d, r
or x
144.
145. """
146. choice = ' '
147. while choice not in ['a', 'd', 'r', 'x']:
148. choice = input('Which operation would you like to perform? [a, d, r or x]: ').lowe
r().strip()
149. print() # Add extra space for layout
150. return choice
151.
152. @staticmethod
153. def show_inventory(table):
154. """Displays current inventory table
155.
156.
157. Args:
158. table (list of dict): 2D data structure (list of dicts) that holds the data during
runtime.
159.
160. Returns:
161. None.
162.
163. """
164. print('======= The Current Inventory: =======')
165. print('ID\tCD Title (by: Artist)\n')
Module 09 Page 32
166. for row in table:
167. print(row)
168. print('======================================')
169.
170. @staticmethod
171. def show_tracks(cd):
172. """Displays the Tracks on a CD / Album
173.
174. Args:
175. cd (CD): CD object.
176.
177. Returns:
178. None.
179.
180. """
181. print('====== Current CD / Album: ======')
182. print(cd)
183. print('=================================')
184. print(cd.get_tracks())
185. print('=================================')
186.
187. @staticmethod
188. def get_CD_info():
189. """function to request CD information from User to add CD to inventory
190.
191.
192. Returns:
193. cdId (string): Holds the ID of the CD dataset.
194. cdTitle (string): Holds the title of the CD.
195. cdArtist (string): Holds the artist of the CD.
196.
197. """
198.
199. cdId = input('Enter ID: ').strip()
200. cdTitle = input('What is the CD\'s title? ').strip()
201. cdArtist = input('What is the Artist\'s name? ').strip()
202. return cdId, cdTitle, cdArtist
203.
204. @staticmethod
205. def get_track_info():
206. """function to request Track information from User to add Track to CD / Album
207.
208.
209. Returns:
210. trkId (string): Holds the ID of the Track dataset.
211. trkTitle (string): Holds the title of the Track.
212. trkLength (string): Holds the length (time) of the Track.
213.
214. """
215.
216. trkId = input('Enter Position on CD / Album: ').strip()
217. trkTitle = input('What is the Track\'s title? ').strip()
218. trkLength = input('What is the Track\'s length? ').strip()
219. return trkId, trkTitle, trkLength

Listing 20 - Lab 09B [Link]

[Link]:

1. #------------------------------------------#
2. # Title: Processing Classes
3. # Desc: A Module for processing Classes
4. # Change Log: (Who, When, What)
5. # DBiesinger, 2030-Jan-01, Created File
6. # DBiesinger, 2030-Jan-02, Extended functionality to add tracks
7. #------------------------------------------#
Module 09 Page 33
8.
9. if __name__ == '__main__':
10. raise Exception('This file is not meant to ran by itself')
11.
12. import DataClasses as DC
13.
14. class DataProcessor:
15. """Processing the data in the application"""
16. @staticmethod
17. def add_CD(CDInfo, table):
18. """function to add CD info in CDinfo to the inventory table.
19.
20.
21. Args:
22. CDInfo (tuple): Holds information (ID, CD Title, CD Artist) to be added to inventory.
23. table (list of CD Objects): 2D data structure (list of CD Objects) that holds the data du
ring runtime.
24.
25. Returns:
26. None.
27.
28. """
29.
30. cdId, title, artist = CDInfo
31. try:
32. cdId = int(cdId)
33. except:
34. raise Exception('ID must be an Integer!')
35. row = [Link](cdId, title, artist)
36. [Link](row)
37.
38. @staticmethod
39. def select_cd(table: list, cd_idx: int) -> [Link]:
40. """selects a CD object out of table that has the ID cd_idx
41.
42. Args:
43. table (list): Inventory list of CD objects.
44. cd_idx (int): id of CD object to return
45.
46. Raises:
47. Exception: If id is not in list.
48.
49. Returns:
50. row ([Link]): CD object that matches cd_idx
51.
52. """
53. try:
54. cd_idx = int(cd_idx)
55. except ValueError as e:
56. print('ID is not an Integer!')
57. print(e.__doc__)
58. for row in table:
59. if row.cd_id == cd_idx:
60. return row
61. raise Exception('This CD / Album index does not exist')
62.
63. @staticmethod
64. def add_track(track_info: tuple, cd: [Link]) -> None:
65. """adds a Track object with attributes in track_info to cd
66.
67.
68. Args:
69. track_info (tuple): Tuple containing track info (position, title, Length).
70. cd ([Link]): cd object the tarck gets added to.
71.
72. Raises:
73. Exception: DESCraised in case position is not an integer.
Module 09 Page 34
74.
75. Returns:
76. None: DESCRIPTION.
77.
78. """
79.
80. trkPos, trkTitle, trkLength = track_info
81. try:
82. trkPos = int(trkPos)
83. except:
84. raise Exception('Position must be an Integer')
85. track = [Link](trkPos, trkTitle, trkLength)
86. cd.add_track(track)

Listing 21 - Lab 09B [Link]

Module 09 Page 35

You might also like