Imho there are only two ways to achieve thread safety: either use locks or risk repeating the import.
In any case, you can no longer rely on exceptions to detect repeated imports. Threads can enter methods of the replacer object concurrently, and if they do so, then the only threadsafe solution is having them both succeed without any exception. You could still enable the current cleanup & exception mechanism for selftests only, but for normal production use, the object should either never clean up, thus allowing repeated replacements, or it should fall back to proxying if the factory has already been cleaned up. The former is easier, and as repeated imports should be a rare scenario, the performance gain from the latter should be negligible. Particularly as even the fallback to proxying won't always prevent repeated imports, as there is still a chance the other thread was interrupted after importing but before cleaning. And I believe that cleaning is not worth the effort, as the whole replacer object will be cleaned soon after the replacement occurred. Therefore cleaning the attributes should have little benefit.
Problem appears to be only moved. See lp:~gagern/bzr/bug-702914 for more tests still exposing this.
Imho there are only two ways to achieve thread safety: either use locks or risk repeating the import.
In any case, you can no longer rely on exceptions to detect repeated imports. Threads can enter methods of the replacer object concurrently, and if they do so, then the only threadsafe solution is having them both succeed without any exception. You could still enable the current cleanup & exception mechanism for selftests only, but for normal production use, the object should either never clean up, thus allowing repeated replacements, or it should fall back to proxying if the factory has already been cleaned up. The former is easier, and as repeated imports should be a rare scenario, the performance gain from the latter should be negligible. Particularly as even the fallback to proxying won't always prevent repeated imports, as there is still a chance the other thread was interrupted after importing but before cleaning. And I believe that cleaning is not worth the effort, as the whole replacer object will be cleaned soon after the replacement occurred. Therefore cleaning the attributes should have little benefit.