11from __future__ import absolute_import
22import json
33
4- from ..hubstorage .job import JobMeta
4+ from ..hubstorage .job import JobMeta as _JobMeta
55from ..hubstorage .job import Items as _Items
66from ..hubstorage .job import Logs as _Logs
77from ..hubstorage .job import Samples as _Samples
1111from .logs import Logs
1212from .requests import Requests
1313from .samples import Samples
14- from .exceptions import NotFound , InvalidUsage , DuplicateJobError
15- from .utils import get_tags_for_update
16- from .utils import parse_job_key
14+ from .exceptions import NotFound , BadRequest , DuplicateJobError
15+ from .utils import _MappingProxy , get_tags_for_update , parse_job_key
1716
1817
1918class Jobs (object ):
@@ -150,7 +149,7 @@ def schedule(self, spidername=None, **params):
150149 try :
151150 response = self ._client ._connection ._post (
152151 'schedule' , 'json' , params )
153- except InvalidUsage as exc :
152+ except BadRequest as exc :
154153 if 'already scheduled' in str (exc ):
155154 raise DuplicateJobError (exc )
156155 raise
@@ -302,10 +301,10 @@ class Job(object):
302301 >>> job = project.job('123/1/2')
303302 >>> job.key
304303 '123/1/2'
305- >>> job.metadata[ 'state']
304+ >>> job.metadata.get( 'state')
306305 'finished'
307306 """
308- def __init__ (self , client , jobkey , metadata = None ):
307+ def __init__ (self , client , jobkey ):
309308 self .projectid = parse_job_key (jobkey ).projectid
310309 self .key = jobkey
311310
@@ -319,24 +318,7 @@ def __init__(self, client, jobkey, metadata=None):
319318 self .requests = Requests (_Requests , client , jobkey )
320319 self .samples = Samples (_Samples , client , jobkey )
321320
322- self .metadata = JobMeta (client ._hsclient , jobkey , cached = metadata )
323-
324- def update_metadata (self , * args , ** kwargs ):
325- """Update job metadata.
326-
327- :param \*\*kwargs: keyword arguments representing job metadata
328-
329- Usage:
330-
331- - update job outcome::
332-
333- >>> job.update_metadata(close_reason='custom reason')
334-
335- - change job tags::
336-
337- >>> job.update_metadata({'tags': 'obsolete'})
338- """
339- self ._job .update_metadata (* args , ** kwargs )
321+ self .metadata = JobMeta (_JobMeta , client , jobkey )
340322
341323 def update_tags (self , add = None , remove = None ):
342324 """Partially update job tags.
@@ -426,19 +408,49 @@ def cancel(self):
426408 Usage::
427409
428410 >>> job.cancel()
429- >>> job.metadata[ 'cancelled_by']
411+ >>> job.metadata.get( 'cancelled_by')
430412 'John'
431413 """
432414 self ._project .jobq .request_cancel (self )
433415
434- def purge (self ):
435- """Delete job and expire its local metadata.
436416
437- Usage::
417+ class JobMeta (_MappingProxy ):
418+ """Class representing job metadata.
438419
439- >>> job.purge()
440- >>> job.metadata['state']
441- 'deleted'
442- """
443- self .delete ()
444- self .metadata .expire ()
420+ Not a public constructor: use :class:`Job` instance to get a
421+ :class:`Jobmeta` instance. See :attr:`Job.metadata` attribute.
422+
423+ Usage::
424+
425+ - get job metadata instance
426+
427+ >>> job.metadata
428+ <scrapinghub.client.jobs.JobMeta at 0x10494f198>
429+
430+ - iterate through job metadata
431+
432+ >>> job.metadata.iter()
433+ <dict_itemiterator at 0x104adbd18>
434+
435+ - list job metadata
436+
437+ >>> job.metadata.list()
438+ [('project', 123), ('units', 1), ('state', 'finished'), ...]
439+
440+ - get meta field value by name
441+
442+ >>> job.metadata.get('version')
443+ 'test'
444+
445+ - update job meta field value (some meta fields are read-only)
446+
447+ >>> job.metadata.set('my-meta', 'test')
448+
449+ - update multiple meta fields at once
450+
451+ >>> job.metadata.update({'my-meta1': 'test1', 'my-meta2': 'test2})
452+
453+ - delete meta field by name
454+
455+ >>> job.metadata.delete('my-meta')
456+ """
0 commit comments