0
# Python API
1
2
Core Python library functionality for programmatic access to OSF projects. The main entry point is the OSF class, which provides authentication and project access capabilities.
3
4
## Capabilities
5
6
### OSF Client Class
7
8
Main client class for interacting with the Open Science Framework. Handles authentication and provides access to projects.
9
10
```python { .api }
11
class OSF:
12
def __init__(self, username=None, password=None, token=None):
13
"""
14
Initialize OSF client with optional authentication.
15
16
Args:
17
username (str, optional): OSF username for basic authentication
18
password (str, optional): OSF password for basic authentication
19
token (str, optional): Personal Access Token for token authentication
20
21
Note:
22
Authentication is attempted during initialization. If it fails,
23
can_login property will be False but the client can still be used
24
for public projects.
25
"""
26
27
def login(self, username=None, password=None, token=None):
28
"""
29
Authenticate user for protected API calls.
30
31
Args:
32
username (str, optional): OSF username
33
password (str, optional): OSF password
34
token (str, optional): Personal Access Token
35
36
Raises:
37
OSFException: If no login details provided
38
39
Note:
40
Token authentication takes precedence over username/password if both provided.
41
"""
42
43
def project(self, project_id):
44
"""
45
Fetch project by project ID.
46
47
Args:
48
project_id (str): OSF project ID (GUID)
49
50
Returns:
51
Project: Project instance
52
53
Raises:
54
OSFException: If project ID is unrecognized type or not accessible
55
"""
56
57
def guid(self, guid):
58
"""
59
Determine JSONAPI type for provided GUID.
60
61
Args:
62
guid (str): OSF GUID
63
64
Returns:
65
str: JSONAPI type ('nodes', 'registrations', etc.)
66
"""
67
68
@property
69
def username(self):
70
"""
71
Get authenticated username.
72
73
Returns:
74
str or None: Username if using basic auth, None otherwise
75
"""
76
77
@property
78
def password(self):
79
"""
80
Get authenticated password.
81
82
Returns:
83
str or None: Password if using basic auth, None otherwise
84
"""
85
86
@property
87
def token(self):
88
"""
89
Get authentication token.
90
91
Returns:
92
str or None: Token if using token auth, None otherwise
93
"""
94
95
@property
96
def can_login(self):
97
"""
98
Check if authentication succeeded.
99
100
Returns:
101
bool: True if authentication was successful, False otherwise
102
"""
103
```
104
105
### Usage Examples
106
107
Basic authentication:
108
```python
109
from osfclient import OSF
110
111
# Token authentication (recommended)
112
osf = OSF(token='your_personal_access_token')
113
114
# Basic authentication
115
osf = OSF(username='user@example.com', password='password')
116
117
# Check if authentication worked
118
if osf.can_login:
119
print(f"Authenticated as: {osf.username or 'token user'}")
120
else:
121
print("Authentication failed, can only access public projects")
122
```
123
124
Working with projects:
125
```python
126
# Get a project
127
project_id = '9zpcy'
128
project = osf.project(project_id)
129
print(f"Project: {project.title}")
130
print(f"Description: {project.description}")
131
132
# Check project type
133
guid_type = osf.guid(project_id)
134
print(f"Project type: {guid_type}") # 'nodes' or 'registrations'
135
```
136
137
Environment-based authentication:
138
```python
139
import os
140
from osfclient import OSF
141
142
# Using environment variables
143
# Set OSF_TOKEN, OSF_USERNAME, OSF_PASSWORD environment variables
144
osf = OSF(
145
username=os.getenv('OSF_USERNAME'),
146
password=os.getenv('OSF_PASSWORD'),
147
token=os.getenv('OSF_TOKEN')
148
)
149
```
150
151
### Session Management
152
153
The OSF class uses OSFSession internally for HTTP operations with built-in rate limiting and authentication handling. OSFSession extends requests.Session with OSF-specific configuration.
154
155
```python { .api }
156
class OSFSession:
157
def __init__(self):
158
"""
159
Handle HTTP session related work with OSF-specific configuration.
160
161
Automatically configures OSF API headers and base URL.
162
Inherits from requests.Session for full HTTP functionality.
163
"""
164
165
def basic_auth(self, username, password):
166
"""
167
Configure basic authentication.
168
169
Args:
170
username (str): OSF username
171
password (str): OSF password
172
173
Note:
174
Removes any existing Authorization header and stores credentials
175
for HTTP basic authentication. Mutually exclusive with token auth.
176
"""
177
178
def token_auth(self, token):
179
"""
180
Configure token authentication.
181
182
Args:
183
token (str): Personal Access Token
184
185
Note:
186
Sets Authorization: Bearer header and stores token.
187
Takes precedence over basic authentication.
188
"""
189
190
def get(self, url, *args, **kwargs):
191
"""
192
Rate-limited GET request with automatic 401 error handling.
193
194
Args:
195
url (str): Request URL
196
*args, **kwargs: Passed to requests.Session.get()
197
198
Returns:
199
requests.Response: HTTP response object
200
201
Raises:
202
UnauthorizedException: If response status is 401
203
204
Note:
205
Rate limited to 1 request per second.
206
"""
207
208
def put(self, url, *args, **kwargs):
209
"""
210
Rate-limited PUT request with automatic 401 error handling.
211
212
Args:
213
url (str): Request URL
214
*args, **kwargs: Passed to requests.Session.put()
215
216
Returns:
217
requests.Response: HTTP response object
218
219
Raises:
220
UnauthorizedException: If response status is 401
221
222
Note:
223
Rate limited to 1 request per second.
224
"""
225
226
def patch(self, url, *args, **kwargs):
227
"""
228
PATCH request with automatic 401 error handling.
229
230
Args:
231
url (str): Request URL
232
*args, **kwargs: Passed to requests.Session.patch()
233
234
Returns:
235
requests.Response: HTTP response object
236
237
Raises:
238
UnauthorizedException: If response status is 401
239
"""
240
241
def delete(self, url, *args, **kwargs):
242
"""
243
DELETE request with automatic 401 error handling.
244
245
Args:
246
url (str): Request URL
247
*args, **kwargs: Passed to requests.Session.delete()
248
249
Returns:
250
requests.Response: HTTP response object
251
252
Raises:
253
UnauthorizedException: If response status is 401
254
"""
255
256
def build_url(self, *args):
257
"""
258
Build OSF API URLs with canonical trailing slash.
259
260
Args:
261
*args: URL path components
262
263
Returns:
264
str: Complete OSF API URL ending with '/'
265
266
Example:
267
build_url('nodes', 'abc123', 'files')
268
# Returns: 'https://api.osf.io/v2/nodes/abc123/files/'
269
"""
270
271
@property
272
def base_url(self):
273
"""
274
OSF API base URL.
275
276
Returns:
277
str: 'https://api.osf.io/v2/'
278
"""
279
280
@property
281
def auth(self):
282
"""
283
Basic authentication credentials.
284
285
Returns:
286
tuple or None: (username, password) if basic auth configured, None otherwise
287
"""
288
289
@property
290
def token(self):
291
"""
292
Authentication token.
293
294
Returns:
295
str or None: Personal Access Token if token auth configured, None otherwise
296
"""
297
298
@property
299
def last_request(self):
300
"""
301
Timestamp of last HTTP request for rate limiting.
302
303
Returns:
304
float or None: Unix timestamp of last request, None if no requests made
305
"""
306
307
@property
308
def headers(self):
309
"""
310
Default HTTP headers for OSF API requests.
311
312
Returns:
313
dict: Headers including Accept, Content-Type, User-Agent, and Authorization
314
315
Note:
316
Automatically configured with OSF-specific headers:
317
- Accept: application/vnd.api+json
318
- Accept-Charset: utf-8
319
- Content-Type: application/json
320
- User-Agent: osfclient v{version}
321
- Authorization: Bearer {token} (if token auth configured)
322
"""
323
```
324
325
Advanced session usage:
326
```python
327
from osfclient.models import OSFSession
328
from osfclient.exceptions import UnauthorizedException
329
330
# Custom session configuration
331
session = OSFSession()
332
session.token_auth('your_token')
333
334
# Build custom URLs
335
url = session.build_url('nodes', 'project_id', 'files')
336
# Returns: 'https://api.osf.io/v2/nodes/project_id/files/'
337
338
# Direct HTTP operations with rate limiting and error handling
339
try:
340
response = session.get(url)
341
data = response.json()
342
print(f"Found {len(data['data'])} files")
343
except UnauthorizedException:
344
print("Authentication required or token expired")
345
346
# Check session state
347
print(f"Using token auth: {session.token is not None}")
348
print(f"Using basic auth: {session.auth is not None}")
349
print(f"Base URL: {session.base_url}")
350
351
# Access default headers
352
headers = session.headers
353
print(f"User-Agent: {headers.get('User-Agent')}")
354
print(f"Accept: {headers.get('Accept')}")
355
```
356
357
### Rate Limiting and Error Handling
358
359
OSFSession implements automatic rate limiting (1 request per second) and consistent error handling:
360
361
```python
362
import time
363
from osfclient.models import OSFSession
364
365
session = OSFSession()
366
session.token_auth('your_token')
367
368
# Rate limiting example
369
start_time = time.time()
370
response1 = session.get('https://api.osf.io/v2/nodes/project_id/')
371
response2 = session.get('https://api.osf.io/v2/nodes/project_id/files/')
372
elapsed = time.time() - start_time
373
374
# Second request automatically delayed to respect rate limit
375
print(f"Two requests took {elapsed:.2f} seconds (min 1.0s due to rate limiting)")
376
377
# Automatic 401 error handling
378
try:
379
session.basic_auth('invalid', 'credentials')
380
response = session.get('https://api.osf.io/v2/nodes/private_project/')
381
except UnauthorizedException as e:
382
print(f"Authentication failed: {e}")
383
# Session automatically handles 401 responses
384
```