Robust Python

Book description

Does it seem like your Python projects are getting bigger and bigger? Are you feeling the pain as your codebase expands and gets tougher to debug and maintain? Python is an easy language to learn and use, but that also means systems can quickly grow beyond comprehension. Thankfully, Python has features to help developers overcome maintainability woes.

In this practical book, author Patrick Viafore shows you how to use Python's type system to the max. You'll look at user-defined types, such as classes and enums, and Python's type hinting system. You'll also learn how to make Python extensible and how to use a comprehensive testing strategy as a safety net. With these tips and techniques, you'll write clearer and more maintainable code.

  • Learn why types are essential in modern development ecosystems
  • Understand how type choices such as classes, dictionaries, and enums reflect specific intents
  • Make Python extensible for the future without adding bloat
  • Use popular Python tools to increase the safety and robustness of your codebase
  • Evaluate current code to detect common maintainability gotchas
  • Build a safety net around your codebase with linters and tests

Table of contents

  1. Preface
    1. Who Should Read This Book
    2. About This Book
    3. Conventions Used in This Book
    4. Using Code Examples
    5. O’Reilly Online Learning
    6. How to Contact Us
    7. Acknowledgments
  2. 1. Introduction to Robust Python
    1. Robustness
      1. Why Does Robustness Matter?
    2. What’s Your Intent?
      1. Asynchronous Communication
    3. Examples of Intent in Python
      1. Collections
      2. Iteration
      3. Law of Least Surprise
    4. Closing Thoughts
  3. I. Annotating Your Code with Types
  4. 2. Introduction to Python Types
    1. What’s in a Type?
      1. Mechanical Representation
      2. Semantic Representation
    2. Typing Systems
      1. Strong Versus Weak
      2. Dynamic Versus Static
      3. Duck Typing
    3. Closing Thoughts
  5. 3. Type Annotations
    1. What Are Type Annotations?
    2. Benefits of Type Annotations
      1. Autocomplete
      2. Typecheckers
      3. Exercise: Spot the Bug
    3. When to Use Type Annotations
    4. Closing Thoughts
  6. 4. Constraining Types
    1. Optional Type
    2. Union Types
      1. Product and Sum Types
    3. Literal Types
    4. Annotated Types
    5. NewType
    6. Final Types
    7. Closing Thoughts
  7. 5. Collection Types
    1. Annotating Collections
    2. Homogeneous Versus Heterogeneous Collections
    3. TypedDict
    4. Creating New Collections
      1. Generics
      2. Modifying Existing Types
      3. As Easy as ABC
    5. Closing Thoughts
  8. 6. Customizing Your Typechecker
    1. Configuring Your Typechecker
      1. Configuring mypy
      2. Mypy Reporting
      3. Speeding Up mypy
    2. Alternative Typecheckers
      1. Pyre
      2. Pyright
    3. Closing Thoughts
  9. 7. Adopting Typechecking Practically
    1. Trade-offs
    2. Breaking Even Earlier
      1. Find Your Pain Points
      2. Target Code Strategically
      3. Lean on Your Tooling
    3. Closing Thoughts
  10. II. Defining Your Own Types
  11. 8. User-Defined Types: Enums
    1. User-Defined Types
    2. Enumerations
      1. Enum
      2. When Not to Use
    3. Advanced Usage
      1. Automatic Values
      2. Flags
      3. Integer Conversion
      4. Unique
    4. Closing Thoughts
  12. 9. User-Defined Types: Data Classes
    1. Data Classes in Action
    2. Usage
      1. String Conversion
      2. Equality
      3. Relational Comparison
      4. Immutability
    3. Comparison to Other Types
      1. Data Classes Versus Dictionaries
      2. Data Classes Versus TypedDict
      3. Data Classes Versus namedtuple
    4. Closing Thoughts
  13. 10. User-Defined Types: Classes
    1. Class Anatomy
      1. Constructors
    2. Invariants
      1. Avoiding Broken Invariants
      2. Why Are Invariants Beneficial?
      3. Communicating Invariants
      4. Consuming Your Class
      5. What About Maintainers?
    3. Encapsulation and Maintaining Invariants
      1. Encapsul-what, Now?
      2. Protecting Data Access
      3. Operations
    4. Closing Thoughts
  14. 11. Defining Your Interfaces
    1. Natural Interface Design
      1. Thinking Like a User
    2. Natural Interactions
      1. Natural Interfaces in Action
      2. Magic Methods
      3. Context Managers
    3. Closing Thoughts
  15. 12. Subtyping
    1. Inheritance
    2. Substitutability
    3. Design Considerations
      1. Composition
    4. Closing Thoughts
  16. 13. Protocols
    1. Tension Between Typing Systems
      1. Leave the Type Blank or Use Any
      2. Use a Union
      3. Use Inheritance
      4. Use Mixins
    2. Protocols
      1. Defining a Protocol
    3. Advanced Usage
      1. Composite Protocols
      2. Runtime Checkable Protocols
      3. Modules Satisfying Protocols
    4. Closing Thoughts
  17. 14. Runtime Checking With pydantic
    1. Dynamic Configuration
    2. pydantic
      1. Validators
      2. Validation Versus Parsing
    3. Closing Thoughts
  18. III. Extensible Python
  19. 15. Extensibility
    1. What Is Extensibility?
      1. The Redesign
    2. Open-Closed Principle
      1. Detecting OCP Violations
      2. Drawbacks
    3. Closing Thoughts
  20. 16. Dependencies
    1. Relationships
    2. Types of Dependencies
      1. Physical Dependencies
      2. Logical Dependencies
      3. Temporal Dependencies
    3. Visualizing Your Dependencies
      1. Visualizing Packages
      2. Visualizing Imports
      3. Visualizing Function Calls
      4. Interpreting Your Dependency Graph
    4. Closing Thoughts
  21. 17. Composability
    1. Composability
    2. Policy Versus Mechanisms
    3. Composing on a Smaller Scale
      1. Composing Functions
      2. Composing Algorithms
    4. Closing Thoughts
  22. 18. Event-Driven Architecture
    1. How It Works
      1. Drawbacks
    2. Simple Events
      1. Using a Message Broker
      2. The Observer Pattern
    3. Streaming Events
    4. Closing Thoughts
  23. 19. Pluggable Python
    1. The Template Method Pattern
    2. The Strategy Pattern
    3. Plug-in Architectures
    4. Closing Thoughts
  24. IV. Building a Safety Net
  25. 20. Static Analysis
    1. Linting
      1. Writing Your Own Pylint Plug-in
      2. Breaking Down the Plug-in
    2. Other Static Analyzers
      1. Complexity Checkers
      2. Security Analysis
    3. Closing Thoughts
  26. 21. Testing Strategy
    1. Defining Your Test Strategy
      1. What Is a Test?
    2. Reducing Test Cost
      1. AAA Testing
    3. Closing Thoughts
  27. 22. Acceptance Testing
    1. Behavior-Driven Development
      1. The Gherkin Language
      2. Executable Specifications
    2. Additional behave Features
      1. Parameterized Steps
      2. Table-Driven Requirements
      3. Step Matching
      4. Customizing the Test Life Cycle
      5. Using Tags to Selectively Run Tests
      6. Report Generation
    3. Closing Thoughts
  28. 23. Property-Based Testing
    1. Property-Based Testing with Hypothesis
      1. The Magic of Hypothesis
      2. Contrast with Traditional Tests
    2. Getting the Most Out of Hypothesis
      1. Hypothesis Strategies
      2. Generating Algorithms
    3. Closing Thoughts
  29. 24. Mutation Testing
    1. What Is Mutation Testing?
    2. Mutation Testing with mutmut
      1. Fixing Mutants
      2. Mutation Testing Reports
    3. Adopting Mutation Testing
      1. The Fallacy of Coverage (and Other Metrics)
    4. Closing Thoughts
  30. Index

Product information

  • Title: Robust Python
  • Author(s): Patrick Viafore
  • Release date: July 2021
  • Publisher(s): O'Reilly Media, Inc.
  • ISBN: 9781098100667