@@ -95,19 +95,20 @@ def configure_setting(self, name, prompt, default=NO_DEFAULT):
95
95
passed, the current value of the setting will be ignored, even if it is
96
96
not the attribute's default.
97
97
"""
98
- clazz = getattr (self .__class__ , name )
99
- if default is NO_DEFAULT and not clazz .is_secret :
98
+ attribute = getattr (self .__class__ , name )
99
+ if default is NO_DEFAULT and not attribute .is_secret :
100
100
try :
101
101
default = getattr (self , name )
102
102
except AttributeError :
103
103
pass
104
104
except ValueError :
105
105
print ('The configured value for this option was invalid.' )
106
- if clazz .default is not NO_DEFAULT :
107
- default = clazz .default
106
+ if attribute .default is not NO_DEFAULT :
107
+ default = attribute .default
108
108
while True :
109
109
try :
110
- value = clazz .configure (prompt , default , self ._parent , self ._section_name )
110
+ value = attribute .configure (
111
+ prompt , default , self ._parent , self ._section_name )
111
112
except ValueError as exc :
112
113
print (exc )
113
114
else :
@@ -194,7 +195,9 @@ def configure(self, prompt, default, parent, section_name):
194
195
raise ValueError ("You must provide a value for this option." )
195
196
196
197
value = value or default
197
- return self .parse (value )
198
+ section = getattr (parent , section_name )
199
+
200
+ return self ._parse (value , parent , section )
198
201
199
202
def serialize (self , value , * args , ** kwargs ):
200
203
"""Take some object, and return the string to be saved to the file.
@@ -212,35 +215,48 @@ def parse(self, value, *args, **kwargs):
212
215
def __get__ (self , instance , owner = None ):
213
216
if instance is None :
214
217
# If instance is None, we're getting from a section class, not an
215
- # instance of a session class. It makes the wizard code simpler
218
+ # instance of a section class. It makes the wizard code simpler
216
219
# (and is really just more intuitive) to return the descriptor
217
220
# instance here.
218
221
return self
219
222
223
+ value = None
220
224
env_name = 'SOPEL_%s_%s' % (instance ._section_name .upper (), self .name .upper ())
221
225
if env_name in os .environ :
222
226
value = os .environ .get (env_name )
223
227
elif instance ._parser .has_option (instance ._section_name , self .name ):
224
228
value = instance ._parser .get (instance ._section_name , self .name )
225
- else :
226
- if self .default is not NO_DEFAULT :
227
- return self .default
228
- raise AttributeError (
229
- "Missing required value for {}.{}" .format (
230
- instance ._section_name , self .name
231
- )
229
+
230
+ settings = instance ._parent
231
+ section = getattr (settings , instance ._section_name )
232
+ return self ._parse (value , settings , section )
233
+
234
+ def _parse (self , value , settings , section ):
235
+ if value is not None :
236
+ return self .parse (value )
237
+ if self .default is not NO_DEFAULT :
238
+ return self .default
239
+ raise AttributeError (
240
+ "Missing required value for {}.{}" .format (
241
+ section ._section_name , self .name
232
242
)
233
- return self . parse ( value )
243
+ )
234
244
235
245
def __set__ (self , instance , value ):
236
246
if value is None :
237
247
if self .default == NO_DEFAULT :
238
248
raise ValueError ('Cannot unset an option with a required value.' )
239
249
instance ._parser .remove_option (instance ._section_name , self .name )
240
250
return
241
- value = self .serialize (value )
251
+
252
+ settings = instance ._parent
253
+ section = getattr (settings , instance ._section_name )
254
+ value = self ._serialize (value , settings , section )
242
255
instance ._parser .set (instance ._section_name , self .name , value )
243
256
257
+ def _serialize (self , value , settings , section ):
258
+ return self .serialize (value )
259
+
244
260
def __delete__ (self , instance ):
245
261
instance ._parser .remove_option (instance ._section_name , self .name )
246
262
@@ -503,7 +519,10 @@ def configure(self, prompt, default, parent, section_name):
503
519
else :
504
520
values .append (value )
505
521
value = get_input (each_prompt + ' ' )
506
- return self .parse (self .serialize (values ))
522
+
523
+ section = getattr (parent , section_name )
524
+ values = self ._serialize (values , parent , section )
525
+ return self ._parse (values , parent , section )
507
526
508
527
509
528
class ChoiceAttribute (BaseValidated ):
@@ -569,62 +588,55 @@ def __init__(self, name, relative=True, directory=False, default=None):
569
588
self .relative = relative
570
589
self .directory = directory
571
590
572
- def __get__ (self , instance , owner = None ):
573
- if instance is None :
574
- return self
575
- env_name = 'SOPEL_%s_%s' % (instance ._section_name .upper (), self .name .upper ())
576
- if env_name in os .environ :
577
- value = os .environ .get (env_name )
578
- elif instance ._parser .has_option (instance ._section_name , self .name ):
579
- value = instance ._parser .get (instance ._section_name , self .name )
580
- else :
581
- if self .default is not NO_DEFAULT :
582
- value = self .default
583
- else :
591
+ def _parse (self , value , settings , section ):
592
+ if value is None :
593
+ if self .default == NO_DEFAULT :
584
594
raise AttributeError (
585
595
"Missing required value for {}.{}" .format (
586
- instance ._section_name , self .name
596
+ section ._section_name , self .name
587
597
)
588
598
)
589
- main_config = instance ._parent
590
- this_section = getattr (main_config , instance ._section_name )
591
- return self .parse (value , main_config , this_section )
599
+ value = self .default
592
600
593
- def __set__ (self , instance , value ):
594
- main_config = instance ._parent
595
- this_section = getattr (main_config , instance ._section_name )
596
- value = self .serialize (value , main_config , this_section )
597
- instance ._parser .set (instance ._section_name , self .name , value )
601
+ if not value :
602
+ return self .parse (value )
598
603
599
- def configure (self , prompt , default , parent , section_name ):
600
- if default is not NO_DEFAULT and default is not None :
601
- prompt = '{} [{}]' .format (prompt , default )
602
- value = get_input (prompt + ' ' )
603
- if not value and default is NO_DEFAULT :
604
- raise ValueError ("You must provide a value for this option." )
605
- value = value or default
606
- return self .parse (value , parent , section_name )
604
+ result = os .path .expanduser (value )
605
+ if not os .path .isabs (result ):
606
+ if not self .relative :
607
+ raise ValueError ("Value must be an absolute path." )
608
+ result = os .path .join (settings .homedir , result )
609
+
610
+ return self .parse (result )
607
611
608
- def parse (self , value , main_config , this_section ):
609
- """Used to validate ``value`` when loading the config .
612
+ def _serialize (self , value , settings , section ):
613
+ """Used to validate ``value`` when it is changed at runtime .
610
614
611
- :param main_config : the config object which contains this attribute
612
- :type main_config : :class:`~sopel.config.Config`
613
- :param this_section : the config section which contains this attribute
614
- :type this_section : :class:`~StaticSection`
615
+ :param settings : the config object which contains this attribute
616
+ :type settings : :class:`~sopel.config.Config`
617
+ :param section : the config section which contains this attribute
618
+ :type section : :class:`~StaticSection`
615
619
:return: the ``value``, if it is valid
616
620
:rtype: str
617
621
:raise ValueError: if the ``value`` is not valid
618
622
"""
619
- if value is None :
620
- return
623
+ self . _parse ( value , settings , section )
624
+ return self . serialize ( value )
621
625
622
- value = os .path .expanduser (value )
626
+ def parse (self , value ):
627
+ """Parse ``value`` as a path on the filesystem to check.
623
628
624
- if not os .path .isabs (value ):
625
- if not self .relative :
626
- raise ValueError ("Value must be an absolute path." )
627
- value = os .path .join (main_config .homedir , value )
629
+ :param str value: the path to check
630
+ :rtype: str
631
+ :raise ValueError: if the directory or file doesn't exist and cannot
632
+ be created
633
+
634
+ If there is no ``value``, then this returns ``None``. Otherwise, it'll
635
+ check if the directory or file exists. If it doesn't, it'll try to
636
+ create it.
637
+ """
638
+ if not value :
639
+ return None
628
640
629
641
if self .directory and not os .path .isdir (value ):
630
642
try :
@@ -639,16 +651,15 @@ def parse(self, value, main_config, this_section):
639
651
raise ValueError ("Value must be an existing or creatable file." )
640
652
return value
641
653
642
- def serialize (self , value , main_config , this_section ):
643
- """Used to validate ``value`` when it is changed at runtime .
654
+ def serialize (self , value ):
655
+ """Directly return the ``value`` without modification .
644
656
645
- :param main_config: the config object which contains this attribute
646
- :type main_config: :class:`~sopel.config.Config`
647
- :param this_section: the config section which contains this attribute
648
- :type this_section: :class:`~StaticSection`
649
- :return: the ``value``, if it is valid
657
+ :param str value: the value needing to be saved
658
+ :return: the unaltered ``value``, if it is valid
650
659
:rtype: str
651
- :raise ValueError: if the ``value`` is not valid
660
+
661
+ Managing the filename is done by other methods (:meth:`parse`), and
662
+ this method is a no-op: this way it ensures that relative paths won't
663
+ be replaced by absolute ones.
652
664
"""
653
- self .parse (value , main_config , this_section )
654
665
return value # So that it's still relative
0 commit comments