pyarallel 0.1.2__tar.gz → 0.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. {pyarallel-0.1.2 → pyarallel-0.1.3}/PKG-INFO +51 -1
  2. {pyarallel-0.1.2 → pyarallel-0.1.3}/README.md +50 -0
  3. {pyarallel-0.1.2 → pyarallel-0.1.3}/TASKS.md +35 -5
  4. {pyarallel-0.1.2 → pyarallel-0.1.3}/docs/development/roadmap.md +4 -0
  5. {pyarallel-0.1.2 → pyarallel-0.1.3}/docs/index.md +40 -0
  6. {pyarallel-0.1.2 → pyarallel-0.1.3}/pyarallel/__init__.py +2 -2
  7. {pyarallel-0.1.2 → pyarallel-0.1.3}/pyarallel/config.py +30 -48
  8. {pyarallel-0.1.2 → pyarallel-0.1.3}/pyarallel/config_manager.py +74 -48
  9. {pyarallel-0.1.2 → pyarallel-0.1.3}/pyarallel/core.py +209 -92
  10. {pyarallel-0.1.2 → pyarallel-0.1.3}/pyarallel/env_config.py +5 -4
  11. {pyarallel-0.1.2 → pyarallel-0.1.3}/pyproject.toml +1 -1
  12. {pyarallel-0.1.2 → pyarallel-0.1.3}/sandbox/sandbox_test.py +20 -29
  13. {pyarallel-0.1.2 → pyarallel-0.1.3}/setup.py +1 -1
  14. {pyarallel-0.1.2 → pyarallel-0.1.3}/tests/conftest.py +37 -25
  15. {pyarallel-0.1.2 → pyarallel-0.1.3}/tests/test_config_manager.py +11 -14
  16. {pyarallel-0.1.2 → pyarallel-0.1.3}/tests/test_decorator_config.py +48 -42
  17. {pyarallel-0.1.2 → pyarallel-0.1.3}/tests/test_env_config.py +15 -11
  18. pyarallel-0.1.3/tests/test_pyarallel.py +184 -0
  19. {pyarallel-0.1.2 → pyarallel-0.1.3}/tests/test_runtime_config.py +46 -41
  20. pyarallel-0.1.2/tests/test_pyarallel.py +0 -99
  21. {pyarallel-0.1.2 → pyarallel-0.1.3}/.gitignore +0 -0
  22. {pyarallel-0.1.2 → pyarallel-0.1.3}/.python-version +0 -0
  23. {pyarallel-0.1.2 → pyarallel-0.1.3}/CONTRIBUTING.md +0 -0
  24. {pyarallel-0.1.2 → pyarallel-0.1.3}/LICENSE.md +0 -0
  25. {pyarallel-0.1.2 → pyarallel-0.1.3}/Makefile +0 -0
  26. {pyarallel-0.1.2 → pyarallel-0.1.3}/docs/api-reference/configuration-api.md +0 -0
  27. {pyarallel-0.1.2 → pyarallel-0.1.3}/docs/api-reference/decorators.md +0 -0
  28. {pyarallel-0.1.2 → pyarallel-0.1.3}/docs/api-reference/rate-limiting.md +0 -0
  29. {pyarallel-0.1.2 → pyarallel-0.1.3}/docs/development/CONTRIBUTING.md +0 -0
  30. {pyarallel-0.1.2 → pyarallel-0.1.3}/docs/getting-started/installation.md +0 -0
  31. {pyarallel-0.1.2 → pyarallel-0.1.3}/docs/getting-started/quickstart.md +0 -0
  32. {pyarallel-0.1.2 → pyarallel-0.1.3}/docs/user-guide/advanced-features.md +0 -0
  33. {pyarallel-0.1.2 → pyarallel-0.1.3}/docs/user-guide/best-practices.md +0 -0
  34. {pyarallel-0.1.2 → pyarallel-0.1.3}/docs/user-guide/configuration.md +0 -0
  35. {pyarallel-0.1.2 → pyarallel-0.1.3}/mkdocs.yml +0 -0
  36. {pyarallel-0.1.2 → pyarallel-0.1.3}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyarallel
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: A powerful parallel execution library for Python
5
5
  Project-URL: Homepage, https://github.com/oneryalcin/pyarallel
6
6
  Project-URL: Repository, https://github.com/oneryalcin/pyarallel.git
@@ -98,6 +98,56 @@ def analyze_text(text: str) -> dict:
98
98
  return text_analysis(text)
99
99
  ```
100
100
 
101
+ ## Usage Examples
102
+
103
+ ### Basic Function
104
+ ```python
105
+ from pyarallel import parallel
106
+
107
+ @parallel
108
+ def process_item(x):
109
+ return x * 2
110
+
111
+ results = process_item([1, 2, 3]) # [2, 4, 6]
112
+ ```
113
+
114
+ ### Instance Methods
115
+ ```python
116
+ class DataProcessor:
117
+ def __init__(self, multiplier):
118
+ self.multiplier = multiplier
119
+
120
+ @parallel
121
+ def process(self, x):
122
+ return x * self.multiplier
123
+
124
+ processor = DataProcessor(3)
125
+ results = processor.process([1, 2, 3]) # [3, 6, 9]
126
+ ```
127
+
128
+ ### Class Methods
129
+ ```python
130
+ class StringFormatter:
131
+ @classmethod
132
+ @parallel
133
+ def format_all(cls, items):
134
+ return [f"Formatted-{item}" for item in items]
135
+
136
+ results = StringFormatter.format_all(['a', 'b', 'c'])
137
+ # ['Formatted-a', 'Formatted-b', 'Formatted-c']
138
+ ```
139
+
140
+ ### Static Methods
141
+ ```python
142
+ class MathUtils:
143
+ @staticmethod
144
+ @parallel
145
+ def square_all(numbers):
146
+ return [n**2 for n in numbers]
147
+
148
+ results = MathUtils.square_all([1, 2, 3]) # [1, 4, 9]
149
+ ```
150
+
101
151
  ## Advanced Usage
102
152
 
103
153
  ### Rate Limiting
@@ -59,6 +59,56 @@ def analyze_text(text: str) -> dict:
59
59
  return text_analysis(text)
60
60
  ```
61
61
 
62
+ ## Usage Examples
63
+
64
+ ### Basic Function
65
+ ```python
66
+ from pyarallel import parallel
67
+
68
+ @parallel
69
+ def process_item(x):
70
+ return x * 2
71
+
72
+ results = process_item([1, 2, 3]) # [2, 4, 6]
73
+ ```
74
+
75
+ ### Instance Methods
76
+ ```python
77
+ class DataProcessor:
78
+ def __init__(self, multiplier):
79
+ self.multiplier = multiplier
80
+
81
+ @parallel
82
+ def process(self, x):
83
+ return x * self.multiplier
84
+
85
+ processor = DataProcessor(3)
86
+ results = processor.process([1, 2, 3]) # [3, 6, 9]
87
+ ```
88
+
89
+ ### Class Methods
90
+ ```python
91
+ class StringFormatter:
92
+ @classmethod
93
+ @parallel
94
+ def format_all(cls, items):
95
+ return [f"Formatted-{item}" for item in items]
96
+
97
+ results = StringFormatter.format_all(['a', 'b', 'c'])
98
+ # ['Formatted-a', 'Formatted-b', 'Formatted-c']
99
+ ```
100
+
101
+ ### Static Methods
102
+ ```python
103
+ class MathUtils:
104
+ @staticmethod
105
+ @parallel
106
+ def square_all(numbers):
107
+ return [n**2 for n in numbers]
108
+
109
+ results = MathUtils.square_all([1, 2, 3]) # [1, 4, 9]
110
+ ```
111
+
62
112
  ## Advanced Usage
63
113
 
64
114
  ### Rate Limiting
@@ -72,11 +72,11 @@ def test_runtime_warnings():
72
72
  """Warnings for problematic configs"""
73
73
  ```
74
74
 
75
- ## 5. Documentation [ ]
76
- - [ ] Add configuration section to README
77
- - [ ] Document all environment variables
78
- - [ ] Add configuration examples
79
- - [ ] Document best practices
75
+ ## 5. Documentation []
76
+ - [] Add configuration section to README
77
+ - [] Document all environment variables
78
+ - [] Add configuration examples
79
+ - [] Document best practices
80
80
 
81
81
  ## Configuration Schema
82
82
  ```python
@@ -121,3 +121,33 @@ PYARALLEL_SENTRY_DSN=https://...
121
121
  - 🚧 In progress
122
122
  - ❌ Blocked
123
123
  - [ ] Not started
124
+
125
+ ## Feature: Enhanced Decorator Ergonomics
126
+
127
+ Implement first-class support for decorating instance, static, and class methods with `@parallel`.
128
+
129
+ - [✅] **1. Analyze Core Decorator Logic**
130
+ - [✅] Examine `@parallel` implementation in `pyarallel/core.py`.
131
+ - [✅] Understand current argument inspection and `executor.submit` usage.
132
+ - [✅] **2. Modify Argument Handling**
133
+ - [✅] Update the `wrapper` function to detect method type (instance, static, class).
134
+ - [✅] Correctly identify the iterable/item argument based on method type (using `inspect` or signature analysis).
135
+ - [✅] **3. Adapt Executor Submission**
136
+ - [✅] Ensure `self`/`cls` are passed correctly to `executor.submit` for instance/class methods.
137
+ - [✅] Preserve other arguments (`*args`, `**kwargs`).
138
+ - [✅] **4. Implement Comprehensive Tests**
139
+ - [✅] Add tests for instance methods (`test_instance_method_parallel`).
140
+ - [✅] Add tests for static methods (`test_static_method_parallel`).
141
+ - [✅] Add tests for class methods (`test_class_method_parallel`).
142
+ - [✅] Include tests for single item and list inputs.
143
+ - [✅] Test methods with additional arguments.
144
+ - [✅] Ensure no regressions for regular functions.
145
+ - [✅] **5. Update Documentation**
146
+ - [✅] Update `README.md` and `docs/index.md` with clear examples for each method type.
147
+ - [✅] **6. Code Review and Refinement**
148
+ - [✅] Review implementation, tests, and documentation.
149
+ - [✅] Ensure robustness, adherence to standards, and clarity.
150
+ - [✅] **7. Add Type Hints**
151
+ - [✅] Add type hints to the `@parallel` decorator and inner `wrapper` in `pyarallel/core.py` for better IDE support.
152
+
153
+ ## Future Enhancements / Ideas
@@ -56,6 +56,10 @@ Some of the features we're planning to add in the future:
56
56
  - Resource quotas per task
57
57
 
58
58
  ### Developer Experience
59
+ - **Enhanced Decorator Ergonomics**
60
+ - First-class, documented support for `@parallel` on instance methods, static methods, and class methods.
61
+ - Automatic handling of `self` and `cls` arguments.
62
+ - Clear examples and best practices for OOP usage.
59
63
  - **CLI Tools**
60
64
  - Task monitoring dashboard
61
65
  - Performance profiling
@@ -36,6 +36,46 @@ urls = ["http://api1.com", "http://api2.com"]
36
36
  results = fetch_url(urls)
37
37
  ```
38
38
 
39
+ ## Advanced Usage
40
+
41
+ ### Method Support
42
+
43
+ The `@parallel` decorator works seamlessly with:
44
+ - Regular functions
45
+ - Instance methods (preserves `self`)
46
+ - Class methods (preserves `cls`)
47
+ - Static methods
48
+
49
+ #### Instance Method Example
50
+ ```python
51
+ class DataTransformer:
52
+ def __init__(self, base):
53
+ self.base = base
54
+
55
+ @parallel
56
+ def transform(self, items):
57
+ return [self.base + x for x in items]
58
+ ```
59
+
60
+ #### Class Method Example
61
+ ```python
62
+ class Logger:
63
+ log_prefix = "APP"
64
+
65
+ @classmethod
66
+ @parallel
67
+ def log_all(cls, messages):
68
+ return [f"{cls.log_prefix}: {msg}" for msg in messages]
69
+ ```
70
+
71
+ ### Argument Handling
72
+
73
+ The decorator intelligently handles:
74
+ - Positional arguments
75
+ - Keyword arguments
76
+ - Mixed argument types
77
+ - Both single items and iterables
78
+
39
79
  ## Installation
40
80
 
41
81
  ```bash
@@ -1,4 +1,4 @@
1
- from .core import parallel, RateLimit
1
+ from .core import RateLimit, parallel
2
2
 
3
3
  __version__ = "0.1.0"
4
4
  __all__ = ["parallel", "RateLimit"]
@@ -7,4 +7,4 @@ __doc__ = f"""
7
7
  pyarallel v{__version__}
8
8
 
9
9
  Simple parallel processing framework for Python.
10
- """
10
+ """
@@ -7,49 +7,39 @@ with support for loading configurations from different sources and thread-safe o
7
7
  from pathlib import Path
8
8
  from typing import Any, Dict, Optional, Union
9
9
 
10
- from pydantic import BaseModel, Field, ConfigDict
10
+ from pydantic import BaseModel, ConfigDict, Field
11
11
 
12
12
 
13
13
  class ExecutionConfig(BaseModel):
14
14
  """Execution configuration settings."""
15
+
15
16
  max_workers: int = Field(
16
- default=4,
17
- description="Maximum number of worker processes/threads",
18
- ge=1
17
+ default=4, description="Maximum number of worker processes/threads", ge=1
19
18
  )
20
19
  timeout: float = Field(
21
20
  default=30.0,
22
21
  description="Default timeout for parallel operations in seconds",
23
- ge=0
22
+ ge=0,
24
23
  )
25
24
  default_max_workers: int = Field(
26
- default=4,
27
- description="Default number of workers for parallel operations",
28
- ge=1
25
+ default=4, description="Default number of workers for parallel operations", ge=1
29
26
  )
30
27
  default_executor_type: str = Field(
31
- default="thread",
32
- description="Default executor type (thread or process)"
28
+ default="thread", description="Default executor type (thread or process)"
33
29
  )
34
30
  default_batch_size: int = Field(
35
- default=10,
36
- description="Default batch size for parallel operations",
37
- ge=1
31
+ default=10, description="Default batch size for parallel operations", ge=1
38
32
  )
39
-
33
+
40
34
  model_config = ConfigDict(extra="allow") # Allow dynamic fields
41
35
 
36
+
42
37
  class RateLimitingConfig(BaseModel):
43
38
  """Rate limiting configuration settings."""
44
- rate: int = Field(
45
- default=1000,
46
- description="Rate limit per interval",
47
- ge=0
48
- )
49
- interval: str = Field(
50
- default="minute",
51
- description="Rate limit interval"
52
- )
39
+
40
+ rate: int = Field(default=1000, description="Rate limit per interval", ge=0)
41
+ interval: str = Field(default="minute", description="Rate limit interval")
42
+
53
43
 
54
44
  class PyarallelConfig(BaseModel):
55
45
  """Base configuration class for pyarallel.
@@ -60,57 +50,44 @@ class PyarallelConfig(BaseModel):
60
50
 
61
51
  # Execution settings
62
52
  max_workers: int = Field(
63
- default=4,
64
- description="Maximum number of worker processes/threads",
65
- ge=1
53
+ default=4, description="Maximum number of worker processes/threads", ge=1
66
54
  )
67
55
  timeout: float = Field(
68
56
  default=30.0,
69
57
  description="Default timeout for parallel operations in seconds",
70
- ge=0
58
+ ge=0,
71
59
  )
72
60
  execution: Optional[ExecutionConfig] = Field(
73
- default=None,
74
- description="Nested execution settings"
61
+ default=None, description="Nested execution settings"
75
62
  )
76
63
 
77
64
  # Rate limiting settings
78
65
  rate_limiting: Optional[RateLimitingConfig] = Field(
79
- default=None,
80
- description="Rate limiting settings"
66
+ default=None, description="Rate limiting settings"
81
67
  )
82
68
 
83
69
  # Error handling settings
84
70
  error_handling: Dict[str, Any] = Field(
85
71
  default_factory=lambda: {"retry_count": 3},
86
- description="Error handling settings"
72
+ description="Error handling settings",
87
73
  )
88
74
 
89
75
  # Monitoring settings
90
76
  monitoring: Dict[str, Any] = Field(
91
- default_factory=lambda: {"enabled": False},
92
- description="Monitoring settings"
77
+ default_factory=lambda: {"enabled": False}, description="Monitoring settings"
93
78
  )
94
79
 
95
80
  # Resource management
96
81
  memory_limit: Optional[int] = Field(
97
- default=None,
98
- description="Memory limit per worker in bytes, None for no limit"
82
+ default=None, description="Memory limit per worker in bytes, None for no limit"
99
83
  )
100
84
  cpu_affinity: bool = Field(
101
- default=False,
102
- description="Enable CPU affinity for workers"
85
+ default=False, description="Enable CPU affinity for workers"
103
86
  )
104
87
 
105
88
  # Logging and debugging
106
- debug: bool = Field(
107
- default=False,
108
- description="Enable debug mode"
109
- )
110
- log_level: str = Field(
111
- default="INFO",
112
- description="Logging level"
113
- )
89
+ debug: bool = Field(default=False, description="Enable debug mode")
90
+ log_level: str = Field(default="INFO", description="Logging level")
114
91
 
115
92
  @classmethod
116
93
  def from_dict(cls, config_dict: Dict[str, Any]) -> "PyarallelConfig":
@@ -148,18 +125,23 @@ class PyarallelConfig(BaseModel):
148
125
  # Load based on file extension
149
126
  if config_path.suffix == ".json":
150
127
  import json
128
+
151
129
  with open(config_path) as f:
152
130
  config_dict = json.load(f)
153
131
  elif config_path.suffix in (".yml", ".yaml"):
154
132
  import yaml
133
+
155
134
  with open(config_path) as f:
156
135
  config_dict = yaml.safe_load(f)
157
136
  elif config_path.suffix == ".toml":
158
137
  import toml
138
+
159
139
  with open(config_path) as f:
160
140
  config_dict = toml.load(f)
161
141
  else:
162
- raise ValueError(f"Unsupported configuration file format: {config_path.suffix}")
142
+ raise ValueError(
143
+ f"Unsupported configuration file format: {config_path.suffix}"
144
+ )
163
145
 
164
146
  return cls.from_dict(config_dict)
165
147
 
@@ -169,4 +151,4 @@ class PyarallelConfig(BaseModel):
169
151
  Returns:
170
152
  Dictionary representation of the configuration
171
153
  """
172
- return self.model_dump()
154
+ return self.model_dump()
@@ -13,7 +13,7 @@ from .env_config import load_env_vars
13
13
 
14
14
  logger = logging.getLogger(__name__)
15
15
 
16
- T = TypeVar('T', bound='ConfigManager')
16
+ T = TypeVar("T", bound="ConfigManager")
17
17
 
18
18
 
19
19
  class ConfigManager:
@@ -22,6 +22,7 @@ class ConfigManager:
22
22
  This class ensures thread-safe access to configuration settings and provides
23
23
  methods for updating and retrieving configuration values.
24
24
  """
25
+
25
26
  _instance: Optional[T] = None
26
27
  _lock: RLock = RLock()
27
28
  _config: Optional[PyarallelConfig] = None
@@ -34,18 +35,23 @@ class ConfigManager:
34
35
  # Initialize with default config
35
36
  config_dict = PyarallelConfig().model_dump()
36
37
  logger.debug(f"Default config: {config_dict}")
37
-
38
+
38
39
  # Load and apply environment variables
39
40
  env_config = load_env_vars()
40
41
  logger.debug(f"Loaded environment config: {env_config}")
41
-
42
+
42
43
  # Update config with environment variables
43
44
  if env_config:
44
45
  logger.debug("Updating config with environment variables")
45
- config_dict = {**config_dict, **env_config} # Use dictionary unpacking for proper update
46
+ config_dict = {
47
+ **config_dict,
48
+ **env_config,
49
+ } # Use dictionary unpacking for proper update
46
50
  logger.debug(f"Updated config: {config_dict}")
47
-
48
- cls._instance._config = PyarallelConfig(**config_dict) # Use direct instantiation
51
+
52
+ cls._instance._config = PyarallelConfig(
53
+ **config_dict
54
+ ) # Use direct instantiation
49
55
  logger.debug(f"Final config: {cls._instance._config}")
50
56
  return cls._instance
51
57
 
@@ -79,18 +85,20 @@ class ConfigManager:
79
85
  current_config = self._config.model_dump()
80
86
  logger.debug(f"Current config before update: {current_config}")
81
87
  logger.debug(f"Incoming updates: {updates}")
82
-
88
+
83
89
  # Validate max_workers before merging
84
90
  if "max_workers" in updates and updates["max_workers"] < 1:
85
91
  updates["max_workers"] = 1
86
-
92
+
87
93
  # Use deep merge for nested updates
88
94
  merged_config = self._deep_merge(current_config, updates)
89
95
  logger.debug(f"Merged config: {merged_config}")
90
96
  self._config = PyarallelConfig.from_dict(merged_config)
91
97
  logger.debug(f"Final config after update: {self._config}")
92
98
 
93
- def _deep_merge(self, base: Dict[str, Any], updates: Dict[str, Any]) -> Dict[str, Any]:
99
+ def _deep_merge(
100
+ self, base: Dict[str, Any], updates: Dict[str, Any]
101
+ ) -> Dict[str, Any]:
94
102
  """Recursively merge two configuration dictionaries with special handling for execution settings.
95
103
 
96
104
  This method implements a specialized merge strategy for configuration dictionaries that:
@@ -123,13 +131,13 @@ class ConfigManager:
123
131
  logger.debug(f"Deep merging - Base: {base}")
124
132
  logger.debug(f"Deep merging - Updates: {updates}")
125
133
  result = base.copy()
126
-
134
+
127
135
  # Initialize critical nested structures
128
136
  self._ensure_critical_structures(result)
129
-
137
+
130
138
  for key, value in updates.items():
131
139
  logger.debug(f"Processing key: {key}, value: {value}")
132
-
140
+
133
141
  if self._is_execution_update(key, value):
134
142
  self._handle_execution_settings(result, value)
135
143
  elif self._is_nested_dict_update(key, value, result):
@@ -137,11 +145,11 @@ class ConfigManager:
137
145
  else:
138
146
  result[key] = value
139
147
  logger.debug(f"Direct value assignment for key: {key}")
140
-
148
+
141
149
  # Re-ensure critical structures after each update
142
150
  self._ensure_critical_structures(result)
143
151
  logger.debug(f"Current result after processing {key}: {result}")
144
-
152
+
145
153
  return result
146
154
 
147
155
  def _ensure_critical_structures(self, config: Dict[str, Any]) -> None:
@@ -151,15 +159,17 @@ class ConfigManager:
151
159
  config: The configuration dictionary to initialize
152
160
  """
153
161
  critical_structures = {
154
- 'execution': {},
155
- 'rate_limiting': {},
156
- 'error_handling': {'retry_count': 3},
157
- 'monitoring': {'enabled': False}
162
+ "execution": {},
163
+ "rate_limiting": {},
164
+ "error_handling": {"retry_count": 3},
165
+ "monitoring": {"enabled": False},
158
166
  }
159
167
  for structure, default_value in critical_structures.items():
160
168
  if structure not in config or config[structure] is None:
161
169
  config[structure] = default_value.copy()
162
- logger.debug(f"Initialized {structure} structure with defaults: {default_value}")
170
+ logger.debug(
171
+ f"Initialized {structure} structure with defaults: {default_value}"
172
+ )
163
173
 
164
174
  def _is_execution_update(self, key: str, value: Any) -> bool:
165
175
  """Check if the update is for execution settings.
@@ -173,7 +183,9 @@ class ConfigManager:
173
183
  """
174
184
  return key == "execution" and isinstance(value, dict)
175
185
 
176
- def _is_nested_dict_update(self, key: str, value: Any, base: Dict[str, Any]) -> bool:
186
+ def _is_nested_dict_update(
187
+ self, key: str, value: Any, base: Dict[str, Any]
188
+ ) -> bool:
177
189
  """Check if the update is for a nested dictionary.
178
190
 
179
191
  Args:
@@ -184,11 +196,11 @@ class ConfigManager:
184
196
  Returns:
185
197
  bool: True if this is a nested dictionary update
186
198
  """
187
- return (key in base and
188
- isinstance(base[key], dict) and
189
- isinstance(value, dict))
199
+ return key in base and isinstance(base[key], dict) and isinstance(value, dict)
190
200
 
191
- def _handle_execution_settings(self, config: Dict[str, Any], execution_settings: Dict[str, Any]) -> None:
201
+ def _handle_execution_settings(
202
+ self, config: Dict[str, Any], execution_settings: Dict[str, Any]
203
+ ) -> None:
192
204
  """Handle special case of execution settings update.
193
205
 
194
206
  This method maintains both top-level and nested execution settings
@@ -201,19 +213,23 @@ class ConfigManager:
201
213
  # Update top-level settings for backward compatibility
202
214
  if "max_workers" in execution_settings:
203
215
  config["max_workers"] = execution_settings["max_workers"]
204
- logger.debug(f"Set top-level max_workers: {execution_settings['max_workers']}")
216
+ logger.debug(
217
+ f"Set top-level max_workers: {execution_settings['max_workers']}"
218
+ )
205
219
  if "timeout" in execution_settings:
206
220
  config["timeout"] = execution_settings["timeout"]
207
221
  logger.debug(f"Set top-level timeout: {execution_settings['timeout']}")
208
-
222
+
209
223
  # Initialize execution settings if None
210
224
  if config["execution"] is None:
211
225
  config["execution"] = {}
212
226
  logger.debug("Initialized empty execution settings")
213
-
227
+
214
228
  # Merge with existing execution settings
215
229
  config["execution"] = {**config["execution"], **execution_settings}
216
- logger.debug(f"Merged execution settings in nested structure: {config['execution']}")
230
+ logger.debug(
231
+ f"Merged execution settings in nested structure: {config['execution']}"
232
+ )
217
233
 
218
234
  def reset(self) -> None:
219
235
  """Reset the configuration to default values.
@@ -233,56 +249,66 @@ class ConfigManager:
233
249
  value: Value to set
234
250
  """
235
251
  with self._lock:
236
- parts = key.split('.')
252
+ parts = key.split(".")
237
253
  current = self._config.model_dump()
238
254
  target = current
239
255
  logger.debug(f"Setting config value - Key: {key}, Value: {value}")
240
256
  logger.debug(f"Current config state: {current}")
241
-
257
+
242
258
  # Handle execution settings at top level
243
- if parts[0] == 'execution' and len(parts) == 2:
244
- if parts[1] in ['max_workers', 'timeout']:
259
+ if parts[0] == "execution" and len(parts) == 2:
260
+ if parts[1] in ["max_workers", "timeout"]:
245
261
  target[parts[1]] = value
246
- logger.debug(f"Setting top-level execution parameter: {parts[1]} = {value}")
262
+ logger.debug(
263
+ f"Setting top-level execution parameter: {parts[1]} = {value}"
264
+ )
247
265
  else:
248
266
  # Create execution dictionary if needed
249
- if 'execution' not in target:
250
- target['execution'] = {}
251
- target['execution'][parts[1]] = value
252
- logger.debug(f"Setting nested execution parameter: {parts[1]} = {value}")
267
+ if "execution" not in target:
268
+ target["execution"] = {}
269
+ target["execution"][parts[1]] = value
270
+ logger.debug(
271
+ f"Setting nested execution parameter: {parts[1]} = {value}"
272
+ )
253
273
  else:
254
274
  # Initialize nested configuration objects if needed
255
- if parts[0] == 'rate_limiting' and target['rate_limiting'] is None:
256
- target['rate_limiting'] = {'rate': 1000, 'interval': 'minute'}
257
- logger.debug(f"Initialized rate_limiting config: {target['rate_limiting']}")
275
+ if parts[0] == "rate_limiting" and target["rate_limiting"] is None:
276
+ target["rate_limiting"] = {"rate": 1000, "interval": "minute"}
277
+ logger.debug(
278
+ f"Initialized rate_limiting config: {target['rate_limiting']}"
279
+ )
258
280
 
259
281
  # Navigate to the nested location
260
282
  for part in parts[:-1]:
261
283
  if part not in target:
262
284
  target[part] = {}
263
285
  target = target[part]
264
- logger.debug(f"Navigating to nested key: {part}, Current target: {target}")
286
+ logger.debug(
287
+ f"Navigating to nested key: {part}, Current target: {target}"
288
+ )
265
289
 
266
290
  # Set the value
267
291
  target[parts[-1]] = value
268
292
  logger.debug(f"Set final value at {parts[-1]}: {value}")
269
-
293
+
270
294
  logger.debug(f"Updated config state: {current}")
271
295
  self._config = PyarallelConfig.from_dict(current)
272
296
  logger.debug(f"Final config after update: {self._config}")
273
297
 
274
298
  def get(self, key: str, default: Any = None) -> Any:
275
- parts = key.split('.')
299
+ parts = key.split(".")
276
300
  current = self._config.model_dump()
277
301
  logger.debug(f"Getting config value - Key: {key}")
278
302
  logger.debug(f"Current config state: {current}")
279
303
 
280
304
  # Handle execution settings specially
281
- if parts[0] == 'execution':
282
- if current['execution'] is None:
305
+ if parts[0] == "execution":
306
+ if current["execution"] is None:
283
307
  # Check if the value exists at top level
284
- if len(parts) == 2 and parts[1] in ['max_workers', 'timeout']:
285
- logger.debug(f"Retrieving top-level {parts[1]} value: {current[parts[1]]}")
308
+ if len(parts) == 2 and parts[1] in ["max_workers", "timeout"]:
309
+ logger.debug(
310
+ f"Retrieving top-level {parts[1]} value: {current[parts[1]]}"
311
+ )
286
312
  return current[parts[1]]
287
313
  logger.debug("Execution config is None, returning default")
288
314
  return default
@@ -339,4 +365,4 @@ class ConfigManager:
339
365
  """
340
366
  with self._lock:
341
367
  updates = {"monitoring": kwargs}
342
- self.update_config(updates)
368
+ self.update_config(updates)