Skip to content

25th March 2022

Coding

Python

Type Hints

  • New: Suggest to use Sequence over List.

    Because using List could lead to some unexpected errors when combined with type inference. For example:

    class A: ...
    class B(A): ...
    
    lst = [A(), A()]  # Inferred type is List[A]
    new_lst = [B(), B()]  # inferred type is List[B]
    lst = new_lst  # mypy will complain about this, because List is invariant
    

    Possible strategies in such situations are:

    • Use an explicit type annotation:

      new_lst: List[A] = [B(), B()]
      lst = new_lst  # OK
      
    • Make a copy of the right hand side:

      lst = list(new_lst) # Also OK
      
    • Use immutable collections as annotations whenever possible:

      def f_bad(x: List[A]) -> A:
          return x[0]
      f_bad(new_lst) # Fails
      
      def f_good(x: Sequence[A]) -> A:
          return x[0]
      f_good(new_lst) # OK
      
  • New: Overloading the methods.

    Sometimes the types of several variables are related, such as “if x is type A, y is type B, else y is type C”. Basic type hints cannot describe such relationships, making type checking cumbersome or inaccurate. We can instead use @typing.overload to represent type relationships properly.

    from __future__ import annotations
    
    from collections.abc import Sequence
    from typing import overload
    
    @overload
    def double(input_: int) -> int:
        ...
    
    @overload
    def double(input_: Sequence[int]) -> list[int]:
        ...
    
    def double(input_: int | Sequence[int]) -> int | list[int]:
        if isinstance(input_, Sequence):
            return [i * 2 for i in input_]
        return input_ * 2
    

    This looks a bit weird at first glance—we are defining double three times! Let’s take it apart.

    The first two @overload definitions exist only for their type hints. Each definition represents an allowed combination of types. These definitions never run, so their bodies could contain anything, but it’s idiomatic to use Python’s ... (ellipsis) literal.

    The third definition is the actual implementation. In this case, we need to provide type hints that union all the possible types for each variable. Without such hints, Mypy will skip type checking the function body.

    When Mypy checks the file, it collects the @overload definitions as type hints. It then uses the first non-@overload definition as the implementation. All @overload definitions must come before the implementation, and multiple implementations are not allowed.

    When Python imports the file, the @overload definitions create temporary double functions, but each is overridden by the next definition. After importing, only the implementation exists. As a protection against accidentally missing implementations, attempting to call an @overload definition will raise a NotImplementedError.

    @overload can represent arbitrarily complex scenarios. For a couple more examples, see the function overloading section of the Mypy docs.

  • Correction: Debug the Start request repeated too quickly error.

    Use journalctl -eu docker to debug

DevOps

Automating Processes

cruft

Operative Systems

Linux

Linux Snippets

ffmpeg

  • New: Convert VOB to mkv.

    • Unify your VOBs

      cat *.VOB > output.vob
      

    • Identify the streams

      ffmpeg -analyzeduration 100M -probesize 100M -i output.vob
      

      Select the streams that you are interested in, imagine that is 1, 3, 4, 5 and 6.

    • Encoding

      bash ffmpeg \ -analyzeduration 100M -probesize 100M \ -i output.vob \ -map 0:1 -map 0:3 -map 0:4 -map 0:5 -map 0:6 \ -metadata:s:a:0 language=ita -metadata:s:a:0 title="Italian stereo" \ -metadata:s:a:1 language=eng -metadata:s:a:1 title="English stereo" \ -metadata:s:s:0 language=ita -metadata:s:s:0 title="Italian" \ -metadata:s:s:1 language=eng -metadata:s:s:1 title="English" \ -codec:v libx264 -crf 21 \ -codec:a libmp3lame -qscale:a 2 \ -codec:s copy \ output.mkv