Practicalities: linting, testing, documentation.

Python Style Best Practises

Python Style Best Practises

Concepts

Pythonistas - veteran Python developers
Pythonic - following the Python philosophy and Python's guidelines
PEPPythonEnhancementProposal
PEP index

PEP20:The Zen of Python


			>>> import this
			The Zen of Python, by Tim Peters

			Beautiful is better than ugly.
			Explicit is better than implicit.
			Simple is better than complex.
			Complex is better than complicated.
			Flat is better than nested.
			Sparse is better than dense.
			Readability counts.
			Special cases aren't special enough to break the rules.
			Although practicality beats purity.
			Errors should never pass silently.
			Unless explicitly silenced.
			In the face of ambiguity, refuse the temptation to guess.
			There should be one-- and preferably only one --obvious way to do it.
			Although that way may not be obvious at first unless you're Dutch.
			Now is better than never.
			Although never is often better than *right* now.
			If the implementation is hard to explain, it's a bad idea.
			If the implementation is easy to explain, it may be a good idea.
			Namespaces are one honking great idea -- let's do more of those!
			>>>
		

PEP 20 -- The Zen of Python

PEP 20 (The Zen of Python) by Example by Hunter Blank

PEP8: Style Guide for Python Code

PEP8 is the de facto coding style guide for Python.
PEP 8 @python.org

Indentation


			def long_function_name(
			        var_one, var_two, var_three,
			        var_four):
			    print(var_one)
		

			#Arguments on first line forbidden when not using vertical alignment.
			def long_function_name(var_one, var_two, var_three,
			        var_four):
			    print(var_one)
		

Indentation


			my_list = [
			    1, 2, 3,
			    4, 5, 6,
			]
		

			my_list = [
			    1, 2, 3,
			    4, 5, 6,
								]
		

Line break before or after a binary operator?


			result = (op1
			          + (op2 * op3)
			          - op4)
		

			result = (op1 +
			          op2 *
			          op3 -
			          op4)
		

Tabs or Spaces?

Spaces are the preferred indentation method.
Python 3 disallows mixing the use of tabs and spaces for indentation.

Linters

Linters

pycodestyle - the PEP8 Linter Module

pycodestyle (formerly called pep8) module

				pip3 install pycodestyle
				pycodestyle my_file.py
			

pycodestyle - example


			def print_list(my_list):
			  for i in my_list:
			    print(i)
			my_list = [
			          1, 2, 3,
			          4, 5, 6,]

			print_list(my_list)
		

			$ pycodestyle nonPEP8_styled.py
			nonPEP8_styled.py:2:3: E111 indentation is not a multiple of four
			nonPEP8_styled.py:4:1: E305 expected 2 blank lines after class or function definition, found 0
			nonPEP8_styled.py:6:18: E231 missing whitespace after ','
			nonPEP8_styled.py:8:20: W292 no newline at end of file
		

pycodestyle for Editors and IDEs

SublimeLinter-pycodestyle
Pep8 Linting @code.visualstudio.com
PyCharm - you can set pycodestyle as an external tool

Documentation Conventions

Documentation Conventions

Docstring Versus Block Comments

Docstrings and block comments aren't interchangeable.. Both can be used for a function or class

			# TODO: put more semantics on this example
			def foo(x,y):
			  """foo() Summary

			  Args:
			      x (TYPE): int
			      y (TYPE): int

			  Returns:
			      TYPE: int
			  """
			  return x+Y
		

The docstring describes the operation of the function or class and will be shown in an interactive Python session when the user types help

Project Documentation for Contributors

A README file at the root directory should give general information to both users and maintainers of a project
A LICENSE file should always be present and specify the license under which the software is made available to the public.
A TODO file (or section in README) should list the planned development for the code.
A CHANGELOG file (or section in README) should present a short overview of the changes in the code base for the latest versions.

Python documentation tools

Sphinx - is a tool that makes it easy to create intelligent and beautiful documentation
Sphinx is well integrated with Read The Docs - free documentation hosting for the open source community

Unittest

Unittest

Test-Driven Development (TDD)

TDD means that the developer first writes tests that define the main operation and edge cases for a function, and then writes the function.
Python 2.1, released in 2001, embraced the test-driven development (TDD)

Best Practices for testing

A testing unit should focus on one tiny bit of functionality and prove it correct.
Each test unit must be fully independent: able to run alone and regardless of the order the test units are called
Use long and descriptive names for testing function, as these function names are displayed when a test fails.
Try hard to make tests that are fast
Always run the full test suite before a coding session, and run it again after.

unittest - Python's Unit testing framework

The built-in module unittest implements unit testing framework in Python, similar to JUnit or nUnit
Creating test cases is accomplished by subclassing unittest.TestCase
Test methods must start with the string test or they will not run.
Test modules (files) are expected to match the pattern test*.py by default, or the --pattern keyword argument, if given, on the command line

unittest - example


			import unittest

			def floor_div(x,y):
			  return x/y

			class PositiveTest(unittest.TestCase):
			  def test_floor_div_with_positive_integers(self):
			    self.assertEqual(floor_div(4,3), 1)
		

			$ python3 -m unittest floor_div_test.py
			F
			======================================================================
			FAIL: test_floor_div_with_positive_integers (floor_div_test.PositiveTest)
			----------------------------------------------------------------------
			Traceback (most recent call last):
			  File "/data/projects/www/wwwcourses.github.io/ProgressBG-VC-Python/pages/themes/beginners/practicalities/examples/floor_div_test.py", line 9, in test_floor_div_with_positive_integers
			    self.assertEqual(floor_div(4,3), 1)
			AssertionError: 1.3333333333333333 != 1

			----------------------------------------------------------------------
			Ran 1 test in 0.000s

			FAILED (failures=1)
		

Intro to py.test

Intro to py.test

Install


				# install for a virtual env:
				pipenv install pytest

				# install for the system python3:
				pip3 install --user pytest
			
Official site: pytest: helps you write better programs

Example


			def floor_div(x,y):
			  return x/y

			def test_floor_div_with_positive_integers():
			  assert floor_div(4,3) == 1
		

			>pytest floor_div_pytest.py
			========================================================================= test session starts =========================================================================
			platform linux -- Python 3.6.4, pytest-3.5.0, py-1.5.3, pluggy-0.6.0
			rootdir: /data/projects/www/wwwcourses.github.io/ProgressBG-VC-Python/pages/themes/beginners/practicalities/examples, inifile: pytest.ini
			collected 1 item

			floor_div_pytest.py F                                                                                                                                           [100%]

			============================================================================== FAILURES ===============================================================================
			________________________________________________________________ test_floor_div_with_positive_integers ________________________________________________________________

			    def test_floor_div_with_positive_integers():
			>     assert floor_div(4,3) == 1
			E     assert 1.3333333333333333 == 1
			E      +  where 1.3333333333333333 = floor_div(4, 3)

			floor_div_pytest.py:6: AssertionError
			====================================================================== 1 failed in 0.03 seconds =======================================================================
		

Customizing test collection


			# discover tests from every Python file
			[pytest]
			python_files = *.py
		

			$pytest --collect-only
			========================================================================= test session starts =========================================================================
			platform linux -- Python 3.6.4, pytest-3.5.0, py-1.5.3, pluggy-0.6.0
			rootdir: /data/projects/www/wwwcourses.github.io/ProgressBG-VC-Python/pages/themes/beginners/practicalities/examples, inifile: pytest.ini
			collected 3 items
			<Module 'floor_div_pytest.py'>
			  <Function 'test_floor_div_with_positive_integers'>
			<Module 'floor_div_test.py'>
			  <UnitTestCase 'PositiveTest'>
			    <TestCaseFunction 'test_floor_div_with_positive_integers'>
			<Module 'pytest_sample.py'>
			  <Function 'test_answer'>

			==================================================================== no tests ran in 0.01 seconds =====================================================================
			(ProgressBG-VC-Python)nemsys@X230~gh-pages->
		

Resources

Resources

Texts

Code Style @The Hitchhiker’s Guide to Python
Python Linters and Code Analysis tools curated list @github

Videos

Raymond Hettinger - Beyond PEP 8 -- Best practices for beautiful intelligible code - PyCon 2015

Exercises

Task1: PEP8 styled

The Task

Lint your solution code of task: guess_the_quotes, according to PEP8 Recommendation,and make sure it strictly follows them.

Submission

Please, prefix your filenames/archive with your name initials, before sending.
For instance: iep_task1.py or iep_tasks.rar
Send files to progressbg.python.course@gmail.com

These slides are based on

customised version of

Hakimel's reveal.js

framework