<NME> credentials_provider.py
<BEF> # @license
# Copyright 2017 Google Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import absolute_import

import concurrent.futures
import threading

from .futures import future_then_immediate


class CredentialsManager(object):
    def __init__(self):
        self._providers = dict()

    def register(self, key, credentials_provider_getter):
        self._providers[key] = credentials_provider_getter

    def get(self, key, parameters):


class CredentialsProvider(object):
    def __init__(self):
        self.credentials = None
        self.future = None
        self.next_generation = 0
        self._lock = threading.Lock()

    def get(self, invalid_generation=None):
    def get(self, invalid_generation=None):
        with self._lock:
            if self.future is not None and (self.credentials is None or
                                            invalid_generation != self.credentials['generation']):
                return self.future

            def attach_generation_and_save_credentials(credentials):
                with self._lock:
                    self.next_generation += 1
                    credentials_with_generation = dict(
                        credentials=credentials, generation=self.next_generation)
                    self.credentials = credentials_with_generation
                    return credentials_with_generation

                return credentials_with_generation

        future_then_immediate(self.get_new(), attach_generation_and_save_credentials, future)
        return future

    def get_new(self):
        raise NotImplementedError

<MSG> fix(python): ensure credentials generation numbers aren't reused

Reusing the generation numbers prevented the credentials from being refreshed properly.

<DFF> @@ -31,10 +31,12 @@ class CredentialsManager(object):
 
 
 class CredentialsProvider(object):
+    next_generation = 0
+    next_generation_lock = threading.Lock()
+
     def __init__(self):
         self.credentials = None
         self.future = None
-        self.next_generation = 0
         self._lock = threading.Lock()
 
     def get(self, invalid_generation=None):
@@ -46,9 +48,11 @@ class CredentialsProvider(object):
 
             def attach_generation_and_save_credentials(credentials):
                 with self._lock:
-                    self.next_generation += 1
+                    with CredentialsProvider.next_generation_lock:
+                        CredentialsProvider.next_generation += 1
+                        next_generation = CredentialsProvider.next_generation
                     credentials_with_generation = dict(
-                        credentials=credentials, generation=self.next_generation)
+                        credentials=credentials, generation=next_generation)
                     self.credentials = credentials_with_generation
                     return credentials_with_generation
 

fix(python): ensure credentials generation numbers aren't reused