or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

tessl/pypi-rodi

Implementation of dependency injection for Python 3

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/rodi@2.0.x

To install, run

npx @tessl/cli install tessl/pypi-rodi@2.0.0

0

# Rodi

1

2

Implementation of dependency injection for Python 3 that enables automatic resolution of service dependencies through type annotations and class signatures. Rodi provides flexible service registration patterns including singleton, transient, and scoped lifestyles with minimal runtime overhead through code inspection and dynamic function generation.

3

4

## Package Information

5

6

- **Package Name**: rodi

7

- **Language**: Python

8

- **Installation**: `pip install rodi`

9

10

## Core Imports

11

12

```python

13

from rodi import Container, Services, ActivationScope

14

```

15

16

Protocol-based interface:

17

18

```python

19

from rodi import ContainerProtocol

20

```

21

22

## Basic Usage

23

24

```python

25

from rodi import Container

26

27

# Basic type registration and resolution

28

class DatabaseService:

29

def get_data(self):

30

return "data from database"

31

32

class UserService:

33

def __init__(self, db: DatabaseService):

34

self.db = db

35

36

def get_user(self, user_id: int):

37

return f"User {user_id}: {self.db.get_data()}"

38

39

# Create container and register services

40

container = Container()

41

container.register(DatabaseService)

42

container.register(UserService)

43

44

# Resolve services - dependencies are automatically injected

45

user_service = container.resolve(UserService)

46

print(user_service.get_user(123))

47

```

48

49

## Architecture

50

51

Rodi uses a two-phase approach for efficient dependency injection:

52

53

- **Configuration Phase**: Services are registered with the Container, which inspects types once to build dependency graphs

54

- **Resolution Phase**: The built Services provider quickly activates instances using pre-generated functions

55

56

The architecture supports different service lifestyles:

57

- **Singleton**: Single instance per container

58

- **Transient**: New instance every time

59

- **Scoped**: Single instance per scope (e.g., per web request)

60

61

Key components:

62

- **Container**: Configuration and registration

63

- **Services**: Fast service activation

64

- **ActivationScope**: Scoped service management

65

66

## Capabilities

67

68

### Container Configuration

69

70

Core service registration and container configuration functionality. The Container class provides methods for registering services with different lifestyles and building the service provider.

71

72

```python { .api }

73

class Container:

74

def __init__(self, *, strict: bool = False, scope_cls: Optional[Type[ActivationScope]] = None): ...

75

def register(self, obj_type, sub_type=None, instance=None, *args, **kwargs) -> Container: ...

76

def add_singleton(self, base_type: Type, concrete_type: Optional[Type] = None) -> Container: ...

77

def add_transient(self, base_type: Type, concrete_type: Optional[Type] = None) -> Container: ...

78

def add_scoped(self, base_type: Type, concrete_type: Optional[Type] = None) -> Container: ...

79

def build_provider(self) -> Services: ...

80

```

81

82

[Container Configuration](./container-configuration.md)

83

84

### Service Resolution

85

86

Service activation and dependency resolution through the Services provider. Provides efficient service lookup and instantiation with support for scoped resolution.

87

88

```python { .api }

89

class Services:

90

def __init__(self, services_map=None, scope_cls: Optional[Type[ActivationScope]] = None): ...

91

def get(self, desired_type: Union[Type[T], str], scope: Optional[ActivationScope] = None, *, default: Optional[Any] = ...) -> T: ...

92

def create_scope(self, scoped: Optional[Dict[Union[Type, str], Any]] = None) -> ActivationScope: ...

93

def exec(self, method: Callable, scoped: Optional[Dict[Type, Any]] = None) -> Any: ...

94

```

95

96

[Service Resolution](./service-resolution.md)

97

98

### Scoped Services

99

100

Scoped service management through ActivationScope context managers. Enables per-request or per-operation service scoping with automatic cleanup.

101

102

```python { .api }

103

class ActivationScope:

104

def __init__(self, provider: Optional[Services] = None, scoped_services: Optional[Dict[Union[Type[T], str], T]] = None): ...

105

def get(self, desired_type: Union[Type[T], str], scope: Optional[ActivationScope] = None, *, default: Optional[Any] = ...) -> T: ...

106

def dispose(self): ...

107

def __enter__(self): ...

108

def __exit__(self, exc_type, exc_val, exc_tb): ...

109

```

110

111

[Scoped Services](./scoped-services.md)

112

113

### Factory Registration

114

115

Advanced service registration using factory functions for complex instantiation scenarios. Supports different factory signatures and service lifestyles.

116

117

```python { .api }

118

def add_singleton_by_factory(self, factory: FactoryCallableType, return_type: Optional[Type] = None) -> Container: ...

119

def add_transient_by_factory(self, factory: FactoryCallableType, return_type: Optional[Type] = None) -> Container: ...

120

def add_scoped_by_factory(self, factory: FactoryCallableType, return_type: Optional[Type] = None) -> Container: ...

121

```

122

123

[Factory Registration](./factory-registration.md)

124

125

### Aliases and Names

126

127

Convention-based service registration and resolution using string names and aliases instead of type annotations.

128

129

```python { .api }

130

def add_alias(self, name: str, desired_type: Type) -> Container: ...

131

def add_aliases(self, values: AliasesTypeHint) -> Container: ...

132

def set_alias(self, name: str, desired_type: Type, override: bool = False) -> Container: ...

133

```

134

135

[Aliases and Names](./aliases-names.md)

136

137

## Types

138

139

```python { .api }

140

class ContainerProtocol(Protocol):

141

def register(self, obj_type: Union[Type, str], *args, **kwargs): ...

142

def resolve(self, obj_type: Union[Type[T], str], *args, **kwargs) -> T: ...

143

def __contains__(self, item) -> bool: ...

144

145

class ServiceLifeStyle(Enum):

146

TRANSIENT = 1

147

SCOPED = 2

148

SINGLETON = 3

149

150

AliasesTypeHint = Dict[str, Type]

151

152

FactoryCallableNoArguments = Callable[[], Any]

153

FactoryCallableSingleArgument = Callable[[ActivationScope], Any]

154

FactoryCallableTwoArguments = Callable[[ActivationScope, Type], Any]

155

FactoryCallableType = Union[FactoryCallableNoArguments, FactoryCallableSingleArgument, FactoryCallableTwoArguments]

156

```

157

158

## Decorators and Utilities

159

160

```python { .api }

161

def inject(globalsns=None, localns=None) -> Callable[..., Any]:

162

"""

163

Marks a class or function as injected. Required for Python >= 3.10 with locals.

164

165

Returns:

166

Decorator function that binds locals/globals to the target

167

"""

168

169

def class_name(input_type) -> str:

170

"""

171

Gets the name of a type, handling generic types.

172

173

Args:

174

input_type: Type to get name for

175

176

Returns:

177

String name of the type

178

"""

179

180

def to_standard_param_name(name) -> str:

181

"""

182

Convert class names to standard parameter names following Python conventions.

183

184

Args:

185

name: Class name to convert

186

187

Returns:

188

Converted parameter name (e.g., "UserService" -> "user_service")

189

"""

190

```

191

192

## Exception Handling

193

194

Rodi provides specific exceptions for different error scenarios:

195

196

```python { .api }

197

class DIException(Exception): ...

198

class CannotResolveTypeException(DIException): ...

199

class CannotResolveParameterException(DIException): ...

200

class CircularDependencyException(DIException): ...

201

class OverridingServiceException(DIException): ...

202

class InvalidOperationInStrictMode(DIException): ...

203

class AliasAlreadyDefined(DIException): ...

204

class AliasConfigurationError(DIException): ...

205

class MissingTypeException(DIException): ...

206

class InvalidFactory(DIException): ...

207

class FactoryMissingContextException(DIException): ...

208

```