0
# Utilities and Exceptions
1
2
Utility functions for path handling, file operations, and custom exception classes for comprehensive error handling in OSFClient operations.
3
4
## Capabilities
5
6
### Path Utilities
7
8
Functions for handling and normalizing file paths in OSF storage systems.
9
10
```python { .api }
11
def norm_remote_path(path):
12
"""
13
Normalize remote file path.
14
15
All remote paths are treated as absolute paths. Removes leading
16
slash and normalizes path separators.
17
18
Args:
19
path (str): File or directory path
20
21
Returns:
22
str: Normalized path without leading slash
23
"""
24
25
def split_storage(path, default='osfstorage'):
26
"""
27
Extract storage provider name from file path.
28
29
If path begins with a known storage provider, the provider name
30
is removed from the path. Otherwise returns the default provider
31
and leaves path unchanged.
32
33
Args:
34
path (str): File path that may include storage provider prefix
35
default (str): Default storage provider if none found in path
36
37
Returns:
38
tuple: (provider_name, remaining_path)
39
40
Examples:
41
split_storage('github/README.md') -> ('github', 'README.md')
42
split_storage('data/file.txt') -> ('osfstorage', 'data/file.txt')
43
"""
44
```
45
46
### File Operations
47
48
Utility functions for file system operations and file analysis.
49
50
```python { .api }
51
def makedirs(path, mode=511, exist_ok=False):
52
"""
53
Create directory and any necessary parent directories.
54
55
Cross-platform wrapper around os.makedirs with Python 2/3 compatibility.
56
57
Args:
58
path (str): Directory path to create
59
mode (int): Directory permissions (default: 0o777)
60
exist_ok (bool): Don't raise exception if directory already exists
61
62
Returns:
63
None
64
65
Note:
66
Mode 511 is decimal for octal 0o777 (full permissions)
67
"""
68
69
def file_empty(fp):
70
"""
71
Determine if a file is empty.
72
73
Args:
74
fp (file): File pointer opened for reading
75
76
Returns:
77
bool: True if file is empty, False otherwise
78
79
Note:
80
File pointer position is reset to beginning after check.
81
"""
82
83
def get_local_file_size(fp):
84
"""
85
Get file size from file pointer.
86
87
Args:
88
fp (file): File pointer
89
90
Returns:
91
int: File size in bytes
92
"""
93
```
94
95
### Cryptographic Utilities
96
97
Functions for calculating file checksums and hash verification.
98
99
```python { .api }
100
def checksum(file_path, hash_type='md5', block_size=65536):
101
"""
102
Calculate hash of a file.
103
104
Args:
105
file_path (str): Path to file to hash
106
hash_type (str): Hash algorithm ('md5' or 'sha256')
107
block_size (int): Size of blocks to read (default: 64KB)
108
109
Returns:
110
str: Hexadecimal hash digest
111
112
Raises:
113
ValueError: If hash_type is not 'md5' or 'sha256'
114
115
Note:
116
MD5 is faster than SHA256 and is the default for compatibility
117
with OSF's hash storage format.
118
"""
119
```
120
121
### Storage Provider Constants
122
123
```python { .api }
124
KNOWN_PROVIDERS = ['osfstorage', 'github', 'figshare', 'googledrive', 'owncloud']
125
```
126
127
List of storage providers supported by OSFClient. Used by `split_storage()` to recognize provider prefixes in file paths.
128
129
## Exception Classes
130
131
Custom exception hierarchy for OSF-specific error handling.
132
133
```python { .api }
134
class OSFException(Exception):
135
"""
136
Base exception class for all OSF-related errors.
137
138
Inherits from built-in Exception class. All other OSF exceptions
139
inherit from this class.
140
"""
141
142
class UnauthorizedException(OSFException):
143
"""
144
Raised when authentication fails or access is denied.
145
146
Typically occurs when:
147
- Invalid credentials provided
148
- Token has expired or been revoked
149
- Attempting to access private resources without authentication
150
- Insufficient permissions for requested operation
151
"""
152
153
class FolderExistsException(OSFException):
154
"""
155
Raised when attempting to create a folder that already exists.
156
157
Args:
158
name (str): Name of the folder that already exists
159
160
Attributes:
161
args (tuple): Contains error message with folder name
162
"""
163
```
164
165
## Usage Examples
166
167
### Path Handling
168
169
```python
170
from osfclient.utils import norm_remote_path, split_storage
171
172
# Normalize paths
173
path1 = norm_remote_path('/data/file.txt')
174
print(path1) # 'data/file.txt'
175
176
path2 = norm_remote_path('folder/subfolder/file.txt')
177
print(path2) # 'folder/subfolder/file.txt'
178
179
# Split storage providers from paths
180
provider, path = split_storage('github/README.md')
181
print(f"Provider: {provider}, Path: {path}") # Provider: github, Path: README.md
182
183
provider, path = split_storage('data/analysis.csv')
184
print(f"Provider: {provider}, Path: {path}") # Provider: osfstorage, Path: data/analysis.csv
185
186
# Custom default provider
187
provider, path = split_storage('data/file.txt', default='figshare')
188
print(f"Provider: {provider}, Path: {path}") # Provider: figshare, Path: data/file.txt
189
```
190
191
### File Operations
192
193
```python
194
from osfclient.utils import makedirs, file_empty, get_local_file_size
195
import os
196
197
# Create directories safely
198
makedirs('/path/to/new/directory', exist_ok=True)
199
200
# Check if file is empty before processing
201
with open('data.txt', 'rb') as f:
202
if file_empty(f):
203
print("File is empty, skipping processing")
204
else:
205
print(f"File size: {get_local_file_size(f)} bytes")
206
# Process file content
207
```
208
209
### Checksum Verification
210
211
```python
212
from osfclient.utils import checksum
213
214
# Calculate MD5 hash (default)
215
md5_hash = checksum('/path/to/file.txt')
216
print(f"MD5: {md5_hash}")
217
218
# Calculate SHA256 hash
219
sha256_hash = checksum('/path/to/file.txt', hash_type='sha256')
220
print(f"SHA256: {sha256_hash}")
221
222
# Custom block size for large files
223
large_file_hash = checksum('/path/to/large_file.bin', block_size=1024*1024) # 1MB blocks
224
225
# Verify file integrity
226
expected_hash = 'a1b2c3d4e5f6...'
227
actual_hash = checksum('downloaded_file.txt')
228
if actual_hash == expected_hash:
229
print("File integrity verified")
230
else:
231
print("File may be corrupted")
232
```
233
234
### Exception Handling
235
236
```python
237
from osfclient import OSF
238
from osfclient.exceptions import OSFException, UnauthorizedException, FolderExistsException
239
240
try:
241
# Authentication
242
osf = OSF(username='invalid', password='invalid')
243
if not osf.can_login:
244
raise UnauthorizedException("Invalid credentials")
245
246
# Project access
247
project = osf.project('invalid_project_id')
248
249
except UnauthorizedException as e:
250
print(f"Authentication error: {e}")
251
# Prompt for new credentials or use token auth
252
253
except OSFException as e:
254
print(f"OSF API error: {e}")
255
# Handle general OSF errors
256
257
except Exception as e:
258
print(f"Unexpected error: {e}")
259
260
try:
261
# Folder creation
262
storage = project.storage()
263
new_folder = storage.create_folder('analysis_results')
264
265
except FolderExistsException as e:
266
print(f"Folder already exists: {e}")
267
# Use exist_ok=True to avoid this exception
268
existing_folder = storage.create_folder('analysis_results', exist_ok=True)
269
270
except OSFException as e:
271
print(f"Failed to create folder: {e}")
272
```
273
274
### Advanced Usage
275
276
```python
277
from osfclient.utils import KNOWN_PROVIDERS
278
279
# Check if storage provider is supported
280
def is_supported_provider(provider_name):
281
return provider_name in KNOWN_PROVIDERS
282
283
# Validate storage path format
284
def validate_storage_path(path):
285
provider, clean_path = split_storage(path)
286
if provider not in KNOWN_PROVIDERS:
287
raise ValueError(f"Unsupported storage provider: {provider}")
288
return provider, norm_remote_path(clean_path)
289
290
# Usage
291
try:
292
provider, path = validate_storage_path('github/docs/README.md')
293
print(f"Valid path - Provider: {provider}, Path: {path}")
294
except ValueError as e:
295
print(f"Invalid path: {e}")
296
```
297
298
### Cross-Platform File Operations
299
300
```python
301
import os
302
from osfclient.utils import makedirs
303
304
# Create nested directory structure safely
305
base_path = os.path.expanduser('~/osf_projects')
306
project_path = os.path.join(base_path, 'project_123', 'data', 'raw')
307
308
# This works on Windows, macOS, and Linux
309
makedirs(project_path, exist_ok=True)
310
311
# Now safe to create files in the directory
312
file_path = os.path.join(project_path, 'experiment.csv')
313
with open(file_path, 'w') as f:
314
f.write('data,goes,here\n')
315
```