Unit 6
Development team project: Design document
Summative assessment reflection
The goal of the assignment was to design a secure application for one of the suggested domains. The system had to support authentication, role-based access, store user data, and include measures against common attack vectors. A key requirement was that security features could be toggled on and off to demonstrate their effectiveness. Besides, it was a team assignment, which also added a coordination component.
The team was assigned by the tutor, but organizing the team cooperation was up to us. Initially, no one took the lead, so I decided to show some initiative and reached out to my teammates. A few responded and joined the Discord server I created for our communication, but others remained silent until I eventually asked the module tutor to contact them directly. That finally helped get the full team on board. Most communication happened asynchronously due to different time zones, but we also managed a couple of group calls, which I found especially helpful. In my experience, synchronous discussions are often more effective for making decisions quickly and avoiding misunderstandings.
Overall, it was great to interact more informally with other students from the course. However, it was frustrating when some members did not participate or respond to messages at all, without any explanation. That said, we still managed to complete the assignment on time, and I’d describe the collaboration as mostly positive — certainly a valuable learning experience.
The most challenging aspect of the system design was deciding on how and what security features could be turned off to make the application vulnerable. This requirement influenced several design decisions: we had to structure the system, so that its weaknesses were exposed when protections were disabled.
One of my key takeaways from this project was about the team dynamics. Waiting for others to take initiative leads to unnecessary delays, so it might be better to step up early, even if it feels uncomfortable. At the same time, it was challenging to find a balance between being proactive and not feeling like I was overstepping, especially when no one in the group held a formal leadership role.
Another important lesson was about pacing and time management in group projects. The actual timeline didn’t match the expectations we had when we were first planning the work, and instead we resorted to an even more flexible approach that we initially expected. I think in future group projects, both I and the other students will know what to expect and how to plan the team work realistically.
Exploring linters to support testing in Python
The following questions will be discussed during this week’s seminar. These questions are provided in the 'testing-with-python' zip file with instructions provided in the 'Secure Software Development' PDF file. These activities should be completed on your chosen Jupyter Notebook workspace.
Question 1
Run styleLint.py.
What happens when the code is run? Can you modify this code for a more favourable outcome? What amendments have you made to the code?
# CODE SOURCE: SOFTWARE ARCHITECTURE WITH PYTHON
def factorial(n):
""" Return factorial of n """
if n == 0:
return 1
else:
return n*factorial(n-1)
An attempt to run this Python code fails; the reason is incorrect code formatting: function body must be properly indented:
File "/Users/sergei.lebedev/Downloads/testing-with-python/styleLint.py", line 5
""" Return factorial of n """
^
IndentationError: expected an indented block after function definition on line 4
To make this code run, a few changes are required to properly reflect the code structure via indentation:
# CODE SOURCE: SOFTWARE ARCHITECTURE WITH PYTHON
def factorial(n):
""" Return factorial of n """
if n == 0:
return 1
else:
return n * factorial(n - 1)
The code now can be successfully executed.
Question 2
pip install pylint
Run
pylint
on pylintTest.py
Review each of the code errors returned. Can you correct each of the errors identified by pylint?
Before correcting the code errors, save the pylintTest.py file with a new name (it will be needed again in the next question).
# SOURCE OF CODE: https://docs.pylint.org/en/1.6.0/tutorial.html
import string
shift = 3
choice = raw_input("would you like to encode or decode?")
word = (raw_input("Please enter text"))
letters = string.ascii_letters + string.punctuation + string.digits
encoded = ''
if choice == "encode":
for letter in word:
if letter == ' ':
encoded = encoded + ' '
else:
x = letters.index(letter) + shift
encoded=encoded + letters[x]
if choice == "decode":
for letter in word:
if letter == ' ':
encoded = encoded + ' '
else:
x = letters.index(letter) - shift
encoded = encoded + letters[x]
print encoded
Running the command pylint pylintTest.py
yields the following result:
pylintTest.py:26:1: E0001: Parsing failed: 'Missing parentheses in call to 'print'. Did you mean print(...)? (pylintTest, line 26)' (syntax-error)
This indicates issues with the syntax used in the print()
function invocation on the line 26:
print encoded
To resolve the issue, the function call must look as follows:
print(encoded)
This change allows pylint
to be run and return the following list of issues for the file:
************* Module pylintTest
pylintTest.py:8:0: C0325: Unnecessary parens after '=' keyword (superfluous-parens)
pylintTest.py:12:0: W0311: Bad indentation. Found 2 spaces, expected 4 (bad-indentation)
pylintTest.py:13:0: W0311: Bad indentation. Found 4 spaces, expected 8 (bad-indentation)
pylintTest.py:14:0: W0311: Bad indentation. Found 6 spaces, expected 12 (bad-indentation)
pylintTest.py:15:0: W0311: Bad indentation. Found 4 spaces, expected 8 (bad-indentation)
pylintTest.py:16:0: W0311: Bad indentation. Found 6 spaces, expected 12 (bad-indentation)
pylintTest.py:17:0: W0311: Bad indentation. Found 6 spaces, expected 12 (bad-indentation)
pylintTest.py:18:0: W0311: Bad indentation. Found 4 spaces, expected 8 (bad-indentation)
pylintTest.py:19:0: W0311: Bad indentation. Found 6 spaces, expected 12 (bad-indentation)
pylintTest.py:20:0: W0311: Bad indentation. Found 8 spaces, expected 16 (bad-indentation)
pylintTest.py:21:0: W0311: Bad indentation. Found 12 spaces, expected 20 (bad-indentation)
pylintTest.py:22:0: W0311: Bad indentation. Found 8 spaces, expected 16 (bad-indentation)
pylintTest.py:23:0: W0311: Bad indentation. Found 10 spaces, expected 20 (bad-indentation)
pylintTest.py:24:0: W0311: Bad indentation. Found 10 spaces, expected 20 (bad-indentation)
pylintTest.py:26:0: C0304: Final newline missing (missing-final-newline)
pylintTest.py:1:0: C0114: Missing module docstring (missing-module-docstring)
pylintTest.py:1:0: C0103: Module name "pylintTest" doesn't conform to snake_case naming style (invalid-name)
pylintTest.py:6:0: C0103: Constant name "shift" doesn't conform to UPPER_CASE naming style (invalid-name)
pylintTest.py:7:9: E0602: Undefined variable 'raw_input' (undefined-variable)
pylintTest.py:8:8: E0602: Undefined variable 'raw_input' (undefined-variable)
pylintTest.py:9:0: C0103: Constant name "letters" doesn't conform to UPPER_CASE naming style (invalid-name)
pylintTest.py:10:0: C0103: Constant name "encoded" doesn't conform to UPPER_CASE naming style (invalid-name)
pylintTest.py:14:6: C0103: Constant name "encoded" doesn't conform to UPPER_CASE naming style (invalid-name)
pylintTest.py:16:6: C0103: Constant name "x" doesn't conform to UPPER_CASE naming style (invalid-name)
pylintTest.py:17:6: C0103: Constant name "encoded" doesn't conform to UPPER_CASE naming style (invalid-name)
pylintTest.py:21:12: C0103: Constant name "encoded" doesn't conform to UPPER_CASE naming style (invalid-name)
pylintTest.py:23:10: C0103: Constant name "x" doesn't conform to UPPER_CASE naming style (invalid-name)
pylintTest.py:24:10: C0103: Constant name "encoded" doesn't conform to UPPER_CASE naming style (invalid-name)
------------------------------------------------------------------
Your code has been rated at 0.00/10 (previous run: 0.00/10, +0.00)
The following changes are required to fix the problems with the file:
- Rename
pylintTest.py
intopylint_test.py
to comply with snake naming convention for modules; - Remove unnecessary parentheses in the
word
variable definition; - Apply proper indentation with four spaces;
- Insert a trailing empty line;
- Introduce the
main()
function to avoidC0101
warnings caused by the variables being declared globally; - Add docstring for the module and the
main()
function; - Replace
raw_input()
from Python 2 withinput()
from Python 3.
As a result, pylint
runs without reporting any problems:
-------------------------------------------------------------------
Your code has been rated at 10.00/10 (previous run: 9.55/10, +0.45)
The script looks as follows after all necessary corrections:
# SOURCE OF CODE: https://docs.pylint.org/en/1.6.0/tutorial.html
"""
Pylint demo
"""
import string
def main():
"""
Main function
"""
shift = 3
choice = input("would you like to encode or decode?")
word = input("Please enter text")
letters = string.ascii_letters + string.punctuation + string.digits
encoded = ''
if choice == "encode":
for letter in word:
if letter == ' ':
encoded = encoded + ' '
else:
x = letters.index(letter) + shift
encoded = encoded + letters[x]
if choice == "decode":
for letter in word:
if letter == ' ':
encoded = encoded + ' '
else:
x = letters.index(letter) - shift
encoded = encoded + letters[x]
print(encoded)
if __name__ == "__main__":
main()
Question 3
pip install flake8
Run
flake8
on pylintTest.py
Review the errors returned. In what way does this error message differ from the error message returned by pylint?
Run flake8 on metricTest.py. Can you correct each of the errors returned by flake8? What amendments have you made to the code?
Similarly to the previous question, flake8
fails due to incorrect print()
function call:
pylintTest.py:26:2: E999 SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?
After this issue is resolved, the following set of problems is reported:
pylintTest.py:7:10: F821 undefined name 'raw_input'
pylintTest.py:8:9: F821 undefined name 'raw_input'
pylintTest.py:12:3: E111 indentation is not a multiple of 4
pylintTest.py:14:7: E111 indentation is not a multiple of 4
pylintTest.py:16:7: E111 indentation is not a multiple of 4
pylintTest.py:17:7: E111 indentation is not a multiple of 4
pylintTest.py:17:14: E225 missing whitespace around operator
pylintTest.py:19:7: E111 indentation is not a multiple of 4
pylintTest.py:23:11: E111 indentation is not a multiple of 4
pylintTest.py:24:11: E111 indentation is not a multiple of 4
pylintTest.py:26:15: W292 no newline at end of file
After these issues are resolved and the file looks as below, flake8
does not report any further problems, indicating that the set of issues that this tool detects is smaller. Besides, pylint
appears to be more opinionated in terms of code style.
# SOURCE OF CODE: https://docs.pylint.org/en/1.6.0/tutorial.html
import string
shift = 3
choice = input("would you like to encode or decode?")
word = (input("Please enter text"))
letters = string.ascii_letters + string.punctuation + string.digits
encoded = ''
if choice == "encode":
for letter in word:
if letter == ' ':
encoded = encoded + ' '
else:
x = letters.index(letter) + shift
encoded = encoded + letters[x]
if choice == "decode":
for letter in word:
if letter == ' ':
encoded = encoded + ' '
else:
x = letters.index(letter) - shift
encoded = encoded + letters[x]
print(encoded)
Question 4
pip install mccabe
Run
mccabe
on sums.py. What is the result?
Run
mccabe
on sums2.py. What is the result?
What are the contributors to the cyclomatic complexity in each piece of code?
Source code for sums.py
and the result of mccabe
tool execution for the file:
# SOURCE OF CODE: https://realpython.com/python-testing/
def test_sum():
assert sum([1, 2, 3]) == 6, "Should be 6"
if __name__ == "__main__":
test_sum()
print("Everything passed")
3:0: 'test_sum' 1
If 7 2
Source code for sums2.py
and the result of mccabe
tool execution for the file:
# SOURCE OF CODE: https://realpython.com/python-testing/
def test_sum():
assert sum([1, 2, 3]) == 6, "Should be 6"
def test_sum_tuple():
assert sum((1, 2, 2)) == 6, "Should be 6"
if __name__ == "__main__":
test_sum()
test_sum_tuple()
print("Everything passed")
3:0: 'test_sum' 1
7:0: 'test_sum_tuple' 1
If 11 2
Both files have a pretty similar structure and similar scores. All declared functions have a linear execution path, therefore they have a score of one. The if
blocks in each of the files are also included in the report. As if
conditions offer branching, they introduce a McCabe complexity of two.