class_docstr: Base class to store one piece of work.
  
  In adversarial competition, all work consists of the following:
  - evaluation of all attacks on all images from dataset which results in
    generation of adversarial images;
  - evaluation of all defenses on all adversarial images which results in
    storing classification labels.
  
  One piece of work is either evaluation of one attack on a subset of images or
  evaluation of one defense on a subset of adversarial images.
  This way all work is split into work pieces which could be computed
  independently in parallel by different workers.
  
  Each work piece is identified by unique ID and has one of the following
  statuses:
  - Unclaimed. This means that no worker has started working on the work piece.
  - Claimed by worker NN. This means that worker NN is working on this work
    piece. After workpiece being claimed for too long (more than
    MAX_PROCESSING_TIME seconds) it automatically considered unclaimed. This
    is needed in case worker failed while processing the work piece.
  - Completed. This means that computation of work piece is done.
  
  Additionally each work piece may be assigned to a shard. In such case
  workers are also grouped into shards. Each time worker looking for a work
  piece it first tries to find undone work from the shard worker is assigned to.
  Only after all work from this shard is done, worker will try to claim
  work pieces from other shards.
  
  The purpose of sharding is to reduce load on Google Cloud Datastore.
docstr: Writes all work pieces into datastore.
  
  Each work piece is identified by ID. This method writes/updates only those
  work pieces which IDs are stored in this class. For examples, if this class
  has only work pieces with IDs  '1' ... '100' and datastore already contains
  work pieces with IDs '50' ... '200' then this method will create new
  work pieces with IDs '1' ... '49', update work pieces with IDs
  '50' ... '100' and keep unchanged work pieces with IDs '101' ... '200'.
code: def write_all_to_datastore(self):
      """Writes all work pieces into datastore.
  
      Each work piece is identified by ID. This method writes/updates only those
      work pieces which IDs are stored in this class. For examples, if this class
      has only work pieces with IDs  '1' ... '100' and datastore already contains
      work pieces with IDs '50' ... '200' then this method will create new
      work pieces with IDs '1' ... '49', update work pieces with IDs
      '50' ... '100' and keep unchanged work pieces with IDs '101' ... '200'.
      """
      client = self._datastore_client
      with client.no_transact_batch() as batch:
          parent_key = client.key(
              KIND_WORK_TYPE, self._work_type_entity_id
          )
          batch.put(client.entity(parent_key))
          for work_id, work_val in iteritems(self._work):
              entity = client.entity(
                  client.key(KIND_WORK, work_id, parent=parent_key)
              )
              entity.update(work_val)
              batch.put(entity)
  
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  from builtins import int
  from io import StringIO
  import pickle
  import random
  import time
  import numpy
  from six import iteritems
  from six import itervalues
  from six import text_type
label_desc: Use image node_id 8 for calling the WorkPiecesBase obj's underlying member method code with example usage: obj.write_all_to_datastore() without return types