Brought to you by Michael and Brian - take a Talk Python course or get Brian's pytest book

Episode #195: Runtime type checking for Python type hints

Published Tue, Aug 18, 2020, recorded Wed, Aug 12, 2020.

Sponsored by us! Support our work through:

Michael #1: watchdog

  • via Prayson Daniel
  • Python API and shell utilities to monitor file system events.
  • Example:
    observer = Observer()
    observer.schedule(event_handler, path, recursive=True)
    observer.start()
  • Watchdog comes with an optional utility script called watchmedo
  • try $ watchmedo log and see what happens in that folder.
  • Why Watchdog? Compared to other similar libs

Brian #2: Status code 418

  • Thanks Andy Howe for the suggestion
  • Python 3.9 rc1 is out.
  • One nice enhancement that has made it into 3.9, a fix for http library missing HTTP status code 418 “I’m a teapot”.
  • https://bugs.python.org/issue39507
    • Title: http library missing HTTP status code 418 "I'm a teapot"
  • See also status code 418 is also supported by HTCPCP, Hyper Text Coffee Pot Control Protocol, https://tools.ietf.org/html/rfc2324
    • 418 I'm a teapot
Any attempt to brew coffee with a teapot should result in the error  code "418 I'm a teapot". The resulting entity body MAY be short and stout.
  • The only other unique HTCPCP code is 406
    • 406 Not Acceptable
… In HTCPCP, this response code MAY be returned if the operator of the coffee pot cannot comply with the Accept-Addition request. Unless the request was a HEAD request, the response SHOULD include an entity containing a list of available coffee additions.

Michael #3: pydantic’s new Validation decorator

  • via Andy Shapiro
  • Built-in type checking for any function via a decorator
  • easy to add for any public methods in a package
  • pydantic uses lots of cython under the hood so it should be fast....
  • The validate_arguments decorator allows the arguments passed to a function to be parsed and validated using the function's annotations before the function is called.
  • Under the hood this uses the same approach of model creation and initialization; it provides an extremely easy way to apply validation to your code with minimal boilerplate.
  • Example:
    from pydantic import validate_arguments, ValidationError

    @validate_arguments
    def repeat(s: str, count: int, *, separator: bytes = b'') -> bytes:
        b = s.encode()
        return separator.join(b for _ in range(count))

    a = repeat('hello', 3)
    print(a)
    #> b'hellohellohello'

    b = repeat('x', '4', separator=' ')
    print(b)
    #> b'x x x x'

    try:
        c = repeat('hello', 'wrong')
    except ValidationError as exc:
        print(exc)
        """
        1 validation error for Repeat
        count
          value is not a valid integer (type=type_error.integer)
        """

Brian #4: Building Python Extension Modules in Assembly

  • Anthony Shaw
  • From twitter announcement:
    • “After a series of highly questionable life decisions, my Python extension written in pure assembly is now on PyPI. https://pypi.org/project/pymult/ it required writing an Assembly extension for distutils, I also added GitHub Actions support so its running CI/CD and testing with pytest”.
  • A proof-of-concept to demonstrate how you can create a Python Extension in 100% assembly.
  • Demonstrates:
    • How to write a Python module in pure assembly
    • How to write a function in pure assembly and call it from Python with Python objects
    • How to call the C API to create a PyObject and parse PyTuple (arguments) into raw pointers
    • How to pass data back into Python
    • How to register a module from assembly
    • How to create a method definition in assembly
    • How to write back to the Python stack using the dynamic module loader
    • How to package a NASM/Assembly Python extension with distutils
  • The simple proof-of-concept function takes 2 parameters,
    >>> import pymult
    >>> pymult.multiply(2, 4)
    8  
  • May need a few more test cases:
    >>> pymult.multiply(2, 3)
    6
    >>> pymult.multiply(-2, -3)
    6
    >>> pymult.multiply(-2, 3)
    4294967290
  • Also, clearly Anthony has too much time on his hands. Just saying.

Michael #5: easy property

  • via Ruud van der Ham
  • The easy_property module, developed by me, offers a more intuitive way to define a Python property with getter, setter, deleter, getter_setter and documenter decorators.
  • Normally when you want to define a property that has a getter and a setter, you have to do something like
    Class Demo:
        def __init__(self, val):
            self.a = val
        @property
        def a(self):
            return self._a

        @a.setter
        def a(self, val):
            self._a = val
  • IMHO, the @a.setter is a rather ugly decorator, and hard to remember. And there's no way to not define the getter.
  • With the easy_property module, one can use the decorators
    • getter
    • setter
    • deleted
  • as in:
    Class Demo:
        def __init__(self, val):
            self.a = val
        @getter
        def a(self):
            return self._a
        @setter
        def a(self, val):
            self._a = val
        @deleter
        def a(self):
            print('delete')
            del self._a
  • In contrast with an ordinary property, the order of definition of getter, setter and deleter is not important. And it is even possible to define a setter only (without a getter), just in case.
  • With easy_property, you can even create a combined getter/setter decorator:
    Class Demo:
        def __init__(self, val):
            self.a = val
        @getter_setter
        def a(self, val=None):
            if val is None:
                return self._a
            self._a = val
  • Finally, it is possible to add a docstring to the property, with the @documenter decorator:
    Class Demo:
        def __init__(self, val):
            self.a = val
        @getter
        def a(self):
            return self._a
        @documenter:
        def a(self):
            return "this is the docstring of Demo.a"

Although this might not be always a good solution, I think in many cases this will make it easier and more intuitive to define properties.

Brian #6: Non Blocking Assertion Failures with pytest-check

  • Ryan Howard wrote an article about a project of mine on the TestProject blog.
  • I think it’s a first that someone else wrote an article about something I made. So that’s cool.
  • Most tests do the “check” part with assert statements.
  • The problem is assert stops after the first failure and you often want to check lots of stuff, and you want to see all the failures.
  • Ryan has a good example with checking web pages using selenium and a simple example of wanting to check both the content of an element on the page, and the url.
  • Cool use of pytest-check
  • See also:

Extras:

Brian

  • PSA: There are no capital letters in pytest, even if it begins a sentence.

Michael

Joke:

  • XKCD git - xkcd.com/1597
  • “I used to do low-level programming. Then a product I bought told me, "No assembly required." Since then, I've been coding in Python.” - From Rueven Lerner, Inspired by Anthony Shaw

Click to show comments