Skip to content

Commit 87edfbd

Browse files
authored
Merge pull request #319 from Duke-GCB/better-exception-handling
Show stack traces for general exceptions
2 parents 83cd532 + 0d7400c commit 87edfbd

22 files changed

Lines changed: 63 additions & 37 deletions

ddsc/__main__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Duke data service command line project management utility."""
22
import sys
33
from ddsc.ddsclient import DDSClient
4+
from ddsc.exceptions import DDSUserException
45

56

67
def main(args=None):
@@ -9,7 +10,7 @@ def main(args=None):
910
client = DDSClient()
1011
try:
1112
client.run_command(args)
12-
except Exception as ex:
13+
except DDSUserException as ex:
1314
if client.show_error_stack_trace:
1415
raise
1516
else:

ddsc/config.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import yaml
66
import multiprocessing
77
from ddsc.core.util import verify_file_private
8+
from ddsc.exceptions import DDSUserException
89

910
try:
1011
from urllib.parse import urlparse
@@ -92,7 +93,7 @@ def add_properties(self, filename):
9293
if config_data:
9394
self.update_properties(config_data)
9495
else:
95-
raise ValueError("Error: Empty config file {}".format(filename))
96+
raise DDSUserException("Error: Empty config file {}".format(filename))
9697

9798
def update_properties(self, new_values):
9899
"""

ddsc/core/d4s2.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from ddsc.versioncheck import get_internal_version_str
1515
from ddsc.core.remotestore import ProjectNameOrId, RemotePath
1616
from ddsc.sdk.client import Client
17+
from ddsc.exceptions import DDSUserException
1718

1819
UNAUTHORIZED_MESSAGE = """
1920
ERROR: Your account does not have authorization for D4S2 (the deliver/share service).
@@ -33,7 +34,7 @@
3334
"""
3435

3536

36-
class D4S2Error(Exception):
37+
class D4S2Error(DDSUserException):
3738
def __init__(self, message, warning=False):
3839
"""
3940
Setup error.
@@ -45,7 +46,7 @@ def __init__(self, message, warning=False):
4546
self.warning = warning
4647

4748

48-
class ShareWithSelfError(Exception):
49+
class ShareWithSelfError(DDSUserException):
4950
"""
5051
Error raised whe user attempts to share/deliver a project just themselves
5152
"""
@@ -56,7 +57,7 @@ def __init__(self, message):
5657
Exception.__init__(self, message)
5758

5859

59-
class UserMissingEmailError(Exception):
60+
class UserMissingEmailError(DDSUserException):
6061
"""
6162
Raised when attempting to deliver or share with a DukeDS user that has a null email
6263
"""
@@ -345,7 +346,7 @@ def _copy_project(self, project, new_project_name, path_filter):
345346
new_project_name_or_id = ProjectNameOrId.create_from_name(new_project_name)
346347
remote_project = self.remote_store.fetch_remote_project(new_project_name_or_id)
347348
if remote_project:
348-
raise ValueError("A project with name '{}' already exists.".format(new_project_name))
349+
raise DDSUserException("A project with name '{}' already exists.".format(new_project_name))
349350
activity = CopyActivity(self.remote_store.data_service, project, new_project_name)
350351
self._download_project(activity, project.id, temp_directory, path_filter)
351352
self._upload_project(activity, new_project_name, temp_directory)

ddsc/core/ddsapi.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from ddsc.config import get_user_config_filename
88
from ddsc.versioncheck import APP_NAME, get_internal_version_str
99
from ddsc.core.retry import RetrySettings
10+
from ddsc.exceptions import DDSUserException
1011

1112
AUTH_TOKEN_CLOCK_SKEW_MAX = 5 * 60 # 5 minutes
1213
SETUP_GUIDE_URL = "https://github.com/Duke-GCB/DukeDSClient/blob/master/docs/GettingAgentAndUserKeys.md"
@@ -1278,7 +1279,7 @@ class ActivityRelationTypes(object):
12781279
WAS_INVALIDATED_BY = "was_invalidated_by"
12791280

12801281

1281-
class AuthTokenException(Exception):
1282+
class AuthTokenException(DDSUserException):
12821283
def __init__(self, message):
12831284
super(AuthTokenException, self).__init__(message)
12841285

ddsc/core/fileuploader.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from ddsc.core.util import ProgressQueue, wait_for_processes
1010
from ddsc.core.localstore import HashData
1111
from ddsc.core.retry import RetrySettings
12+
from ddsc.exceptions import DDSUserException
1213
import traceback
1314
import sys
1415
import time
@@ -260,8 +261,8 @@ def _verify_upload_response(upload_response):
260261
if file_chunks:
261262
total_chunk_size = sum([chunk['size'] for chunk in file_chunks])
262263
if file_size != total_chunk_size:
263-
raise ValueError("Failure uploading {}. Size mismatch file: {} vs chunks:{}."
264-
"\nPlease retry uploading.".format(file_name, file_size, total_chunk_size))
264+
raise DDSUserException("Failure uploading {}. Size mismatch file: {} vs chunks:{}."
265+
"\nPlease retry uploading.".format(file_name, file_size, total_chunk_size))
265266

266267

267268
class ParallelChunkProcessor(object):

ddsc/core/moveutil.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
from ddsc.core.util import KindType
3+
from ddsc.exceptions import DDSUserException
34

45

56
class MoveUtil(object):
@@ -24,7 +25,7 @@ def get_new_parent(self):
2425
if self.is_folder_or_project(target):
2526
return target
2627
else:
27-
raise ValueError("Cannot move to existing file {}.".format(self.target_remote_path))
28+
raise DDSUserException("Cannot move to existing file {}.".format(self.target_remote_path))
2829
else:
2930
source_parent_remote_path = os.path.dirname(self.source_remote_path)
3031
target_parent_remote_path = os.path.dirname(self.target_remote_path)
@@ -34,9 +35,9 @@ def get_new_parent(self):
3435
if self.is_folder_or_project(target_parent):
3536
return target_parent
3637
else:
37-
raise ValueError("Target parent {} is a file.".format(target_parent_remote_path))
38+
raise DDSUserException("Target parent {} is a file.".format(target_parent_remote_path))
3839
else:
39-
raise ValueError("Target parent directory {} does not exist.".format(target_parent_remote_path))
40+
raise DDSUserException("Target parent directory {} does not exist.".format(target_parent_remote_path))
4041
return None
4142

4243
def get_new_name(self):

ddsc/core/remotestore.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from ddsc.core.util import KindType, REMOTE_PATH_SEP, RemotePath
44
from ddsc.core.localstore import HashUtil
55
from ddsc.core.userutil import UserUtil, DUKE_EMAIL_SUFFIX
6+
from ddsc.exceptions import DDSUserException
67

78
FETCH_ALL_USERS_PAGE_SIZE = 25
89
DOWNLOAD_FILE_CHUNK_SIZE = 20 * 1024 * 1024
@@ -110,7 +111,7 @@ def lookup_user_by_name(self, full_name):
110111
if found_cnt == 0:
111112
raise NotFoundError("User not found:" + full_name)
112113
elif found_cnt > 1:
113-
raise ValueError("Multiple users with name:" + full_name)
114+
raise DDSUserException("Multiple users with name:" + full_name)
114115
user = RemoteUser(results[0])
115116
if user.full_name.lower() != full_name.lower():
116117
raise NotFoundError("User not found:" + full_name)
@@ -142,7 +143,7 @@ def get_or_register_user_by_email(self, email):
142143
if affiliate:
143144
user_json = util.register_user_by_username(affiliate['uid'])
144145
else:
145-
raise ValueError("Unable to find or register a user with email {}".format(email))
146+
raise DDSUserException("Unable to find or register a user with email {}".format(email))
146147
return RemoteUser(user_json)
147148

148149
def get_auth_providers(self):
@@ -272,7 +273,7 @@ def delete_project(self, project_name_or_id):
272273
if project:
273274
self.data_service.delete_project(project.id)
274275
else:
275-
raise ValueError("No project with {} found.\n".format(project_name_or_id.description()))
276+
raise DDSUserException("No project with {} found.\n".format(project_name_or_id.description()))
276277

277278
def get_active_auth_roles(self, context):
278279
"""
@@ -435,7 +436,7 @@ def get_upload_from_json(json_data):
435436
if 'upload' in json_data:
436437
return json_data['upload']
437438
else:
438-
raise ValueError("Invalid file json data, unable to find upload.")
439+
raise DDSUserException("Invalid file json data, unable to find upload.")
439440

440441
@staticmethod
441442
def get_hash_from_upload(upload, target_algorithm=HashUtil.HASH_NAME):
@@ -572,7 +573,7 @@ def __init__(self, json_data):
572573
self.login_initiation_url = json_data['login_initiation_url']
573574

574575

575-
class NotFoundError(Exception):
576+
class NotFoundError(DDSUserException):
576577
def __init__(self, message):
577578
Exception.__init__(self, message)
578579
self.message = message

ddsc/core/tests/test_fileuploader.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from ddsc.core.fileuploader import ParallelChunkProcessor, upload_async, FileUploadOperations, \
33
RetrySettings, ForbiddenSendExternalException, ChunkSender, FileUploader
44
from ddsc.core.ddsapi import DSResourceNotConsistentError, DataServiceError
5+
from ddsc.exceptions import DDSUserException
56
import requests
67
from mock import MagicMock, Mock, patch, call, ANY
78

@@ -188,7 +189,7 @@ def test_finish_upload_with_bad_chunks(self):
188189
'chunks': [{'size': 50}, {'size': 50}]
189190
}
190191
fop = FileUploadOperations(data_service, MagicMock())
191-
with self.assertRaises(ValueError) as raised_exception:
192+
with self.assertRaises(DDSUserException) as raised_exception:
192193
fop.finish_upload(upload_id="123",
193194
hash_data=MagicMock(),
194195
parent_data=MagicMock(),

ddsc/core/tests/test_moveutil.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import absolute_import
22
from unittest import TestCase
33
from ddsc.core.moveutil import MoveUtil, KindType
4+
from ddsc.exceptions import DDSUserException
45
from mock import Mock
56

67

@@ -49,7 +50,7 @@ def test_get_new_parent__target_is_file(self):
4950
move_util.is_folder_or_project.return_value = False
5051
mock_folder = Mock()
5152
mock_project.try_get_item_for_path.return_value = mock_folder
52-
with self.assertRaises(ValueError) as raised_exception:
53+
with self.assertRaises(DDSUserException) as raised_exception:
5354
move_util.get_new_parent()
5455
self.assertEqual(str(raised_exception.exception), 'Cannot move to existing file data/file2.txt.')
5556

@@ -79,7 +80,7 @@ def test_get_new_parent__target_parent_file(self):
7980
None,
8081
mock_parent_folder
8182
]
82-
with self.assertRaises(ValueError) as raised_exception:
83+
with self.assertRaises(DDSUserException) as raised_exception:
8384
move_util.get_new_parent()
8485
self.assertEqual(str(raised_exception.exception), 'Target parent /data2/file1.txt is a file.')
8586

@@ -90,7 +91,7 @@ def test_get_new_parent__target_parent_not_found(self):
9091
None,
9192
None
9293
]
93-
with self.assertRaises(ValueError) as raised_exception:
94+
with self.assertRaises(DDSUserException) as raised_exception:
9495
move_util.get_new_parent()
9596
self.assertEqual(str(raised_exception.exception), 'Target parent directory /data2 does not exist.')
9697

ddsc/core/tests/test_remotestore.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from ddsc.core.remotestore import RemoteAuthProvider
1111
from ddsc.core.remotestore import ProjectNameOrId
1212
from ddsc.core.remotestore import ProjectFile, RemoteFileUrl
13+
from ddsc.exceptions import DDSUserException
1314

1415

1516
class TestProjectFolderFile(TestCase):
@@ -664,7 +665,7 @@ def test_get_or_register_user_by_email__unable_to_find_user(self, mock_remote_us
664665
mock_user_util.return_value.find_affiliate_by_email.return_value = None
665666

666667
remote_store = RemoteStore(config=MagicMock())
667-
with self.assertRaises(ValueError) as raised_exception:
668+
with self.assertRaises(DDSUserException) as raised_exception:
668669
remote_store.get_or_register_user_by_email("user@user.user")
669670
self.assertEqual(str(raised_exception.exception), 'Unable to find or register a user with email user@user.user')
670671
mock_util = mock_user_util.return_value

0 commit comments

Comments
 (0)