Repository: conda/conda

Issue:
CondaMultiError precludes catching more specific exceptions
In trying to narrow Conda-build's exception scope, I find that I cannot directly catch the PaddingError here:

```
===================================================== FAILURES =====================================================
______________________________ test_env_creation_with_short_prefix_does_not_deadlock _______________________________
Traceback (most recent call last):
  File "/Users/msarahan/code/conda/conda/core/path_actions.py", line 299, in execute
    self.file_mode)
  File "/Users/msarahan/code/conda/conda/core/portability.py", line 57, in update_prefix
    update_file_in_place_as_binary(realpath(path), _update_prefix)
  File "/Users/msarahan/code/conda/conda/gateways/disk/update.py", line 33, in update_file_in_place_as_binary
    fh.write(callback(data))
  File "/Users/msarahan/code/conda/conda/core/portability.py", line 39, in _update_prefix
    data = replace_prefix(mode, original_data, placeholder, new_prefix)
  File "/Users/msarahan/code/conda/conda/core/portability.py", line 64, in replace_prefix
    data = binary_replace(data, placeholder.encode('utf-8'), new_prefix.encode('utf-8'))
  File "/Users/msarahan/code/conda/conda/core/portability.py", line 93, in binary_replace
    data = pat.sub(replace, data)
  File "/Users/msarahan/code/conda/conda/core/portability.py", line 88, in replace
    raise _PaddingError
conda.core.portability._PaddingError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/msarahan/code/conda/conda/core/link.py", line 326, in _execute_actions
    action.execute()
  File "/Users/msarahan/code/conda/conda/core/path_actions.py", line 302, in execute
    len(self.prefix_placeholder))
conda.exceptions.PaddingError: Placeholder of length '80' too short in package /tmp/cb/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_/binary-has-prefix.
The package must be rebuilt with conda-build > 2.0.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/msarahan/code/conda/conda/core/link.py", line 281, in execute
    pkg_data, actions)
  File "/Users/msarahan/code/conda/conda/core/link.py", line 344, in _execute_actions
    reverse_excs,
conda.CondaMultiError: Placeholder of length '80' too short in package /tmp/cb/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_/binary-has-prefix.
The package must be rebuilt with conda-build > 2.0.


During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/msarahan/code/conda-build/tests/test_environ.py", line 34, in test_env_creation_with_short_prefix_does_not_deadlock
    env='build', config=config, subdir=subdir)
  File "/Users/msarahan/code/conda-build/conda_build/environ.py", line 788, in create_env
    execute_actions(actions, index, verbose=config.debug)
  File "/Users/msarahan/code/conda/conda/plan.py", line 830, in execute_actions
    execute_instructions(plan, index, verbose)
  File "/Users/msarahan/code/conda/conda/instructions.py", line 247, in execute_instructions
    cmd(state, arg)
  File "/Users/msarahan/code/conda/conda/instructions.py", line 108, in UNLINKLINKTRANSACTION_CMD
    txn.execute()
  File "/Users/msarahan/code/conda/conda/core/link.py", line 297, in execute
    rollback_excs,
conda.CondaMultiError: Placeholder of length '80' too short in package /tmp/cb/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_/binary-has-prefix.
The package must be rebuilt with conda-build > 2.0.
```

Do you have any advice for how to pull apart a CondaMultiError to look for the specific error types that we want to look for?
CondaMultiError precludes catching more specific exceptions
In trying to narrow Conda-build's exception scope, I find that I cannot directly catch the PaddingError here:

```
===================================================== FAILURES =====================================================
______________________________ test_env_creation_with_short_prefix_does_not_deadlock _______________________________
Traceback (most recent call last):
  File "/Users/msarahan/code/conda/conda/core/path_actions.py", line 299, in execute
    self.file_mode)
  File "/Users/msarahan/code/conda/conda/core/portability.py", line 57, in update_prefix
    update_file_in_place_as_binary(realpath(path), _update_prefix)
  File "/Users/msarahan/code/conda/conda/gateways/disk/update.py", line 33, in update_file_in_place_as_binary
    fh.write(callback(data))
  File "/Users/msarahan/code/conda/conda/core/portability.py", line 39, in _update_prefix
    data = replace_prefix(mode, original_data, placeholder, new_prefix)
  File "/Users/msarahan/code/conda/conda/core/portability.py", line 64, in replace_prefix
    data = binary_replace(data, placeholder.encode('utf-8'), new_prefix.encode('utf-8'))
  File "/Users/msarahan/code/conda/conda/core/portability.py", line 93, in binary_replace
    data = pat.sub(replace, data)
  File "/Users/msarahan/code/conda/conda/core/portability.py", line 88, in replace
    raise _PaddingError
conda.core.portability._PaddingError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/msarahan/code/conda/conda/core/link.py", line 326, in _execute_actions
    action.execute()
  File "/Users/msarahan/code/conda/conda/core/path_actions.py", line 302, in execute
    len(self.prefix_placeholder))
conda.exceptions.PaddingError: Placeholder of length '80' too short in package /tmp/cb/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_/binary-has-prefix.
The package must be rebuilt with conda-build > 2.0.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/msarahan/code/conda/conda/core/link.py", line 281, in execute
    pkg_data, actions)
  File "/Users/msarahan/code/conda/conda/core/link.py", line 344, in _execute_actions
    reverse_excs,
conda.CondaMultiError: Placeholder of length '80' too short in package /tmp/cb/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_/binary-has-prefix.
The package must be rebuilt with conda-build > 2.0.


During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/msarahan/code/conda-build/tests/test_environ.py", line 34, in test_env_creation_with_short_prefix_does_not_deadlock
    env='build', config=config, subdir=subdir)
  File "/Users/msarahan/code/conda-build/conda_build/environ.py", line 788, in create_env
    execute_actions(actions, index, verbose=config.debug)
  File "/Users/msarahan/code/conda/conda/plan.py", line 830, in execute_actions
    execute_instructions(plan, index, verbose)
  File "/Users/msarahan/code/conda/conda/instructions.py", line 247, in execute_instructions
    cmd(state, arg)
  File "/Users/msarahan/code/conda/conda/instructions.py", line 108, in UNLINKLINKTRANSACTION_CMD
    txn.execute()
  File "/Users/msarahan/code/conda/conda/core/link.py", line 297, in execute
    rollback_excs,
conda.CondaMultiError: Placeholder of length '80' too short in package /tmp/cb/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_/binary-has-prefix.
The package must be rebuilt with conda-build > 2.0.
```

Do you have any advice for how to pull apart a CondaMultiError to look for the specific error types that we want to look for?


Discussion:
I can add a `contains` method on `CondaMultiError`.  In the interim, you could do the same for code locally until we get a few releases out with the addition.  Here's what it would look like

```python
    def contains(self, exception_class):
        return any(isinstance(e, exception_class) for e in self.errors)

```


I can add a `contains` method on `CondaMultiError`.  In the interim, you could do the same for code locally until we get a few releases out with the addition.  Here's what it would look like

```python
    def contains(self, exception_class):
        return any(isinstance(e, exception_class) for e in self.errors)

```



Resolving patch:
diff --git a/conda/__init__.py b/conda/__init__.py
--- a/conda/__init__.py
+++ b/conda/__init__.py
@@ -88,6 +88,9 @@ def dump_map(self):
                     error="Multiple Errors Encountered.",
                     )
 
+    def contains(self, exception_class):
+        return any(isinstance(e, exception_class) for e in self.errors)
+
 
 class CondaExitZero(CondaError):
     pass


Test patch: