Harness the Power of Typing Extensions for Python Developers

Introduction to typing-extensions

The Python library typing-extensions is an essential tool for developers who want to maintain compatibility with the Python type annotation system across multiple versions of Python. Along with supporting backporting of new typing features to older Python versions, it also provides additional tools that are invaluable for defining precise type hints. In this blog post, we’ll explore its most useful APIs, with code examples, followed by a real-world app implementation.

Key Features and APIs of typing-extensions

1. Annotated

Annotated allows metadata to be associated with a type. This is useful for frameworks that use the extra information for validations or behaviors.

  from typing_extensions import Annotated

  def process_data(age: Annotated[int, "Age in years (must be positive)"]) -> None:
      if age < 0:
          raise ValueError("Age must be a positive integer.")
      print(f"Processing age: {age}")
  
  process_data(25)

2. TypedDict

TypedDict is a dictionary with a defined schema. It ensures all dictionary keys and their associated values follow strict type rules.

  from typing_extensions import TypedDict

  class User(TypedDict):
      name: str
      age: int

  user: User = {"name": "John", "age": 30}
  print(user)

3. Literal

Use Literal to restrict arguments to specific, pre-defined options.

  from typing_extensions import Literal

  def set_status(status: Literal["active", "inactive", "pending"]) -> None:
      print(f"Status is set to: {status}")

  set_status("active")

4. Final

Final allows marking constants or methods as immutable or un-overridable.

  from typing_extensions import Final

  MAX_USERS: Final = 100

  MAX_USERS = 200  # This will raise an error in static analysis tools.

5. Protocol

Protocol defines an interface that a class must adhere to, similar to abstract base classes.

  from typing_extensions import Protocol
  
  class SupportsFly(Protocol):
      def fly(self) -> None:
          ...

  class Bird:
      def fly(self) -> None:
          print("Flying!")

  def make_it_fly(obj: SupportsFly) -> None:
      obj.fly()

  bird = Bird()
  make_it_fly(bird)

6. Self

Self is useful for defining methods that return the current instance type.

  from typing_extensions import Self

  class Builder:
      def set_feature_a(self) -> Self:
          print("Feature A set.")
          return self

      def set_feature_b(self) -> Self:
          print("Feature B set.")
          return self

  builder = Builder().set_feature_a().set_feature_b()

Real-World Example: A Typed Configuration Manager

Below, we’ll showcase how typing-extensions can be leveraged to create a configuration manager for a Python application using TypedDict, Annotated, and Protocol.

  from typing_extensions import TypedDict, Annotated, Protocol

  # Define the configuration schema using TypedDict
  class AppConfig(TypedDict):
      debug: Annotated[bool, "Enable debugging or not"]
      host: Annotated[str, "Hostname or IP address"]
      port: Annotated[int, "Port number"]

  # Define a manager interface using Protocol
  class ConfigManager(Protocol):
      def load(self) -> AppConfig:
          ...
      def save(self, config: AppConfig) -> None:
          ...

  # Implement the ConfigManager interface
  class FileConfigManager:
      def __init__(self, file_path: str) -> None:
          self.file_path = file_path

      def load(self) -> AppConfig:
          return {"debug": True, "host": "localhost", "port": 8080}

      def save(self, config: AppConfig) -> None:
          print(f"Config saved to {self.file_path}: {config}")

  # Usage
  manager: ConfigManager = FileConfigManager("./config.json")
  config = manager.load()
  print(f"Loaded config: {config}")
  manager.save(config)

Conclusion

With typing-extensions, Python developers can embrace the full power of type hints to write more expressive, maintainable, and error-free code. From defining custom metadata with Annotated to strictly typing your application states with TypedDict, this library serves as a perfect companion for Python’s built-in typing module. Start using it in your projects today to take your Python skills to the next level!

Leave a Reply

Your email address will not be published. Required fields are marked *