Getting Started

In this first tutorial, you’ll learn the basics of Varlord by creating a simple configuration and loading it from defaults.

Learning Objectives

By the end of this tutorial, you’ll be able to:

  • Define a configuration model using dataclasses

  • Load configuration from default values

  • Understand the basic structure of a Varlord application

Step 1: Define Your Configuration Model

First, let’s create a simple configuration model for a web application:

 1from dataclasses import dataclass, field
 2from varlord import Config
 3
 4@dataclass(frozen=True)
 5class AppConfig:
 6    host: str = field(default="127.0.0.1")
 7    port: int = field(default=8000)
 8    debug: bool = field(default=False)
 9    app_name: str = field(default="MyApp")
10
11# Create configuration
12# Model defaults are automatically applied - no need for sources.Defaults
13cfg = Config(
14    model=AppConfig,
15    sources=[],  # No sources needed - defaults are automatic
16)
17
18# Load configuration
19app = cfg.load()
20
21# Use configuration
22print(f"Starting {app.app_name} on {app.host}:{app.port}")
23print(f"Debug mode: {app.debug}")

Expected Output:

Starting MyApp on 127.0.0.1:8000
Debug mode: False

Key Points:

  • Use @dataclass(frozen=True) to create immutable configuration objects

  • Fields are automatically determined as required/optional: - Fields without defaults and not Optional[T] are required - Fields with Optional[T] type annotation are optional - Fields with defaults (or default_factory) are optional

  • Model defaults are automatically applied - no need for sources.Defaults

  • cfg.load() returns an instance of your configuration model

Step 2: Access Configuration Values

Configuration values can be accessed as attributes:

1app = cfg.load()
2
3# Access as attributes
4print(f"Host: {app.host}")
5print(f"Port: {app.port}")
6
7# Configuration is immutable (frozen=True)
8# app.host = "0.0.0.0"  # This would raise FrozenInstanceError

Expected Output:

Host: 127.0.0.1
Port: 8000

Important: Since we used frozen=True, configuration objects are immutable. This prevents accidental modification and ensures consistency.

Step 3: Complete Example

Here’s a complete working example:

 1from dataclasses import dataclass, field
 2from varlord import Config
 3
 4@dataclass(frozen=True)
 5class AppConfig:
 6    host: str = field(default="127.0.0.1")
 7    port: int = field(default=8000)
 8    debug: bool = field(default=False)
 9    app_name: str = field(default="MyApp")
10
11def main():
12    cfg = Config(
13        model=AppConfig,
14        sources=[],  # Defaults are automatically applied
15    )
16
17    app = cfg.load()
18    print(f"Configuration loaded:")
19    print(f"  App: {app.app_name}")
20    print(f"  Host: {app.host}")
21    print(f"  Port: {app.port}")
22    print(f"  Debug: {app.debug}")
23
24if __name__ == "__main__":
25    main()

Expected Output:

Configuration loaded:
  App: MyApp
  Host: 127.0.0.1
  Port: 8000
  Debug: False

Common Pitfalls

Pitfall 1: Forgetting to provide defaults

@dataclass(frozen=True)
class AppConfig:
    host: str  # Missing default value!
    port: int = 8000

# This will fail if no other source provides 'host'
app = cfg.load()  # May raise TypeError

Solution: Always provide default values for optional fields, or use Optional[T] type annotation for fields that may not be set.

Pitfall 4: Not using frozen dataclasses

@dataclass  # Missing frozen=True
class AppConfig:
    host: str = field(default="127.0.0.1")

app = cfg.load()
app.host = "0.0.0.0"  # This works, but breaks immutability!

Solution: Always use @dataclass(frozen=True) to ensure configuration immutability.

Best Practices

  1. Use descriptive field names: Choose clear, self-documenting names

  2. Fields are automatically determined: Use Optional[T] type annotation or default values for optional fields

  3. Provide sensible defaults: Defaults should work for development

  4. Use appropriate types: Use int, str, bool, Optional[T], etc. correctly

  5. Add field descriptions: Use metadata={"description": "..."} for better documentation

  6. Keep it simple: Start with defaults, add complexity as needed

Next Steps

Now that you understand the basics, let’s move on to Multiple Sources to learn how to load configuration from environment variables and command-line arguments.