Skip to content

Latest commit

 

History

History
 
 

10-dp-1class-func

Sample code for Chapter 10 - "Design patterns with first class functions"

From the book "Fluent Python" by Luciano Ramalho (O'Reilly, 2015) http://shop.oreilly.com/product/0636920032519.do

Notes

No issues on file with zero type hints

Running Mypy on classic_strategy.py from the first edition, with no type hints:

$ mypy classic_strategy.py
Success: no issues found in 1 source file

Type inference at play

When the Order.due method made first assignment to discount as discount = 0, Mypy complained:

mypy classic_strategy.py
classic_strategy.py:68: error: Incompatible types in assignment (expression has type "float", variable has type "int")
Found 1 error in 1 file (checked 1 source file)

To fix it, I made the first assigment as discount = 0. I never explicitly declared a type for discount.

Mypy ignores functions with no annotations

Mypy did not raise any issues with this test case:

def test_bulk_item_promo_with_discount(customer_fidelity_0):
    cart = [LineItem('banana', 30, .5),
            LineItem('apple', 10, 1.5)]
    order = Order(customer_fidelity_0, 10, BulkItemPromo())
    assert order.total() == 30.0
    assert order.due() == 28.5

The second argument to Order is declared as Sequence[LineItem]. Mypy only checks the body of a function the signature as at least one annotation, like this:

def test_bulk_item_promo_with_discount(customer_fidelity_0) -> None:
    cart = [LineItem('banana', 30, .5),
            LineItem('apple', 10, 1.5)]
    order = Order(customer_fidelity_0, 10, BulkItemPromo())
    assert order.total() == 30.0
    assert order.due() == 28.5

Now Mypy complains that "Argument 2 of Order has incompatible type".

However, even with the annotation in the test function signature, Mypy did not find any problem when I mistyped the name of the cart argument. Here, cart_plain should be cart:

def test_bulk_item_promo_with_discount(customer_fidelity_0) -> None:
    cart = [LineItem('banana', 30, .5),
            LineItem('apple', 10, 1.5)]
    order = Order(customer_fidelity_0, cart_plain, BulkItemPromo())
    assert order.total() == 30.0
    assert order.due() == 28.5

Hypotesis: cart_plain is a function decorated with @pytest.fixture, and at the top of the test file I told Mypy to ignore the Pytest import:

import pytest  # type: ignore