Merge lp:~mew/charm-helpers/document-core into lp:charm-helpers

Proposed by Matthew Wedgwood
Status: Merged
Merged at revision: 85
Proposed branch: lp:~mew/charm-helpers/document-core
Merge into: lp:charm-helpers
Diff against target: 396 lines (+68/-32)
2 files modified
charmhelpers/core/hookenv.py (+53/-23)
charmhelpers/core/host.py (+15/-9)
To merge this branch: bzr merge lp:~mew/charm-helpers/document-core
Reviewer Review Type Date Requested Status
James Page Approve
Review via email: mp+187623@code.launchpad.net

Description of the change

Add or clean up docstrings for all core functions.

To post a comment you must log in.
Revision history for this message
Nicola Larosa (teknico) wrote :

Very much appreciated, thank you.

However, please be consistent in your choice of docstring delimiters. The convention is to always use triple double-quotes (""").

There's actually a whole guideline for docstrings alone <http://www.python.org/dev/peps/pep-0257/>.

Inconsistency in this has no use that I know of.

lp:~mew/charm-helpers/document-core updated
80. By Matthew Wedgwood

Standardize docstring quoting in core

Revision history for this message
Matthew Wedgwood (mew) wrote :

I've fixed the docstring quoting in the core modules.

Revision history for this message
James Page (james-page) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'charmhelpers/core/hookenv.py'
--- charmhelpers/core/hookenv.py 2013-07-18 16:13:49 +0000
+++ charmhelpers/core/hookenv.py 2013-09-26 14:36:53 +0000
@@ -21,7 +21,7 @@
2121
2222
23def cached(func):23def cached(func):
24 ''' Cache return values for multiple executions of func + args24 """Cache return values for multiple executions of func + args
2525
26 For example:26 For example:
2727
@@ -32,7 +32,7 @@
32 unit_get('test')32 unit_get('test')
3333
34 will cache the result of unit_get + 'test' for future calls.34 will cache the result of unit_get + 'test' for future calls.
35 '''35 """
36 def wrapper(*args, **kwargs):36 def wrapper(*args, **kwargs):
37 global cache37 global cache
38 key = str((func, args, kwargs))38 key = str((func, args, kwargs))
@@ -46,8 +46,8 @@
4646
4747
48def flush(key):48def flush(key):
49 ''' Flushes any entries from function cache where the49 """Flushes any entries from function cache where the
50 key is found in the function+args '''50 key is found in the function+args """
51 flush_list = []51 flush_list = []
52 for item in cache:52 for item in cache:
53 if key in item:53 if key in item:
@@ -57,7 +57,7 @@
5757
5858
59def log(message, level=None):59def log(message, level=None):
60 "Write a message to the juju log"60 """Write a message to the juju log"""
61 command = ['juju-log']61 command = ['juju-log']
62 if level:62 if level:
63 command += ['-l', level]63 command += ['-l', level]
@@ -66,7 +66,7 @@
6666
6767
68class Serializable(UserDict.IterableUserDict):68class Serializable(UserDict.IterableUserDict):
69 "Wrapper, an object that can be serialized to yaml or json"69 """Wrapper, an object that can be serialized to yaml or json"""
7070
71 def __init__(self, obj):71 def __init__(self, obj):
72 # wrap the object72 # wrap the object
@@ -96,11 +96,11 @@
96 self.data = state96 self.data = state
9797
98 def json(self):98 def json(self):
99 "Serialize the object to json"99 """Serialize the object to json"""
100 return json.dumps(self.data)100 return json.dumps(self.data)
101101
102 def yaml(self):102 def yaml(self):
103 "Serialize the object to yaml"103 """Serialize the object to yaml"""
104 return yaml.dump(self.data)104 return yaml.dump(self.data)
105105
106106
@@ -119,38 +119,38 @@
119119
120120
121def in_relation_hook():121def in_relation_hook():
122 "Determine whether we're running in a relation hook"122 """Determine whether we're running in a relation hook"""
123 return 'JUJU_RELATION' in os.environ123 return 'JUJU_RELATION' in os.environ
124124
125125
126def relation_type():126def relation_type():
127 "The scope for the current relation hook"127 """The scope for the current relation hook"""
128 return os.environ.get('JUJU_RELATION', None)128 return os.environ.get('JUJU_RELATION', None)
129129
130130
131def relation_id():131def relation_id():
132 "The relation ID for the current relation hook"132 """The relation ID for the current relation hook"""
133 return os.environ.get('JUJU_RELATION_ID', None)133 return os.environ.get('JUJU_RELATION_ID', None)
134134
135135
136def local_unit():136def local_unit():
137 "Local unit ID"137 """Local unit ID"""
138 return os.environ['JUJU_UNIT_NAME']138 return os.environ['JUJU_UNIT_NAME']
139139
140140
141def remote_unit():141def remote_unit():
142 "The remote unit for the current relation hook"142 """The remote unit for the current relation hook"""
143 return os.environ['JUJU_REMOTE_UNIT']143 return os.environ['JUJU_REMOTE_UNIT']
144144
145145
146def service_name():146def service_name():
147 "The name service group this unit belongs to"147 """The name service group this unit belongs to"""
148 return local_unit().split('/')[0]148 return local_unit().split('/')[0]
149149
150150
151@cached151@cached
152def config(scope=None):152def config(scope=None):
153 "Juju charm configuration"153 """Juju charm configuration"""
154 config_cmd_line = ['config-get']154 config_cmd_line = ['config-get']
155 if scope is not None:155 if scope is not None:
156 config_cmd_line.append(scope)156 config_cmd_line.append(scope)
@@ -163,6 +163,7 @@
163163
164@cached164@cached
165def relation_get(attribute=None, unit=None, rid=None):165def relation_get(attribute=None, unit=None, rid=None):
166 """Get relation information"""
166 _args = ['relation-get', '--format=json']167 _args = ['relation-get', '--format=json']
167 if rid:168 if rid:
168 _args.append('-r')169 _args.append('-r')
@@ -177,6 +178,7 @@
177178
178179
179def relation_set(relation_id=None, relation_settings={}, **kwargs):180def relation_set(relation_id=None, relation_settings={}, **kwargs):
181 """Set relation information for the current unit"""
180 relation_cmd_line = ['relation-set']182 relation_cmd_line = ['relation-set']
181 if relation_id is not None:183 if relation_id is not None:
182 relation_cmd_line.extend(('-r', relation_id))184 relation_cmd_line.extend(('-r', relation_id))
@@ -192,7 +194,7 @@
192194
193@cached195@cached
194def relation_ids(reltype=None):196def relation_ids(reltype=None):
195 "A list of relation_ids"197 """A list of relation_ids"""
196 reltype = reltype or relation_type()198 reltype = reltype or relation_type()
197 relid_cmd_line = ['relation-ids', '--format=json']199 relid_cmd_line = ['relation-ids', '--format=json']
198 if reltype is not None:200 if reltype is not None:
@@ -203,7 +205,7 @@
203205
204@cached206@cached
205def related_units(relid=None):207def related_units(relid=None):
206 "A list of related units"208 """A list of related units"""
207 relid = relid or relation_id()209 relid = relid or relation_id()
208 units_cmd_line = ['relation-list', '--format=json']210 units_cmd_line = ['relation-list', '--format=json']
209 if relid is not None:211 if relid is not None:
@@ -213,7 +215,7 @@
213215
214@cached216@cached
215def relation_for_unit(unit=None, rid=None):217def relation_for_unit(unit=None, rid=None):
216 "Get the json represenation of a unit's relation"218 """Get the json represenation of a unit's relation"""
217 unit = unit or remote_unit()219 unit = unit or remote_unit()
218 relation = relation_get(unit=unit, rid=rid)220 relation = relation_get(unit=unit, rid=rid)
219 for key in relation:221 for key in relation:
@@ -225,7 +227,7 @@
225227
226@cached228@cached
227def relations_for_id(relid=None):229def relations_for_id(relid=None):
228 "Get relations of a specific relation ID"230 """Get relations of a specific relation ID"""
229 relation_data = []231 relation_data = []
230 relid = relid or relation_ids()232 relid = relid or relation_ids()
231 for unit in related_units(relid):233 for unit in related_units(relid):
@@ -237,7 +239,7 @@
237239
238@cached240@cached
239def relations_of_type(reltype=None):241def relations_of_type(reltype=None):
240 "Get relations of a specific type"242 """Get relations of a specific type"""
241 relation_data = []243 relation_data = []
242 reltype = reltype or relation_type()244 reltype = reltype or relation_type()
243 for relid in relation_ids(reltype):245 for relid in relation_ids(reltype):
@@ -249,7 +251,7 @@
249251
250@cached252@cached
251def relation_types():253def relation_types():
252 "Get a list of relation types supported by this charm"254 """Get a list of relation types supported by this charm"""
253 charmdir = os.environ.get('CHARM_DIR', '')255 charmdir = os.environ.get('CHARM_DIR', '')
254 mdf = open(os.path.join(charmdir, 'metadata.yaml'))256 mdf = open(os.path.join(charmdir, 'metadata.yaml'))
255 md = yaml.safe_load(mdf)257 md = yaml.safe_load(mdf)
@@ -264,6 +266,7 @@
264266
265@cached267@cached
266def relations():268def relations():
269 """Get a nested dictionary of relation data for all related units"""
267 rels = {}270 rels = {}
268 for reltype in relation_types():271 for reltype in relation_types():
269 relids = {}272 relids = {}
@@ -278,14 +281,14 @@
278281
279282
280def open_port(port, protocol="TCP"):283def open_port(port, protocol="TCP"):
281 "Open a service network port"284 """Open a service network port"""
282 _args = ['open-port']285 _args = ['open-port']
283 _args.append('{}/{}'.format(port, protocol))286 _args.append('{}/{}'.format(port, protocol))
284 subprocess.check_call(_args)287 subprocess.check_call(_args)
285288
286289
287def close_port(port, protocol="TCP"):290def close_port(port, protocol="TCP"):
288 "Close a service network port"291 """Close a service network port"""
289 _args = ['close-port']292 _args = ['close-port']
290 _args.append('{}/{}'.format(port, protocol))293 _args.append('{}/{}'.format(port, protocol))
291 subprocess.check_call(_args)294 subprocess.check_call(_args)
@@ -293,6 +296,7 @@
293296
294@cached297@cached
295def unit_get(attribute):298def unit_get(attribute):
299 """Get the unit ID for the remote unit"""
296 _args = ['unit-get', '--format=json', attribute]300 _args = ['unit-get', '--format=json', attribute]
297 try:301 try:
298 return json.loads(subprocess.check_output(_args))302 return json.loads(subprocess.check_output(_args))
@@ -301,22 +305,46 @@
301305
302306
303def unit_private_ip():307def unit_private_ip():
308 """Get this unit's private IP address"""
304 return unit_get('private-address')309 return unit_get('private-address')
305310
306311
307class UnregisteredHookError(Exception):312class UnregisteredHookError(Exception):
313 """Raised when an undefined hook is called"""
308 pass314 pass
309315
310316
311class Hooks(object):317class Hooks(object):
318 """A convenient handler for hook functions.
319
320 Example:
321 hooks = Hooks()
322
323 # register a hook, taking its name from the function name
324 @hooks.hook()
325 def install():
326 ...
327
328 # register a hook, providing a custom hook name
329 @hooks.hook("config-changed")
330 def config_changed():
331 ...
332
333 if __name__ == "__main__":
334 # execute a hook based on the name the program is called by
335 hooks.execute(sys.argv)
336 """
337
312 def __init__(self):338 def __init__(self):
313 super(Hooks, self).__init__()339 super(Hooks, self).__init__()
314 self._hooks = {}340 self._hooks = {}
315341
316 def register(self, name, function):342 def register(self, name, function):
343 """Register a hook"""
317 self._hooks[name] = function344 self._hooks[name] = function
318345
319 def execute(self, args):346 def execute(self, args):
347 """Execute a registered hook based on args[0]"""
320 hook_name = os.path.basename(args[0])348 hook_name = os.path.basename(args[0])
321 if hook_name in self._hooks:349 if hook_name in self._hooks:
322 self._hooks[hook_name]()350 self._hooks[hook_name]()
@@ -324,6 +352,7 @@
324 raise UnregisteredHookError(hook_name)352 raise UnregisteredHookError(hook_name)
325353
326 def hook(self, *hook_names):354 def hook(self, *hook_names):
355 """Decorator, registering them as hooks"""
327 def wrapper(decorated):356 def wrapper(decorated):
328 for hook_name in hook_names:357 for hook_name in hook_names:
329 self.register(hook_name, decorated)358 self.register(hook_name, decorated)
@@ -337,4 +366,5 @@
337366
338367
339def charm_dir():368def charm_dir():
369 """Return the root directory of the current charm"""
340 return os.environ.get('CHARM_DIR')370 return os.environ.get('CHARM_DIR')
341371
=== modified file 'charmhelpers/core/host.py'
--- charmhelpers/core/host.py 2013-08-23 16:42:43 +0000
+++ charmhelpers/core/host.py 2013-09-26 14:36:53 +0000
@@ -19,18 +19,22 @@
1919
2020
21def service_start(service_name):21def service_start(service_name):
22 """Start a system service"""
22 return service('start', service_name)23 return service('start', service_name)
2324
2425
25def service_stop(service_name):26def service_stop(service_name):
27 """Stop a system service"""
26 return service('stop', service_name)28 return service('stop', service_name)
2729
2830
29def service_restart(service_name):31def service_restart(service_name):
32 """Restart a system service"""
30 return service('restart', service_name)33 return service('restart', service_name)
3134
3235
33def service_reload(service_name, restart_on_failure=False):36def service_reload(service_name, restart_on_failure=False):
37 """Reload a system service, optionally falling back to restart if reload fails"""
34 service_result = service('reload', service_name)38 service_result = service('reload', service_name)
35 if not service_result and restart_on_failure:39 if not service_result and restart_on_failure:
36 service_result = service('restart', service_name)40 service_result = service('restart', service_name)
@@ -38,11 +42,13 @@
3842
3943
40def service(action, service_name):44def service(action, service_name):
45 """Control a system service"""
41 cmd = ['service', service_name, action]46 cmd = ['service', service_name, action]
42 return subprocess.call(cmd) == 047 return subprocess.call(cmd) == 0
4348
4449
45def service_running(service):50def service_running(service):
51 """Determine whether a system service is running"""
46 try:52 try:
47 output = subprocess.check_output(['service', service, 'status'])53 output = subprocess.check_output(['service', service, 'status'])
48 except subprocess.CalledProcessError:54 except subprocess.CalledProcessError:
@@ -55,7 +61,7 @@
5561
5662
57def adduser(username, password=None, shell='/bin/bash', system_user=False):63def adduser(username, password=None, shell='/bin/bash', system_user=False):
58 """Add a user"""64 """Add a user to the system"""
59 try:65 try:
60 user_info = pwd.getpwnam(username)66 user_info = pwd.getpwnam(username)
61 log('user {0} already exists!'.format(username))67 log('user {0} already exists!'.format(username))
@@ -138,7 +144,7 @@
138144
139145
140def mount(device, mountpoint, options=None, persist=False):146def mount(device, mountpoint, options=None, persist=False):
141 '''Mount a filesystem'''147 """Mount a filesystem at a particular mountpoint"""
142 cmd_args = ['mount']148 cmd_args = ['mount']
143 if options is not None:149 if options is not None:
144 cmd_args.extend(['-o', options])150 cmd_args.extend(['-o', options])
@@ -155,7 +161,7 @@
155161
156162
157def umount(mountpoint, persist=False):163def umount(mountpoint, persist=False):
158 '''Unmount a filesystem'''164 """Unmount a filesystem"""
159 cmd_args = ['umount', mountpoint]165 cmd_args = ['umount', mountpoint]
160 try:166 try:
161 subprocess.check_output(cmd_args)167 subprocess.check_output(cmd_args)
@@ -169,7 +175,7 @@
169175
170176
171def mounts():177def mounts():
172 '''List of all mounted volumes as [[mountpoint,device],[...]]'''178 """Get a list of all mounted volumes as [[mountpoint,device],[...]]"""
173 with open('/proc/mounts') as f:179 with open('/proc/mounts') as f:
174 # [['/mount/point','/dev/path'],[...]]180 # [['/mount/point','/dev/path'],[...]]
175 system_mounts = [m[1::-1] for m in [l.strip().split()181 system_mounts = [m[1::-1] for m in [l.strip().split()
@@ -178,7 +184,7 @@
178184
179185
180def file_hash(path):186def file_hash(path):
181 ''' Generate a md5 hash of the contents of 'path' or None if not found '''187 """Generate a md5 hash of the contents of 'path' or None if not found """
182 if os.path.exists(path):188 if os.path.exists(path):
183 h = hashlib.md5()189 h = hashlib.md5()
184 with open(path, 'r') as source:190 with open(path, 'r') as source:
@@ -189,7 +195,7 @@
189195
190196
191def restart_on_change(restart_map):197def restart_on_change(restart_map):
192 ''' Restart services based on configuration files changing198 """Restart services based on configuration files changing
193199
194 This function is used a decorator, for example200 This function is used a decorator, for example
195201
@@ -202,7 +208,7 @@
202 In this example, the cinder-api and cinder-volume services208 In this example, the cinder-api and cinder-volume services
203 would be restarted if /etc/ceph/ceph.conf is changed by the209 would be restarted if /etc/ceph/ceph.conf is changed by the
204 ceph_client_changed function.210 ceph_client_changed function.
205 '''211 """
206 def wrap(f):212 def wrap(f):
207 def wrapped_f(*args):213 def wrapped_f(*args):
208 checksums = {}214 checksums = {}
@@ -220,7 +226,7 @@
220226
221227
222def lsb_release():228def lsb_release():
223 '''Return /etc/lsb-release in a dict'''229 """Return /etc/lsb-release in a dict"""
224 d = {}230 d = {}
225 with open('/etc/lsb-release', 'r') as lsb:231 with open('/etc/lsb-release', 'r') as lsb:
226 for l in lsb:232 for l in lsb:
@@ -230,7 +236,7 @@
230236
231237
232def pwgen(length=None):238def pwgen(length=None):
233 '''Generate a random pasword.'''239 """Generate a random pasword."""
234 if length is None:240 if length is None:
235 length = random.choice(range(35, 45))241 length = random.choice(range(35, 45))
236 alphanumeric_chars = [242 alphanumeric_chars = [

Subscribers

People subscribed via source and target branches