0
# Configuration System
1
2
Hierarchical configuration system supporting workspace-level, plugin-specific, and document-specific settings with integration to external configuration files. Provides comprehensive configuration management for server behavior and plugin customization.
3
4
## Capabilities
5
6
### Config Class
7
8
Main configuration management class with hierarchical settings resolution.
9
10
```python { .api }
11
class Config:
12
def __init__(self, root_uri, init_opts, process_id, capabilities):
13
"""
14
Initialize configuration.
15
16
Parameters:
17
- root_uri: str, workspace root URI
18
- init_opts: dict, initialization options from client
19
- process_id: int, client process ID
20
- capabilities: dict, client capabilities
21
"""
22
23
@property
24
def disabled_plugins(self):
25
"""
26
Get list of disabled plugin names.
27
28
Returns:
29
list: Disabled plugin names
30
"""
31
32
@property
33
def plugin_manager(self):
34
"""
35
Get Pluggy plugin manager.
36
37
Returns:
38
PluginManager: Plugin manager instance
39
"""
40
41
@property
42
def init_opts(self):
43
"""
44
Get initialization options.
45
46
Returns:
47
dict: Client initialization options
48
"""
49
50
@property
51
def root_uri(self):
52
"""
53
Get workspace root URI.
54
55
Returns:
56
str: Root URI
57
"""
58
59
@property
60
def process_id(self):
61
"""
62
Get client process ID.
63
64
Returns:
65
int: Process ID
66
"""
67
68
@property
69
def capabilities(self):
70
"""
71
Get client capabilities.
72
73
Returns:
74
dict: Client capabilities
75
"""
76
77
def settings(self, document_path=None):
78
"""
79
Get merged settings for document or workspace.
80
81
Parameters:
82
- document_path: str, optional document path for document-specific settings
83
84
Returns:
85
dict: Merged configuration settings
86
"""
87
88
def find_parents(self, path, names):
89
"""
90
Find parent configuration files.
91
92
Parameters:
93
- path: str, starting path
94
- names: list, configuration file names to find
95
96
Returns:
97
list: Found configuration file paths
98
"""
99
100
def plugin_settings(self, plugin, document_path=None):
101
"""
102
Get plugin-specific settings.
103
104
Parameters:
105
- plugin: str, plugin name
106
- document_path: str, optional document path
107
108
Returns:
109
dict: Plugin configuration
110
"""
111
112
def update(self, settings):
113
"""
114
Update LSP settings.
115
116
Parameters:
117
- settings: dict, new settings to merge
118
"""
119
```
120
121
### Configuration Sources
122
123
Configuration resolution follows this hierarchy (later sources override earlier):
124
125
```python { .api }
126
DEFAULT_CONFIG_SOURCES = ["pycodestyle"] # Default configuration sources
127
128
# Configuration file names searched
129
CONFIG_FILE_NAMES = [
130
"pycodestyle.cfg",
131
"setup.cfg",
132
"tox.ini",
133
".flake8"
134
]
135
```
136
137
### PluginManager Class
138
139
Enhanced Pluggy plugin manager with error handling.
140
141
```python { .api }
142
class PluginManager(pluggy.PluginManager):
143
"""
144
Extended PluginManager with enhanced error handling.
145
Wraps hook execution to provide better error reporting.
146
"""
147
```
148
149
## Configuration Schema
150
151
### Server Configuration
152
153
Top-level server settings structure.
154
155
```python { .api }
156
# Server settings schema
157
SERVER_SETTINGS = {
158
"pylsp": {
159
"type": "object",
160
"properties": {
161
"configurationSources": {
162
"type": "array",
163
"items": {"type": "string"},
164
"default": ["pycodestyle"],
165
"description": "Configuration sources to use"
166
},
167
"plugins": {
168
"type": "object",
169
"description": "Plugin-specific settings"
170
},
171
"rope": {
172
"type": "object",
173
"properties": {
174
"extensionModules": {
175
"type": "array",
176
"items": {"type": "string"},
177
"description": "Rope extension modules"
178
},
179
"ropeFolder": {
180
"type": "string",
181
"description": "Rope project folder"
182
}
183
}
184
}
185
}
186
}
187
}
188
```
189
190
### Plugin Configuration
191
192
Standard plugin configuration patterns.
193
194
```python { .api }
195
# Standard plugin settings pattern
196
PLUGIN_SETTINGS_SCHEMA = {
197
"enabled": {
198
"type": "boolean",
199
"default": True,
200
"description": "Enable/disable plugin"
201
},
202
"exclude": {
203
"type": "array",
204
"items": {"type": "string"},
205
"description": "Files/patterns to exclude"
206
},
207
"filename": {
208
"type": "array",
209
"items": {"type": "string"},
210
"description": "Files/patterns to include"
211
}
212
}
213
214
# Linter-specific settings
215
LINTER_SETTINGS_SCHEMA = {
216
"ignore": {
217
"type": "array",
218
"items": {"type": "string"},
219
"description": "Error codes to ignore"
220
},
221
"select": {
222
"type": "array",
223
"items": {"type": "string"},
224
"description": "Error codes to select"
225
},
226
"maxLineLength": {
227
"type": "integer",
228
"description": "Maximum line length"
229
}
230
}
231
232
# Formatter-specific settings
233
FORMATTER_SETTINGS_SCHEMA = {
234
"args": {
235
"type": "array",
236
"items": {"type": "string"},
237
"description": "Additional formatter arguments"
238
}
239
}
240
```
241
242
## Built-in Plugin Settings
243
244
### Jedi Plugins
245
246
Settings for Jedi-based language features.
247
248
```python { .api }
249
JEDI_SETTINGS = {
250
"jedi_completion": {
251
"enabled": True,
252
"include_params": True,
253
"include_class_objects": True,
254
"fuzzy": False,
255
"eager": False,
256
"resolve_at_most": 25,
257
"cache_for": ["pandas", "numpy", "tensorflow", "matplotlib"]
258
},
259
"jedi_definition": {
260
"enabled": True,
261
"follow_imports": True,
262
"follow_builtin_imports": True
263
},
264
"jedi_hover": {
265
"enabled": True
266
},
267
"jedi_references": {
268
"enabled": True
269
},
270
"jedi_signature_help": {
271
"enabled": True
272
},
273
"jedi_symbols": {
274
"enabled": True,
275
"all_scopes": True,
276
"include_import_symbols": True
277
}
278
}
279
```
280
281
### Linter Settings
282
283
Configuration for built-in linters.
284
285
```python { .api }
286
LINTER_SETTINGS = {
287
"pyflakes": {
288
"enabled": True
289
},
290
"pycodestyle": {
291
"enabled": True,
292
"ignore": [],
293
"select": [],
294
"filename": [],
295
"exclude": [],
296
"hangClosing": False,
297
"maxLineLength": 79
298
},
299
"mccabe": {
300
"enabled": True,
301
"threshold": 15
302
},
303
"pydocstyle": {
304
"enabled": False,
305
"ignore": [],
306
"select": [],
307
"convention": None,
308
"addIgnore": [],
309
"addSelect": [],
310
"match": "(?!test_).*\\.py",
311
"matchDir": "[^\\.].*"
312
},
313
"flake8": {
314
"enabled": False,
315
"ignore": [],
316
"select": [],
317
"filename": [],
318
"exclude": [],
319
"maxLineLength": 79,
320
"hangClosing": False,
321
"args": []
322
},
323
"pylint": {
324
"enabled": False,
325
"args": [],
326
"executable": "pylint"
327
}
328
}
329
```
330
331
### Formatter Settings
332
333
Configuration for code formatters.
334
335
```python { .api }
336
FORMATTER_SETTINGS = {
337
"autopep8": {
338
"enabled": True,
339
"args": []
340
},
341
"yapf": {
342
"enabled": True,
343
"args": []
344
},
345
"black": {
346
"enabled": True,
347
"line_length": 88,
348
"cache_config": True
349
}
350
}
351
```
352
353
### Rope Settings
354
355
Configuration for Rope integration.
356
357
```python { .api }
358
ROPE_SETTINGS = {
359
"rope_completion": {
360
"enabled": True,
361
"eager": False
362
},
363
"rope_autoimport": {
364
"enabled": True,
365
"completions": {
366
"enabled": True
367
},
368
"code_actions": {
369
"enabled": True
370
},
371
"memory": False
372
}
373
}
374
```
375
376
## Usage Examples
377
378
### Basic Configuration
379
380
```python
381
from pylsp.config.config import Config
382
383
# Initialize configuration
384
config = Config(
385
root_uri="file:///project",
386
init_opts={"pylsp": {"plugins": {"pyflakes": {"enabled": True}}}},
387
process_id=1234,
388
capabilities={"textDocument": {"completion": {"completionItem": {"snippetSupport": True}}}}
389
)
390
391
# Get workspace settings
392
settings = config.settings()
393
print(settings["pylsp"]["plugins"]["pyflakes"]["enabled"]) # True
394
395
# Get document-specific settings
396
doc_settings = config.settings("/project/src/main.py")
397
398
# Get plugin settings
399
pyflakes_settings = config.plugin_settings("pyflakes", "/project/src/main.py")
400
```
401
402
### Plugin Configuration
403
404
```python
405
# Configure plugin settings
406
config.update({
407
"pylsp": {
408
"plugins": {
409
"pycodestyle": {
410
"enabled": True,
411
"ignore": ["E203", "W503"],
412
"maxLineLength": 88
413
},
414
"flake8": {
415
"enabled": False
416
},
417
"jedi_completion": {
418
"enabled": True,
419
"fuzzy": True,
420
"eager": True
421
}
422
}
423
}
424
})
425
426
# Access updated settings
427
jedi_settings = config.plugin_settings("jedi_completion")
428
print(jedi_settings["fuzzy"]) # True
429
```
430
431
### Configuration File Discovery
432
433
```python
434
# Find configuration files
435
config_files = config.find_parents("/project/src/main.py", [
436
"setup.cfg",
437
"pyproject.toml",
438
".flake8"
439
])
440
441
print(config_files) # ['/project/setup.cfg', '/project/.flake8']
442
```
443
444
### Dynamic Configuration Updates
445
446
```python
447
# Update configuration at runtime
448
config.update({
449
"pylsp": {
450
"configurationSources": ["flake8"],
451
"plugins": {
452
"pycodestyle": {"enabled": False},
453
"flake8": {"enabled": True}
454
}
455
}
456
})
457
458
# Configuration changes take effect immediately
459
settings = config.settings()
460
print(settings["pylsp"]["plugins"]["flake8"]["enabled"]) # True
461
```
462
463
### Custom Plugin Settings
464
465
```python
466
# Define custom plugin with settings
467
@hookimpl
468
def pylsp_settings(config):
469
return {
470
"plugins": {
471
"my_custom_plugin": {
472
"type": "object",
473
"properties": {
474
"enabled": {"type": "boolean", "default": True},
475
"severity": {
476
"type": "string",
477
"enum": ["error", "warning", "info"],
478
"default": "warning"
479
},
480
"patterns": {
481
"type": "array",
482
"items": {"type": "string"},
483
"default": ["*.py"]
484
}
485
}
486
}
487
}
488
}
489
490
# Use custom plugin settings
491
@hookimpl
492
def pylsp_lint(config, workspace, document, is_saved):
493
settings = config.plugin_settings("my_custom_plugin", document.path)
494
495
if not settings.get("enabled", True):
496
return []
497
498
severity_map = {"error": 1, "warning": 2, "info": 3}
499
severity = severity_map.get(settings.get("severity", "warning"), 2)
500
501
# Use settings in plugin logic
502
patterns = settings.get("patterns", ["*.py"])
503
# ... plugin implementation
504
```
505
506
### Multi-level Configuration
507
508
```python
509
# Configuration hierarchy example:
510
# 1. Default plugin settings
511
# 2. User home directory config
512
# 3. Workspace settings (init_opts)
513
# 4. Project config files (setup.cfg, etc.)
514
# 5. Document-specific overrides
515
516
# Each level can override previous levels
517
config.update({
518
"pylsp": {
519
"plugins": {
520
"pycodestyle": {
521
"enabled": True, # Workspace level
522
"maxLineLength": 100 # Override default 79
523
}
524
}
525
}
526
})
527
528
# setup.cfg in project root might further override:
529
# [pycodestyle]
530
# max-line-length = 120
531
# ignore = E203,W503
532
533
# Final resolved settings will have maxLineLength=120
534
final_settings = config.settings("/project/src/module.py")
535
```