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: Tries pick next unclaimed piece of work to do.
  
  Attempt to claim work piece is done using Cloud Datastore transaction, so
  only one worker can claim any work piece at a time.
  
  Args:
    worker_id: ID of current worker
    submission_id: if not None then this method will try to pick
      piece of work for this submission
  
  Returns:
    ID of the claimed work piece
code: def try_pick_piece_of_work(self, worker_id, submission_id=None):
      """Tries pick next unclaimed piece of work to do.
  
      Attempt to claim work piece is done using Cloud Datastore transaction, so
      only one worker can claim any work piece at a time.
  
      Args:
        worker_id: ID of current worker
        submission_id: if not None then this method will try to pick
          piece of work for this submission
  
      Returns:
        ID of the claimed work piece
      """
      client = self._datastore_client
      unclaimed_work_ids = None
      if submission_id:
          unclaimed_work_ids = [
              k
              for k, v in iteritems(self.work)
              if is_unclaimed(v)
              and (v["submission_id"] == submission_id)
          ]
      if not unclaimed_work_ids:
          unclaimed_work_ids = [
              k for k, v in iteritems(self.work) if is_unclaimed(v)
          ]
      if unclaimed_work_ids:
          next_work_id = random.choice(unclaimed_work_ids)
      else:
          return None
      try:
          with client.transaction() as transaction:
              work_key = client.key(
                  KIND_WORK_TYPE,
                  self._work_type_entity_id,
                  KIND_WORK,
                  next_work_id,
              )
              work_entity = client.get(
                  work_key, transaction=transaction
              )
              if not is_unclaimed(work_entity):
                  return None
              work_entity["claimed_worker_id"] = worker_id
              work_entity[
                  "claimed_worker_start_time"
              ] = get_integer_time()
              transaction.put(work_entity)
      except Exception:
          return None
      return next_work_id
  
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 12 for calling the WorkPiecesBase obj's underlying member method code with example usage: obj.try_pick_piece_of_work(worker_id, submission_id) and returns: next_work_id, None, None, None