title: Make Boto3 upload calls blocking (single threaded)
body: <p><strong>Edit</strong>: my original assumption was proved partly wrong.  I've added a lengthy answer here on which I invite others to stress-test and correct.</p>
  
  <hr>
  
  <p>I am looking for a way to utilize the Boto3 S3 API in a single-threaded manner to mimic a threadsafe key-value store.  In a nutshell, I want to <strong>use the calling thread rather than a new thread</strong> to do the upload.</p>
  
  <p>The default behavior of the <a href="https://github.com/boto/boto3/blob/78c87247d0ced972ec68cbcb5e1b0ca722362b26/boto3/s3/inject.py#L485" rel="nofollow noreferrer"><code>.upload_fileobj()</code></a> method in Boto3 (or <code>.upload_file()</code>), as far as I can tell, is to kick the task off to a new thread and return <code>None</code> immediately. </p>
  
  <p>From the <a href="https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Bucket.upload_fileobj" rel="nofollow noreferrer">docs</a>:</p>
  
  <blockquote>
    <p>This is a managed transfer which will perform a multipart upload in multiple threads if necessary.</p>
  </blockquote>
  
  <p>(If my understanding of this is wrong in the first place, a correcton on that would be helpful as well.  This is in Boto3 1.9.134.)</p>
  
  <pre><code>&gt;&gt;&gt; import io
  &gt;&gt;&gt; import boto3
  &gt;&gt;&gt; bucket = boto3.resource('s3').Bucket('my-bucket-name')
  &gt;&gt;&gt; buf = io.BytesIO(b"test")
  &gt;&gt;&gt; res = bucket.upload_fileobj(buf, 'testobj')
  &gt;&gt;&gt; res is None
  True
  </code></pre>
  
  <p>Now, let's say that <code>buf</code> is not a short 4-byte string, but a huge text blob that's going to take a non-negligible amount of time to fully upload.</p>
  
  <p>I also use this function to check if an object with a given key exists:</p>
  
  <pre><code>def key_exists_in_bucket(bucket_obj, key: str) -&gt; bool:
      try:
          bucket_obj.Object(key).load()
      except botocore.exceptions.ClientError:
          return False
      else:
          return True
  </code></pre>
  
  <p>My intention is to not re-write the object if it exists by name.</p>
  
  <p>The race condition here is fairly obvious: kick off an upload asynchronously, then do a quick check with <code>key_exists_in_bucket()</code>, getting back <code>False</code> if the object is still being written, then go to write it again unnecessarily as a result of that.</p>
  
  <p><strong>Is there a way to ensure that <code>bucket.upload_fileobj()</code> is called by the <em>current thread</em> rather than a new thread created within the scope of that method?</strong></p>
  
  <p>I realize that this will slow things down.  I'm willing to sacrifice speed in this case.</p>