or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

tessl/pypi-singleton-decorator

A testable singleton decorator that allows easily creating singleton objects by adding a decorator to class definitions while maintaining testability.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/singleton-decorator@1.0.x

To install, run

npx @tessl/cli install tessl/pypi-singleton-decorator@1.0.0

0

# Singleton Decorator

1

2

A testable singleton decorator that allows easily creating singleton objects by adding a decorator to class definitions while maintaining testability. Unlike traditional singleton implementations that make direct class access impossible in unit tests, this decorator uses a wrapper object that stores the original class in a `__wrapped__` attribute, allowing developers to access the decorated class directly for isolated testing.

3

4

## Package Information

5

6

- **Package Name**: singleton-decorator

7

- **Language**: Python

8

- **Installation**: `pip install singleton-decorator`

9

10

## Core Imports

11

12

```python

13

from singleton_decorator import singleton

14

```

15

16

Version information:

17

18

```python

19

from singleton_decorator import __version__

20

```

21

22

## Basic Usage

23

24

```python

25

from singleton_decorator import singleton

26

27

@singleton

28

class DatabaseConnection:

29

def __init__(self, host, port):

30

self.host = host

31

self.port = port

32

print(f"Connecting to {host}:{port}")

33

34

def query(self, sql):

35

return f"Executing: {sql}"

36

37

# First call creates the instance

38

db1 = DatabaseConnection("localhost", 5432)

39

# Subsequent calls return the same instance (constructor args ignored)

40

db2 = DatabaseConnection("ignored", 9999)

41

db3 = DatabaseConnection("also_ignored", 1111)

42

43

# All variables reference the same instance

44

assert db1 is db2 is db3

45

print(db1.host) # "localhost"

46

print(db2.host) # "localhost" (not "ignored")

47

```

48

49

## Capabilities

50

51

### Singleton Decorator

52

53

Creates a singleton wrapper for any class, ensuring only one instance exists while maintaining testability through the `__wrapped__` attribute.

54

55

```python { .api }

56

def singleton(cls):

57

"""

58

A singleton decorator that returns a wrapper object. A call on that object

59

returns a single instance object of decorated class. Use the __wrapped__

60

attribute to access decorated class directly in unit tests.

61

62

Args:

63

cls: The class to decorate as a singleton

64

65

Returns:

66

_SingletonWrapper: Wrapper object that manages singleton instance

67

"""

68

```

69

70

### Testing Access

71

72

Access the original class for isolated unit testing without singleton behavior.

73

74

```python { .api }

75

# Access pattern for testing

76

decorated_class.__wrapped__ # Original class for direct method calls

77

```

78

79

**Usage in Tests:**

80

81

```python

82

from unittest import TestCase, mock

83

from singleton_decorator import singleton

84

85

@singleton

86

class MyService:

87

def __init__(self, config):

88

self.config = config

89

90

def process_data(self, data):

91

return f"Processing {data} with {self.config}"

92

93

class TestMyService(TestCase):

94

def test_process_data(self):

95

# Use __wrapped__ to test method in isolation

96

mock_self = mock.MagicMock()

97

mock_self.config = "test_config"

98

99

result = MyService.__wrapped__.process_data(mock_self, "test_data")

100

101

assert result == "Processing test_data with test_config"

102

```

103

104

## Types and Implementation Details

105

106

```python { .api }

107

class _SingletonWrapper:

108

"""

109

Internal wrapper class created for each decorated class.

110

Manages singleton instance lifecycle.

111

"""

112

113

def __init__(self, cls):

114

"""

115

Initialize wrapper with the decorated class.

116

117

Args:

118

cls: The class to wrap

119

"""

120

121

def __call__(self, *args, **kwargs):

122

"""

123

Returns singleton instance of wrapped class.

124

Creates instance on first call, returns existing instance thereafter.

125

126

Args:

127

*args: Constructor arguments (only used on first call)

128

**kwargs: Constructor keyword arguments (only used on first call)

129

130

Returns:

131

object: Single instance of the wrapped class

132

"""

133

134

__wrapped__: type # Original decorated class for testing access

135

_instance: object # Singleton instance (None until first call)

136

137

__version__: str # Package version constant ("1.0.0")

138

```

139

140

## Important Notes

141

142

### Constructor Behavior

143

144

- The `__init__` method is called **only once** with arguments from the first instantiation

145

- All subsequent instantiation attempts ignore their arguments and return the existing instance

146

- This behavior ensures true singleton semantics but requires careful consideration of constructor arguments

147

148

### Testing Guidelines

149

150

- Use `ClassName.__wrapped__` to access the original class in unit tests

151

- Pass mock objects as `self` to test methods in complete isolation

152

- This approach avoids constructor dependencies and maintains test isolation

153

- The `__wrapped__` attribute provides direct access to all class methods and attributes

154

155

### Thread Safety

156

157

This implementation does not provide thread-safety guarantees. In multi-threaded environments, consider additional synchronization mechanisms if concurrent access to the singleton creation is possible.