Skip to content
This repository was archived by the owner on Jul 19, 2024. It is now read-only.

Commit cf7febe

Browse files
committed
Exposed progress block size and auto token refresh
1 parent 5ac291e commit cf7febe

20 files changed

+338
-182
lines changed

CHANGES.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1+
v0.5.1, 2015-07-09 - Added auto-refresh for unattended tokens
2+
- Exposed configuration of block size to vary upload and download callback frequency
3+
- Progress callbacks now take 3 arguments, the percent commplete (float), the bytes transferred (float),
4+
and the total bytes to be transferred (float).
5+
16
v0.5.0, 2015-07-01 - Removed 3 instance minimum for pool creation.
27
- Added progress callbacks from file upload and download.
8+
39
v0.4.0, 2015-05-11 - Added optional auth config validation flag.
410
- Added JobSubmission.settings attribute
511
- Fixed error in SessionExpiredException.

LICENSE.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
The Azure Batch Apps Python Client ver. 0.5.0 (azure-batch-apps-python)
2+
The Azure Batch Apps Python Client ver. 0.5.1 (azure-batch-apps-python)
33

44
Copyright (c) Microsoft Corporation
55
All rights reserved.

README.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ Release History
4545

4646
For full summary of changes, see CHANGES.txt
4747

48+
* 2015-07-09 - 0.5.1
49+
- Added auto-refresh for unattended tokens
50+
- Exposed configuration of block size to vary upload and download callback frequency
4851
* 2015-07-01 - 0.5.0
4952
- Added progress callbacks for file upload and download
5053
- Removed 3 instance minimum for pool creation
@@ -56,8 +59,8 @@ For full summary of changes, see CHANGES.txt
5659
* 2014-11-26 - 0.2.0
5760
- Changed file upload format
5861
- Changed Authentication config format
59-
- Changed terminology regarding application jobtype
60-
- Changed terminology regarding service principal unattended account
62+
- Changed terminology: application to jobtype
63+
- Changed terminology: service principal to unattended account
6164
- Added FileCollection.index method
6265
- Added better handling for missing auth values in Configuration
6366
* 2014-11-03 - 0.1.1

batchapps/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,5 @@
4646
"config"]
4747

4848

49-
__version__ = "0.5.0"
49+
__version__ = "0.5.1"
5050
__author__ = 'Microsoft Corp. <[email protected]>'

batchapps/api.py

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,8 @@ def get_output(self,
437437
job_id=None,
438438
otype='output',
439439
url=None,
440-
callback=None):
440+
callback=None,
441+
block=1024):
441442
"""
442443
Gets the content of the job output or its thumbnail.
443444
Either ``url``, or both ``job_id`` and ``otype`` must be set.
@@ -461,8 +462,10 @@ def get_output(self,
461462
supplied, ``job_id`` and ``otype`` will not be used.
462463
The default is None.
463464
- callback (func): A function to be called to report download progress.
464-
The function takes a single parameter, the percent downloaded as a
465-
float.
465+
The function takes three parameters: the percent downloaded (float), the
466+
bytes downloaded (float), and the total bytes to be downloaded (float).
467+
- block (int): The amount of data downloaded in each block - determines
468+
the frequency with which the callback is called. Default is 1024.
466469
467470
:Returns:
468471
- :class:`.Response` with the GET response, however this is not
@@ -474,14 +477,15 @@ def get_output(self,
474477
"""
475478
self._log.debug(
476479
"get_output, download_dir={dd}, size={sz}, fname={fn}, "
477-
"overwrite={ow}, job_id={ji}, url={ur}, otype={ot}".format(
480+
"overwrite={ow}, job_id={ji}, url={ur}, otype={ot}, block={bl}".format(
478481
dd=download_dir,
479482
sz=size,
480483
fn=fname,
481484
ow=overwrite,
482485
ji=job_id,
483486
ur=url,
484-
ot=otype))
487+
ot=otype,
488+
bl=block))
485489

486490
if not url and job_id:
487491
if otype.lower() not in ['output', 'preview']:
@@ -510,6 +514,7 @@ def get_output(self,
510514
size,
511515
overwrite,
512516
f_name=fname,
517+
block_size=block,
513518
callback=callback)
514519

515520
except RestCallException as exp:
@@ -621,7 +626,8 @@ def get_output_file(self,
621626
job_id=None,
622627
fname=None,
623628
url=None,
624-
callback=None):
629+
callback=None,
630+
block=1024):
625631
"""
626632
Gets the content of a file created in a job.
627633
Either ``url``, or both ``job_id`` and ``fname`` must be set.
@@ -642,8 +648,10 @@ def get_output_file(self,
642648
- url (str): The URL directly to the file to be downloaded.
643649
The default is None.
644650
- callback (func): A function to be called to report download progress.
645-
The function takes a single parameter, the percent downloaded as a
646-
float.
651+
The function takes three parameters: the percent downloaded (float), the
652+
bytes downloaded (float), and the total bytes to be downloaded (float).
653+
- block (int): The amount of data downloaded in each block - determines
654+
the frequency with which the callback is called. Default is 1024.
647655
648656
:Returns:
649657
- :class:`.Response` with the GET response, however this is not
@@ -655,12 +663,13 @@ def get_output_file(self,
655663
"""
656664
self._log.debug("get_output_file, download_dir={dd}, size={sz}, "
657665
"overwrite={ow}, job_id={ji}, fname={fn}, "
658-
"url={ur}".format(dd=download_dir,
666+
"url={ur}, block={bl}".format(dd=download_dir,
659667
sz=size,
660668
ow=overwrite,
661669
ji=job_id,
662670
fn=fname,
663-
ur=url))
671+
ur=url,
672+
bl=block))
664673

665674
name = fname if fname else None
666675

@@ -683,6 +692,7 @@ def get_output_file(self,
683692
download_dir,
684693
size, overwrite,
685694
f_name=name,
695+
block_size=block,
686696
callback=callback)
687697

688698
except RestCallException as exp:
@@ -1013,7 +1023,8 @@ def query_missing_files(self, files):
10131023
return Response(True, resp['files'])
10141024

10151025

1016-
def get_file(self, userfile, size, download_dir, overwrite=False, callback=None):
1026+
def get_file(self, userfile, size, download_dir, overwrite=False,
1027+
callback=None, block=1024):
10171028
"""Gets the content of a file previously uploaded by the user.
10181029
10191030
:Args:
@@ -1029,8 +1040,10 @@ def get_file(self, userfile, size, download_dir, overwrite=False, callback=None)
10291040
- overwrite (bool): Whether to overwrite a destination file if it
10301041
already exists. The default is ``False``.
10311042
- callback (func): A function to be called to report download progress.
1032-
The function takes a single parameter, the percent downloaded as a
1033-
float.
1043+
The function takes three parameters: the percent downloaded (float), the
1044+
bytes downloaded (float), and the total bytes to be downloaded (float).
1045+
- block (int): The amount of data downloaded in each block - determines
1046+
the frequency with which the callback is called. Default is 1024.
10341047
10351048
:Returns:
10361049
- :class:`.Response` with the GET response, however this is not
@@ -1044,10 +1057,11 @@ def get_file(self, userfile, size, download_dir, overwrite=False, callback=None)
10441057
None))
10451058

10461059
self._log.debug("get_file, file={0}, size={1}, "
1047-
"download_dir={2}, overwrite={3}".format(userfile,
1048-
size,
1049-
download_dir,
1050-
overwrite))
1060+
"download_dir={2}, overwrite={3}, block={4}".format(userfile,
1061+
size,
1062+
download_dir,
1063+
overwrite,
1064+
block))
10511065
url = userfile.url
10521066
self._log.debug("Get file url: {0}".format(url))
10531067
try:
@@ -1057,6 +1071,7 @@ def get_file(self, userfile, size, download_dir, overwrite=False, callback=None)
10571071
download_dir,
10581072
size,
10591073
overwrite=overwrite,
1074+
block_size=block,
10601075
callback=callback)
10611076

10621077
except RestCallException as exp:
@@ -1098,7 +1113,7 @@ def props_file(self, userfile):
10981113
else:
10991114
return Response(True, head_resp)
11001115

1101-
def send_file(self, userfile, callback=None):
1116+
def send_file(self, userfile, callback=None, block=1024):
11021117
"""Uploads a user file for use in a job.
11031118
11041119
:Args:
@@ -1108,8 +1123,10 @@ def send_file(self, userfile, callback=None):
11081123
11091124
:Kwargs:
11101125
- callback (func): A function to be called to report upload progress.
1111-
The function takes a single parameter, the percent uploaded as a
1112-
float.
1126+
The function takes three parameters: the percent uploaded (float), the
1127+
bytes uploaded (float), and the total bytes to be uploaded (float).
1128+
- block (int): The amount of data uploaded in each block - determines
1129+
the frequency with which the callback is called. Default is 1024.
11131130
11141131
:Returns:
11151132
- :class:`.Response` with the PUT response, however this is not
@@ -1140,6 +1157,7 @@ def send_file(self, userfile, callback=None):
11401157
self.headers,
11411158
userfile,
11421159
params,
1160+
block_size=block,
11431161
callback=callback)
11441162

11451163
except (RestCallException, FileMissingException) as exp:

batchapps/credentials.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ def __init__(self, config, client_id, token=None):
409409

410410
self._log = logging.getLogger('batch_apps')
411411
self._id = str(client_id)
412+
self._cfg = config
412413

413414
if not hasattr(config, "aad_config"):
414415
raise InvalidConfigException(
@@ -418,12 +419,12 @@ def __init__(self, config, client_id, token=None):
418419
self._log.debug("No token supplied, attempting to "
419420
"retrieve previous session.")
420421

421-
self.cfg = config.aad_config(unattended=False)
422+
self.auth = config.aad_config(unattended=False)
422423
token = self.get_stored_auth()
423424

424425
else:
425426
unattended = 'refresh_token' not in token
426-
self.cfg = config.aad_config(unattended=unattended)
427+
self.auth = config.aad_config(unattended=unattended)
427428

428429
self.token = token
429430

@@ -444,7 +445,7 @@ def get_session(self):
444445
- :class:`.AuthenticationException` if the token is invalid
445446
or expired.
446447
"""
447-
resource = _https(self.cfg['resource']) #DEP
448+
resource = _https(self.auth['resource']) #DEP
448449
countdown = float(self.token['expires_at']) - time.time()
449450

450451
self.token['expires_in'] = countdown
@@ -453,8 +454,8 @@ def get_session(self):
453454
try:
454455
if 'refresh_token' in self.token:
455456

456-
refresh = _https(self.cfg['root'], self.cfg['tenant'],
457-
self.cfg['token_uri'])
457+
refresh = _https(self.auth['root'], self.auth['tenant'],
458+
self.auth['token_uri'])
458459

459460
new_session = requests_oauthlib.OAuth2Session(
460461
self._id,
@@ -481,6 +482,26 @@ def get_session(self):
481482
new_session.verify = CA_CERT
482483
return new_session
483484

485+
def refresh_session(self):
486+
"""Refresh unattended token
487+
488+
:Returns:
489+
- An authenticated :class:`requests_oauthlib.OAuth2Session` if
490+
refreshed, else `None`.
491+
492+
"""
493+
unattended = 'refresh_token' not in self.token
494+
if unattended:
495+
try:
496+
creds = AzureOAuth.get_unattended_session(self._cfg)
497+
self.token = creds.token
498+
return self.get_session()
499+
500+
except (AuthenticationException, InvalidConfigException) as exp:
501+
self._log.warning("Failed to refresh unattended token: {0}".format(exp))
502+
503+
return None
504+
484505
def get_stored_auth(self):
485506
"""Retrieve a previously stored access token for refreshing
486507

0 commit comments

Comments
 (0)