Show More
@@ -0,0 +1,179 b'' | |||||
|
1 | """Load and store configuration objects. | |||
|
2 | ||||
|
3 | Test this module using | |||
|
4 | ||||
|
5 | nosetests -v --with-doctest --doctest-tests IPython.config | |||
|
6 | ||||
|
7 | """ | |||
|
8 | ||||
|
9 | from __future__ import with_statement | |||
|
10 | from contextlib import contextmanager | |||
|
11 | ||||
|
12 | import inspect | |||
|
13 | import types | |||
|
14 | from IPython.config import traitlets | |||
|
15 | from traitlets import Traitlet | |||
|
16 | from IPython.external.configobj import ConfigObj | |||
|
17 | ||||
|
18 | def debug(s): | |||
|
19 | import sys | |||
|
20 | sys.stderr.write(str(s) + '\n') | |||
|
21 | ||||
|
22 | @contextmanager | |||
|
23 | def raw(config): | |||
|
24 | """Context manager for accessing traitlets directly. | |||
|
25 | ||||
|
26 | """ | |||
|
27 | config.__getattribute__('',raw_access=True) | |||
|
28 | yield config | |||
|
29 | config.__getattribute__('',raw_access=False) | |||
|
30 | ||||
|
31 | class Config(object): | |||
|
32 | """ | |||
|
33 | Implementation Notes | |||
|
34 | ==================== | |||
|
35 | All instances of the same Config class share properties. Therefore, | |||
|
36 | ||||
|
37 | >>> class Sample(Config): | |||
|
38 | ... my_float = traitlets.Float(3) | |||
|
39 | ||||
|
40 | >>> s0 = Sample() | |||
|
41 | >>> s1 = Sample() | |||
|
42 | >>> s0.my_float = 5 | |||
|
43 | >>> s0.my_float == s1.my_float | |||
|
44 | True | |||
|
45 | ||||
|
46 | """ | |||
|
47 | def __init__(self): | |||
|
48 | # Instantiate subconfigs | |||
|
49 | with raw(self): | |||
|
50 | subconfigs = [(n,v) for n,v in | |||
|
51 | inspect.getmembers(self, inspect.isclass) | |||
|
52 | if not n.startswith('__')] | |||
|
53 | ||||
|
54 | for n,v in subconfigs: | |||
|
55 | setattr(self, n, v()) | |||
|
56 | ||||
|
57 | def __getattribute__(self,attr,raw_access=None, | |||
|
58 | _ns={'raw_access':False}): | |||
|
59 | if raw_access is not None: | |||
|
60 | _ns['raw_access'] = raw_access | |||
|
61 | return | |||
|
62 | ||||
|
63 | obj = object.__getattribute__(self,attr) | |||
|
64 | if isinstance(obj,Traitlet) and not _ns['raw_access']: | |||
|
65 | return obj.__call__() | |||
|
66 | else: | |||
|
67 | return obj | |||
|
68 | ||||
|
69 | def __setattr__(self,attr,value): | |||
|
70 | obj = object.__getattribute__(self,attr) | |||
|
71 | if isinstance(obj,Traitlet): | |||
|
72 | obj(value) | |||
|
73 | else: | |||
|
74 | self.__dict__[attr] = value | |||
|
75 | ||||
|
76 | def __str__(self,level=1,only_modified=True): | |||
|
77 | ci = ConfigInspector(self) | |||
|
78 | out = '' | |||
|
79 | spacer = ' '*(level-1) | |||
|
80 | ||||
|
81 | # Add traitlet representations | |||
|
82 | for p,v in ci.properties: | |||
|
83 | if (v.modified and only_modified) or not only_modified: | |||
|
84 | out += spacer + '%s = %s\n' % (p,v) | |||
|
85 | ||||
|
86 | # Add subconfig representations | |||
|
87 | for (n,v) in ci.subconfigs: | |||
|
88 | sub_str = v.__str__(level=level+1,only_modified=only_modified) | |||
|
89 | if sub_str: | |||
|
90 | out += '\n' + spacer + '[' * level + ('%s' % n) \ | |||
|
91 | + ']'*level + '\n' | |||
|
92 | out += sub_str | |||
|
93 | ||||
|
94 | return out | |||
|
95 | ||||
|
96 | def __iadd__(self,source): | |||
|
97 | """Load configuration from filename, and update self. | |||
|
98 | ||||
|
99 | """ | |||
|
100 | if not isinstance(source,dict): | |||
|
101 | source = ConfigObj(source, unrepr=True) | |||
|
102 | update_from_dict(self,source) | |||
|
103 | return self | |||
|
104 | ||||
|
105 | ||||
|
106 | class ConfigInspector(object): | |||
|
107 | """Allow the inspection of Config objects. | |||
|
108 | ||||
|
109 | """ | |||
|
110 | def __init__(self,config): | |||
|
111 | self._config = config | |||
|
112 | ||||
|
113 | @property | |||
|
114 | def properties(self): | |||
|
115 | "Return all traitlet names." | |||
|
116 | with raw(self._config): | |||
|
117 | return inspect.getmembers(self._config, | |||
|
118 | lambda obj: isinstance(obj, Traitlet)) | |||
|
119 | ||||
|
120 | @property | |||
|
121 | def subconfigs(self): | |||
|
122 | "Return all subconfig names and values." | |||
|
123 | with raw(self._config): | |||
|
124 | return [(n,v) for n,v in | |||
|
125 | inspect.getmembers(self._config, | |||
|
126 | lambda obj: isinstance(obj,Config)) | |||
|
127 | if not n.startswith('__')] | |||
|
128 | ||||
|
129 | def reset(self): | |||
|
130 | for (p,v) in self.properties: | |||
|
131 | v.reset() | |||
|
132 | ||||
|
133 | for (s,v) in self.subconfigs: | |||
|
134 | ConfigInspector(v).reset() | |||
|
135 | ||||
|
136 | def update_from_dict(config,d): | |||
|
137 | """Propagate the values of the dictionary to the given configuration. | |||
|
138 | ||||
|
139 | Useful to load configobj instances. | |||
|
140 | ||||
|
141 | """ | |||
|
142 | for k,v in d.items(): | |||
|
143 | try: | |||
|
144 | prop_or_subconfig = getattr(config, k) | |||
|
145 | except AttributeError: | |||
|
146 | print "Invalid section/property in config file: %s" % k | |||
|
147 | else: | |||
|
148 | if isinstance(v,dict): | |||
|
149 | update_from_dict(prop_or_subconfig,v) | |||
|
150 | else: | |||
|
151 | setattr(config, k, v) | |||
|
152 | ||||
|
153 | def dict_from_config(config,only_modified=True): | |||
|
154 | """Create a dictionary from a Config object.""" | |||
|
155 | ci = ConfigInspector(config) | |||
|
156 | out = {} | |||
|
157 | ||||
|
158 | for p,v in ci.properties: | |||
|
159 | if (v.modified and only_modified) or not only_modified: | |||
|
160 | out[p] = v | |||
|
161 | ||||
|
162 | for s,v in ci.subconfigs: | |||
|
163 | d = dict_from_config(v,only_modified) | |||
|
164 | if d != {}: | |||
|
165 | out[s] = d | |||
|
166 | ||||
|
167 | return out | |||
|
168 | ||||
|
169 | def write(config, target): | |||
|
170 | """Write a configuration to file. | |||
|
171 | ||||
|
172 | """ | |||
|
173 | if isinstance(target, str): | |||
|
174 | target = open(target, 'w+') | |||
|
175 | target.flush() | |||
|
176 | target.seek(0) | |||
|
177 | ||||
|
178 | confobj = ConfigObj(dict_from_config(config), unrepr=True) | |||
|
179 | confobj.write(target) |
@@ -0,0 +1,19 b'' | |||||
|
1 | from IPython.config.api import * | |||
|
2 | ||||
|
3 | class SubSubSample(Config): | |||
|
4 | my_int = Int(3) | |||
|
5 | ||||
|
6 | ||||
|
7 | class Sample(Config): | |||
|
8 | my_float = Float(3) | |||
|
9 | my_choice = Enum('a','b','c') | |||
|
10 | ||||
|
11 | class MiddleSection(Config): | |||
|
12 | left_alone = Enum('1','2','c') | |||
|
13 | unknown_mod = Module('asd') | |||
|
14 | ||||
|
15 | class SubSample(Config): | |||
|
16 | subsample_uri = URI('http://localhost:8080') | |||
|
17 | ||||
|
18 | # Example of how to include external config | |||
|
19 | SubSubSample = SubSubSample() |
@@ -0,0 +1,135 b'' | |||||
|
1 | """ | |||
|
2 | # Test utilities | |||
|
3 | ||||
|
4 | >>> import os | |||
|
5 | ||||
|
6 | >>> def dict_as_sorted_list(d): | |||
|
7 | ... for k in d: | |||
|
8 | ... if isinstance(d[k],dict): | |||
|
9 | ... d[k] = dict_as_sorted_list(d[k]) | |||
|
10 | ... return sorted(d.items()) | |||
|
11 | ||||
|
12 | >>> def pprint(d,level=0): | |||
|
13 | ... if isinstance(d,dict): | |||
|
14 | ... d = dict_as_sorted_list(d) | |||
|
15 | ... for item,value in d: | |||
|
16 | ... if isinstance(value,list): | |||
|
17 | ... print "%s%s" % (' '*level, item) | |||
|
18 | ... pprint(value,level+2) | |||
|
19 | ... else: | |||
|
20 | ... print "%s%s: %s" % (' '*level, item, value) | |||
|
21 | ||||
|
22 | ||||
|
23 | # Tests | |||
|
24 | ||||
|
25 | >>> from IPython.config.api import * | |||
|
26 | >>> from sample_config import * | |||
|
27 | ||||
|
28 | >>> s = Sample() | |||
|
29 | >>> print s.my_float | |||
|
30 | 3.0 | |||
|
31 | >>> s.my_float = 4 | |||
|
32 | >>> print s.my_float | |||
|
33 | 4.0 | |||
|
34 | >>> print type(s.my_float) | |||
|
35 | <type 'float'> | |||
|
36 | >>> s.SubSample.SubSubSample.my_int = 5.0 | |||
|
37 | >>> print s.SubSample.SubSubSample.my_int | |||
|
38 | 5 | |||
|
39 | ||||
|
40 | >>> i = ConfigInspector(s) | |||
|
41 | >>> print i.properties | |||
|
42 | [('my_choice', 'a'), ('my_float', 4.0)] | |||
|
43 | >>> print tuple(s for s,v in i.subconfigs) | |||
|
44 | ('MiddleSection', 'SubSample') | |||
|
45 | ||||
|
46 | >>> print s | |||
|
47 | my_float = 4.0 | |||
|
48 | <BLANKLINE> | |||
|
49 | [SubSample] | |||
|
50 | <BLANKLINE> | |||
|
51 | [[SubSubSample]] | |||
|
52 | my_int = 5 | |||
|
53 | <BLANKLINE> | |||
|
54 | ||||
|
55 | >>> import tempfile | |||
|
56 | >>> fn = tempfile.mktemp() | |||
|
57 | >>> f = open(fn,'w') | |||
|
58 | >>> f.write(str(s)) | |||
|
59 | >>> f.close() | |||
|
60 | ||||
|
61 | >>> s += fn | |||
|
62 | ||||
|
63 | >>> from IPython.external.configobj import ConfigObj | |||
|
64 | >>> c = ConfigObj(fn) | |||
|
65 | >>> c['SubSample']['subsample_uri'] = 'http://ipython.scipy.org' | |||
|
66 | ||||
|
67 | >>> s += c | |||
|
68 | >>> print s | |||
|
69 | my_float = 4.0 | |||
|
70 | <BLANKLINE> | |||
|
71 | [SubSample] | |||
|
72 | subsample_uri = 'http://ipython.scipy.org' | |||
|
73 | <BLANKLINE> | |||
|
74 | [[SubSubSample]] | |||
|
75 | my_int = 5 | |||
|
76 | <BLANKLINE> | |||
|
77 | ||||
|
78 | >>> pprint(dict_from_config(s,only_modified=False)) | |||
|
79 | MiddleSection | |||
|
80 | left_alone: '1' | |||
|
81 | unknown_mod: 'asd' | |||
|
82 | SubSample | |||
|
83 | SubSubSample | |||
|
84 | my_int: 5 | |||
|
85 | subsample_uri: 'http://ipython.scipy.org' | |||
|
86 | my_choice: 'a' | |||
|
87 | my_float: 4.0 | |||
|
88 | ||||
|
89 | >>> pprint(dict_from_config(s)) | |||
|
90 | SubSample | |||
|
91 | SubSubSample | |||
|
92 | my_int: 5 | |||
|
93 | subsample_uri: 'http://ipython.scipy.org' | |||
|
94 | my_float: 4.0 | |||
|
95 | ||||
|
96 | Test roundtripping: | |||
|
97 | ||||
|
98 | >>> fn = tempfile.mktemp() | |||
|
99 | >>> f = open(fn, 'w') | |||
|
100 | >>> f.write(''' | |||
|
101 | ... [MiddleSection] | |||
|
102 | ... # some comment here | |||
|
103 | ... left_alone = 'c' | |||
|
104 | ... ''') | |||
|
105 | >>> f.close() | |||
|
106 | ||||
|
107 | >>> s += fn | |||
|
108 | ||||
|
109 | >>> pprint(dict_from_config(s)) | |||
|
110 | MiddleSection | |||
|
111 | left_alone: 'c' | |||
|
112 | SubSample | |||
|
113 | SubSubSample | |||
|
114 | my_int: 5 | |||
|
115 | subsample_uri: 'http://ipython.scipy.org' | |||
|
116 | my_float: 4.0 | |||
|
117 | ||||
|
118 | >>> write(s, fn) | |||
|
119 | >>> f = file(fn,'r') | |||
|
120 | >>> ConfigInspector(s).reset() | |||
|
121 | >>> pprint(dict_from_config(s)) | |||
|
122 | ||||
|
123 | >>> s += fn | |||
|
124 | >>> os.unlink(fn) | |||
|
125 | >>> pprint(dict_from_config(s)) | |||
|
126 | MiddleSection | |||
|
127 | left_alone: 'c' | |||
|
128 | SubSample | |||
|
129 | SubSubSample | |||
|
130 | my_int: 5 | |||
|
131 | subsample_uri: 'http://ipython.scipy.org' | |||
|
132 | my_float: 4.0 | |||
|
133 | ||||
|
134 | ||||
|
135 | """ |
@@ -0,0 +1,322 b'' | |||||
|
1 | """Traitlets -- a light-weight meta-class free stand-in for Traits. | |||
|
2 | ||||
|
3 | Traitlet behaviour | |||
|
4 | ================== | |||
|
5 | - Automatic casting, equivalent to traits.C* classes, e.g. CFloat, CBool etc. | |||
|
6 | ||||
|
7 | - By default, validation is done by attempting to cast a given value | |||
|
8 | to the underlying type, e.g. bool for Bool, float for Float etc. | |||
|
9 | ||||
|
10 | - To set or get a Traitlet value, use the ()-operator. E.g. | |||
|
11 | ||||
|
12 | >>> b = Bool(False) | |||
|
13 | >>> b(True) | |||
|
14 | >>> print b # returns a string representation of the Traitlet | |||
|
15 | True | |||
|
16 | >>> print b() # returns the underlying bool object | |||
|
17 | True | |||
|
18 | ||||
|
19 | This makes it possible to change values "in-place", unlike an assigment | |||
|
20 | of the form | |||
|
21 | ||||
|
22 | >>> c = Bool(False) | |||
|
23 | >>> c = True | |||
|
24 | ||||
|
25 | which results in | |||
|
26 | ||||
|
27 | >>> print type(b), type(c) | |||
|
28 | <class 'IPython.config.traitlets.Bool'> <type 'bool'> | |||
|
29 | ||||
|
30 | - Each Traitlet keeps track of its modification state, e.g. | |||
|
31 | ||||
|
32 | >>> c = Bool(False) | |||
|
33 | >>> print c.modified | |||
|
34 | False | |||
|
35 | >>> c(False) | |||
|
36 | >>> print c.modified | |||
|
37 | False | |||
|
38 | >>> c(True) | |||
|
39 | >>> print c.modified | |||
|
40 | True | |||
|
41 | ||||
|
42 | How to customize Traitlets | |||
|
43 | ========================== | |||
|
44 | ||||
|
45 | The easiest way to create a new Traitlet is by wrapping an underlying | |||
|
46 | Python type. This is done by setting the "_type" class attribute. For | |||
|
47 | example, creating an int-like Traitlet is done as follows: | |||
|
48 | ||||
|
49 | >>> class MyInt(Traitlet): | |||
|
50 | ... _type = int | |||
|
51 | ||||
|
52 | >>> i = MyInt(3) | |||
|
53 | >>> i(4) | |||
|
54 | >>> print i | |||
|
55 | 4 | |||
|
56 | ||||
|
57 | >>> try: | |||
|
58 | ... i('a') | |||
|
59 | ... except ValidationError: | |||
|
60 | ... pass # this is expected | |||
|
61 | ... else: | |||
|
62 | ... "This should not be reached." | |||
|
63 | ||||
|
64 | Furthermore, the following methods are provided for finer grained | |||
|
65 | control of validation and assignment: | |||
|
66 | ||||
|
67 | - validate(self,value) | |||
|
68 | Ensure that "value" is valid. If not, raise an exception of any kind | |||
|
69 | with a suitable error message, which is reported to the user. | |||
|
70 | ||||
|
71 | - prepare_value(self) | |||
|
72 | When using the ()-operator to query the underlying Traitlet value, | |||
|
73 | that value is first passed through prepare_value. For example: | |||
|
74 | ||||
|
75 | >>> class Eval(Traitlet): | |||
|
76 | ... _type = str | |||
|
77 | ... | |||
|
78 | ... def prepare_value(self): | |||
|
79 | ... return eval(self._value) | |||
|
80 | ||||
|
81 | >>> x = Eval('1+1') | |||
|
82 | >>> print x | |||
|
83 | '1+1' | |||
|
84 | >>> print x() | |||
|
85 | 2 | |||
|
86 | ||||
|
87 | - __repr__(self) | |||
|
88 | By default, repr(self._value) is returned. This can be customised | |||
|
89 | to, for example, first call prepare_value and return the repr of | |||
|
90 | the resulting object. | |||
|
91 | ||||
|
92 | """ | |||
|
93 | ||||
|
94 | import re | |||
|
95 | import types | |||
|
96 | ||||
|
97 | class ValidationError(Exception): | |||
|
98 | pass | |||
|
99 | ||||
|
100 | class Traitlet(object): | |||
|
101 | """Traitlet which knows its modification state. | |||
|
102 | ||||
|
103 | """ | |||
|
104 | def __init__(self, value): | |||
|
105 | "Validate and store the default value. State is 'unmodified'." | |||
|
106 | self._type = getattr(self,'_type',None) | |||
|
107 | value = self._parse_validation(value) | |||
|
108 | self._default_value = value | |||
|
109 | self.reset() | |||
|
110 | ||||
|
111 | def reset(self): | |||
|
112 | self._value = self._default_value | |||
|
113 | self._changed = False | |||
|
114 | ||||
|
115 | def validate(self, value): | |||
|
116 | "Validate the given value." | |||
|
117 | if self._type is not None: | |||
|
118 | self._type(value) | |||
|
119 | ||||
|
120 | def _parse_validation(self, value): | |||
|
121 | """Run validation and return a descriptive error if needed. | |||
|
122 | ||||
|
123 | """ | |||
|
124 | try: | |||
|
125 | self.validate(value) | |||
|
126 | except Exception, e: | |||
|
127 | err_message = 'Cannot convert "%s" to %s' % \ | |||
|
128 | (value, self.__class__.__name__.lower()) | |||
|
129 | if e.message: | |||
|
130 | err_message += ': %s' % e.message | |||
|
131 | raise ValidationError(err_message) | |||
|
132 | else: | |||
|
133 | # Cast to appropriate type before storing | |||
|
134 | if self._type is not None: | |||
|
135 | value = self._type(value) | |||
|
136 | return value | |||
|
137 | ||||
|
138 | def prepare_value(self): | |||
|
139 | """Run on value before it is ever returned to the user. | |||
|
140 | ||||
|
141 | """ | |||
|
142 | return self._value | |||
|
143 | ||||
|
144 | def __call__(self,value=None): | |||
|
145 | """Query or set value depending on whether `value` is specified. | |||
|
146 | ||||
|
147 | """ | |||
|
148 | if value is None: | |||
|
149 | return self.prepare_value() | |||
|
150 | ||||
|
151 | self._value = self._parse_validation(value) | |||
|
152 | self._changed = (self._value != self._default_value) | |||
|
153 | ||||
|
154 | @property | |||
|
155 | def modified(self): | |||
|
156 | "Whether value has changed from original definition." | |||
|
157 | return self._changed | |||
|
158 | ||||
|
159 | def __repr__(self): | |||
|
160 | """This class is represented by the underlying repr. Used when | |||
|
161 | dumping value to file. | |||
|
162 | ||||
|
163 | """ | |||
|
164 | return repr(self._value) | |||
|
165 | ||||
|
166 | class Float(Traitlet): | |||
|
167 | """ | |||
|
168 | >>> f = Float(0) | |||
|
169 | >>> print f.modified | |||
|
170 | False | |||
|
171 | ||||
|
172 | >>> f(3) | |||
|
173 | >>> print f() | |||
|
174 | 3.0 | |||
|
175 | >>> print f.modified | |||
|
176 | True | |||
|
177 | ||||
|
178 | >>> f(0) | |||
|
179 | >>> print f() | |||
|
180 | 0.0 | |||
|
181 | >>> print f.modified | |||
|
182 | False | |||
|
183 | ||||
|
184 | >>> try: | |||
|
185 | ... f('a') | |||
|
186 | ... except ValidationError: | |||
|
187 | ... pass | |||
|
188 | ||||
|
189 | """ | |||
|
190 | _type = float | |||
|
191 | ||||
|
192 | class Enum(Traitlet): | |||
|
193 | """ | |||
|
194 | >>> c = Enum('a','b','c') | |||
|
195 | >>> print c() | |||
|
196 | a | |||
|
197 | ||||
|
198 | >>> try: | |||
|
199 | ... c('unknown') | |||
|
200 | ... except ValidationError: | |||
|
201 | ... pass | |||
|
202 | ||||
|
203 | >>> print c.modified | |||
|
204 | False | |||
|
205 | ||||
|
206 | >>> c('b') | |||
|
207 | >>> print c() | |||
|
208 | b | |||
|
209 | ||||
|
210 | """ | |||
|
211 | def __init__(self, *options): | |||
|
212 | self._options = options | |||
|
213 | super(Enum,self).__init__(options[0]) | |||
|
214 | ||||
|
215 | def validate(self, value): | |||
|
216 | if not value in self._options: | |||
|
217 | raise ValueError('must be one of %s' % str(self._options)) | |||
|
218 | ||||
|
219 | class Module(Traitlet): | |||
|
220 | """ | |||
|
221 | >>> m = Module('some.unknown.module') | |||
|
222 | >>> print m | |||
|
223 | 'some.unknown.module' | |||
|
224 | ||||
|
225 | >>> m = Module('re') | |||
|
226 | >>> assert type(m()) is types.ModuleType | |||
|
227 | ||||
|
228 | """ | |||
|
229 | _type = str | |||
|
230 | ||||
|
231 | def prepare_value(self): | |||
|
232 | try: | |||
|
233 | module = eval(self._value) | |||
|
234 | except: | |||
|
235 | module = None | |||
|
236 | ||||
|
237 | if type(module) is not types.ModuleType: | |||
|
238 | raise ValueError("Invalid module name: %s" % self._value) | |||
|
239 | else: | |||
|
240 | return module | |||
|
241 | ||||
|
242 | ||||
|
243 | class URI(Traitlet): | |||
|
244 | """ | |||
|
245 | >>> u = URI('http://') | |||
|
246 | ||||
|
247 | >>> try: | |||
|
248 | ... u = URI('something.else') | |||
|
249 | ... except ValidationError: | |||
|
250 | ... pass | |||
|
251 | ||||
|
252 | >>> u = URI('http://ipython.scipy.org/') | |||
|
253 | >>> print u | |||
|
254 | 'http://ipython.scipy.org/' | |||
|
255 | ||||
|
256 | """ | |||
|
257 | _regexp = re.compile(r'^[a-zA-Z]+:\/\/') | |||
|
258 | _type = str | |||
|
259 | ||||
|
260 | def validate(self, uri): | |||
|
261 | if not self._regexp.match(uri): | |||
|
262 | raise ValueError() | |||
|
263 | ||||
|
264 | class Int(Traitlet): | |||
|
265 | """ | |||
|
266 | >>> i = Int(3.5) | |||
|
267 | >>> print i | |||
|
268 | 3 | |||
|
269 | >>> print i() | |||
|
270 | 3 | |||
|
271 | ||||
|
272 | >>> i = Int('4') | |||
|
273 | >>> print i | |||
|
274 | 4 | |||
|
275 | ||||
|
276 | >>> try: | |||
|
277 | ... i = Int('a') | |||
|
278 | ... except ValidationError: | |||
|
279 | ... pass | |||
|
280 | ... else: | |||
|
281 | ... raise "Should fail" | |||
|
282 | ||||
|
283 | """ | |||
|
284 | _type = int | |||
|
285 | ||||
|
286 | class Bool(Traitlet): | |||
|
287 | """ | |||
|
288 | >>> b = Bool(2) | |||
|
289 | >>> print b | |||
|
290 | True | |||
|
291 | >>> print b() | |||
|
292 | True | |||
|
293 | ||||
|
294 | >>> b = Bool('True') | |||
|
295 | >>> print b | |||
|
296 | True | |||
|
297 | >>> b(True) | |||
|
298 | >>> print b.modified | |||
|
299 | False | |||
|
300 | ||||
|
301 | >>> print Bool(0) | |||
|
302 | False | |||
|
303 | ||||
|
304 | """ | |||
|
305 | _type = bool | |||
|
306 | ||||
|
307 | class Unicode(Traitlet): | |||
|
308 | """ | |||
|
309 | >>> u = Unicode(123) | |||
|
310 | >>> print u | |||
|
311 | u'123' | |||
|
312 | ||||
|
313 | >>> u = Unicode('123') | |||
|
314 | >>> print u.modified | |||
|
315 | False | |||
|
316 | ||||
|
317 | >>> u('hello world') | |||
|
318 | >>> print u | |||
|
319 | u'hello world' | |||
|
320 | ||||
|
321 | """ | |||
|
322 | _type = unicode |
@@ -1,99 +1,104 b'' | |||||
1 | # encoding: utf-8 |
|
1 | # encoding: utf-8 | |
2 |
|
2 | |||
3 | """This is the official entry point to IPython's configuration system. """ |
|
3 | """This is the official entry point to IPython's configuration system. """ | |
4 |
|
4 | |||
5 | __docformat__ = "restructuredtext en" |
|
5 | __docformat__ = "restructuredtext en" | |
6 |
|
6 | |||
7 | #------------------------------------------------------------------------------- |
|
7 | #------------------------------------------------------------------------------- | |
8 | # Copyright (C) 2008 The IPython Development Team |
|
8 | # Copyright (C) 2008 The IPython Development Team | |
9 | # |
|
9 | # | |
10 | # Distributed under the terms of the BSD License. The full license is in |
|
10 | # Distributed under the terms of the BSD License. The full license is in | |
11 | # the file COPYING, distributed as part of this software. |
|
11 | # the file COPYING, distributed as part of this software. | |
12 | #------------------------------------------------------------------------------- |
|
12 | #------------------------------------------------------------------------------- | |
13 |
|
13 | |||
14 | #------------------------------------------------------------------------------- |
|
14 | #------------------------------------------------------------------------------- | |
15 | # Imports |
|
15 | # Imports | |
16 | #------------------------------------------------------------------------------- |
|
16 | #------------------------------------------------------------------------------- | |
17 |
|
17 | |||
18 | import os |
|
18 | import os | |
19 | from IPython.config.cutils import get_home_dir, get_ipython_dir |
|
19 | from IPython.config.cutils import get_home_dir, get_ipython_dir | |
20 | from IPython.external.configobj import ConfigObj |
|
20 | from IPython.external.configobj import ConfigObj | |
21 |
|
21 | |||
|
22 | # Traitlets config imports | |||
|
23 | from IPython.config import traitlets | |||
|
24 | from IPython.config.config import * | |||
|
25 | from traitlets import * | |||
|
26 | ||||
22 | class ConfigObjManager(object): |
|
27 | class ConfigObjManager(object): | |
23 |
|
28 | |||
24 | def __init__(self, configObj, filename): |
|
29 | def __init__(self, configObj, filename): | |
25 | self.current = configObj |
|
30 | self.current = configObj | |
26 | self.current.indent_type = ' ' |
|
31 | self.current.indent_type = ' ' | |
27 | self.filename = filename |
|
32 | self.filename = filename | |
28 | # self.write_default_config_file() |
|
33 | # self.write_default_config_file() | |
29 |
|
34 | |||
30 | def get_config_obj(self): |
|
35 | def get_config_obj(self): | |
31 | return self.current |
|
36 | return self.current | |
32 |
|
37 | |||
33 | def update_config_obj(self, newConfig): |
|
38 | def update_config_obj(self, newConfig): | |
34 | self.current.merge(newConfig) |
|
39 | self.current.merge(newConfig) | |
35 |
|
40 | |||
36 | def update_config_obj_from_file(self, filename): |
|
41 | def update_config_obj_from_file(self, filename): | |
37 | newConfig = ConfigObj(filename, file_error=False) |
|
42 | newConfig = ConfigObj(filename, file_error=False) | |
38 | self.current.merge(newConfig) |
|
43 | self.current.merge(newConfig) | |
39 |
|
44 | |||
40 | def update_config_obj_from_default_file(self, ipythondir=None): |
|
45 | def update_config_obj_from_default_file(self, ipythondir=None): | |
41 | fname = self.resolve_file_path(self.filename, ipythondir) |
|
46 | fname = self.resolve_file_path(self.filename, ipythondir) | |
42 | self.update_config_obj_from_file(fname) |
|
47 | self.update_config_obj_from_file(fname) | |
43 |
|
48 | |||
44 | def write_config_obj_to_file(self, filename): |
|
49 | def write_config_obj_to_file(self, filename): | |
45 | f = open(filename, 'w') |
|
50 | f = open(filename, 'w') | |
46 | self.current.write(f) |
|
51 | self.current.write(f) | |
47 | f.close() |
|
52 | f.close() | |
48 |
|
53 | |||
49 | def write_default_config_file(self): |
|
54 | def write_default_config_file(self): | |
50 | ipdir = get_ipython_dir() |
|
55 | ipdir = get_ipython_dir() | |
51 | fname = ipdir + '/' + self.filename |
|
56 | fname = ipdir + '/' + self.filename | |
52 | if not os.path.isfile(fname): |
|
57 | if not os.path.isfile(fname): | |
53 | print "Writing the configuration file to: " + fname |
|
58 | print "Writing the configuration file to: " + fname | |
54 | self.write_config_obj_to_file(fname) |
|
59 | self.write_config_obj_to_file(fname) | |
55 |
|
60 | |||
56 | def _import(self, key): |
|
61 | def _import(self, key): | |
57 | package = '.'.join(key.split('.')[0:-1]) |
|
62 | package = '.'.join(key.split('.')[0:-1]) | |
58 | obj = key.split('.')[-1] |
|
63 | obj = key.split('.')[-1] | |
59 | execString = 'from %s import %s' % (package, obj) |
|
64 | execString = 'from %s import %s' % (package, obj) | |
60 | exec execString |
|
65 | exec execString | |
61 | exec 'temp = %s' % obj |
|
66 | exec 'temp = %s' % obj | |
62 | return temp |
|
67 | return temp | |
63 |
|
68 | |||
64 | def resolve_file_path(self, filename, ipythondir = None): |
|
69 | def resolve_file_path(self, filename, ipythondir = None): | |
65 | """Resolve filenames into absolute paths. |
|
70 | """Resolve filenames into absolute paths. | |
66 |
|
71 | |||
67 | This function looks in the following directories in order: |
|
72 | This function looks in the following directories in order: | |
68 |
|
73 | |||
69 | 1. In the current working directory or by absolute path with ~ expanded |
|
74 | 1. In the current working directory or by absolute path with ~ expanded | |
70 | 2. In ipythondir if that is set |
|
75 | 2. In ipythondir if that is set | |
71 | 3. In the IPYTHONDIR environment variable if it exists |
|
76 | 3. In the IPYTHONDIR environment variable if it exists | |
72 | 4. In the ~/.ipython directory |
|
77 | 4. In the ~/.ipython directory | |
73 |
|
78 | |||
74 | Note: The IPYTHONDIR is also used by the trunk version of IPython so |
|
79 | Note: The IPYTHONDIR is also used by the trunk version of IPython so | |
75 | changing it will also affect it was well. |
|
80 | changing it will also affect it was well. | |
76 | """ |
|
81 | """ | |
77 |
|
82 | |||
78 | # In cwd or by absolute path with ~ expanded |
|
83 | # In cwd or by absolute path with ~ expanded | |
79 | trythis = os.path.expanduser(filename) |
|
84 | trythis = os.path.expanduser(filename) | |
80 | if os.path.isfile(trythis): |
|
85 | if os.path.isfile(trythis): | |
81 | return trythis |
|
86 | return trythis | |
82 |
|
87 | |||
83 | # In ipythondir if it is set |
|
88 | # In ipythondir if it is set | |
84 | if ipythondir is not None: |
|
89 | if ipythondir is not None: | |
85 | trythis = ipythondir + '/' + filename |
|
90 | trythis = ipythondir + '/' + filename | |
86 | if os.path.isfile(trythis): |
|
91 | if os.path.isfile(trythis): | |
87 | return trythis |
|
92 | return trythis | |
88 |
|
93 | |||
89 | trythis = get_ipython_dir() + '/' + filename |
|
94 | trythis = get_ipython_dir() + '/' + filename | |
90 | if os.path.isfile(trythis): |
|
95 | if os.path.isfile(trythis): | |
91 | return trythis |
|
96 | return trythis | |
92 |
|
97 | |||
93 | return None |
|
98 | return None | |
94 |
|
99 | |||
95 |
|
100 | |||
96 |
|
101 | |||
97 |
|
102 | |||
98 |
|
103 | |||
99 |
|
104 |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
This diff has been collapsed as it changes many lines, (622 lines changed) Show them Hide them |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now