Skip to content

Commit

Permalink
Merge pull request #25 from fieldse/master
Browse files Browse the repository at this point in the history
Merge fixes
  • Loading branch information
sibblegp authored Nov 2, 2018
2 parents 1cf9a60 + cbb9187 commit 5976bde
Show file tree
Hide file tree
Showing 15 changed files with 780 additions and 264 deletions.
24 changes: 22 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,13 +162,33 @@ save_file.write(downloaded_file.read())
save_file.close()
```

#### Delete a file
#### Delete a file version

```python
file.delete()
```

NOTE: There is no confirmation and this will delete all of a file's versions.
This deletes a single version of a file. (See the [docs on File Versions](https://www.backblaze.com/b2/docs/b2_delete_file_version.html) at Backblaze for explanation)

#### Hide (aka "Soft-delete") a file

```python
file.hide()
```

This hides a file (aka "soft-delete") so that downloading by name will not find the file, but previous versions of the file are still stored. (See the [docs on Hiding file](https://www.backblaze.com/b2/docs/b2_hide_file.html) at Backblaze for details)

## Testing

Unit testing with pytest
Before running, you must set the environment variables: `B2_KEY_ID` and `B2_APPLICATION_KEY`

** Run tests **

``` bash
python3 ./tests.py
```


## LICENSE

Expand Down
3 changes: 2 additions & 1 deletion b2blaze/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from b2blaze.b2lib import B2
from b2blaze.b2lib import B2
from .api import API_VERSION, BASE_URL, API
22 changes: 22 additions & 0 deletions b2blaze/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# api.py
# BackBlaze API endpoints

API_VERSION = '/b2api/v2'
BASE_URL = 'https://api.backblazeb2.com' + API_VERSION


class API():
authorize = '/b2_authorize_account'
delete_file = '/b2_hide_file'
delete_file_version = '/b2_delete_file_version'
file_info = '/b2_get_file_info'
download_file_by_id = '/b2_download_file_by_id'
list_all_files = '/b2_list_file_names'
list_file_versions = '/b2_list_file_versions'
upload_url = '/b2_get_upload_url'
upload_large = '/b2_start_large_file'
upload_large_part = '/b2_get_upload_part_url'
upload_large_finish = '/b2_finish_large_file'
create_bucket = '/b2_create_bucket'
delete_bucket = '/b2_delete_bucket'
list_all_buckets = '/b2_list_buckets'
109 changes: 86 additions & 23 deletions b2blaze/b2_exceptions.py
Original file line number Diff line number Diff line change
@@ -1,53 +1,116 @@
"""
Copyright George Sibble 2018
"""
class B2ApplicationKeyNotSet(Exception):
"""

"""
import json


class B2ApplicationKeyNotSet(Exception):
""" You must set the B2_KEY_ID environment variable before running the application """
pass


class B2KeyIDNotSet(Exception):
"""
""" You must set the B2_APPLICATION_KEY environment variable before running the application """
pass

"""

class B2Exception(Exception):
""" Base exception class for the Backblaze API """

@staticmethod
def parse(response):
""" Parse the response error code and return the related error type. """

API_EXCEPTION_CODES = {
400 : B2RequestError,
401 : B2UnauthorizedError,
403 : B2ForbiddenError,
404 : B2FileNotFoundError,
408 : B2RequestTimeoutError,
429 : B2TooManyRequestsError,
500 : B2InternalError,
503 : B2ServiceUnavailableError,
}

try:
response_json = response.json()
message = response_json['message']
code = response_json['code']
status = int(response_json['status'])

# Return B2Exception if unrecognized status code
if not status in API_EXCEPTION_CODES:
return B2Exception('{} - {}: {}'.format(status, code, message))

ErrorClass = API_EXCEPTION_CODES[status]
return ErrorClass('{} - {}: {}'.format(status, code, message))

except:
return Exception('error parsing response. status code - {} Response JSON: {}'.format(response.status_code, response_json) )

class B2FileNotFoundError(Exception):
""" 404 Not Found """
pass

class B2InvalidBucketName(Exception):
"""

"""
class B2RequestError(Exception):
""" There is a problem with a passed in request parameters. See returned message for details """
pass

class B2InvalidBucketConfiguration(Exception):
"""

class B2UnauthorizedError(Exception):
""" When calling b2_authorize_account, this means that there was something wrong with the accountId/applicationKeyId or with the applicationKey that was provided. The code unauthorized means that the application key is bad. The code unsupported means that the application key is only valid in a later version of the API.
The code unauthorized means that the auth token is valid, but does not allow you to make this call with these parameters. When the code is either bad_auth_token or expired_auth_token you should call b2_authorize_account again to get a new auth token.
"""
pass

class B2AuthorizationError(Exception):
"""

class B2ForbiddenError(Exception):
""" You have a reached a storage cap limit, or account access may be impacted in some other way; see the human-readable message.
"""
pass

class B2BucketCreationError(Exception):
"""

"""
class B2RequestTimeoutError(Exception):
""" The service timed out trying to read your request. """
pass

class B2RequestError(Exception):
"""
class B2OutOfRangeError(Exception):
""" The Range header in the request is outside the size of the file.. """
pass

"""

class B2InvalidRequestType(Exception):
"""
class B2TooManyRequestsError(Exception):
""" B2 may limit API requests on a per-account basis. """
pass

"""

class B2FileNotFound(Exception):
class B2InternalError(Exception):
""" An unexpected error has occurred. """
pass


class B2ServiceUnavailableError(Exception):
""" The service is temporarily unavailable. The human-readable message identifies the nature of the issue, in general we recommend retrying with an exponential backoff between retries in response to this error.
"""
pass


"""
class B2InvalidBucketName(Exception):
""" Bucket name must be alphanumeric or '-' """
pass


class B2InvalidBucketConfiguration(Exception):
""" Value error in bucket configuration """
pass

class B2AuthorizationError(Exception):
""" An error with the authorization request """
pass

class B2InvalidRequestType(Exception):
""" Request type must be get or post """
pass
4 changes: 1 addition & 3 deletions b2blaze/b2lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
Copyright George Sibble 2018
"""
import os
from b2blaze.b2_exceptions import B2ApplicationKeyNotSet, B2KeyIDNotSet, B2InvalidBucketName, B2InvalidBucketConfiguration
from b2blaze.b2_exceptions import B2BucketCreationError
from b2blaze.b2_exceptions import B2ApplicationKeyNotSet, B2KeyIDNotSet
from b2blaze.connector import B2Connector

from b2blaze.models.bucket_list import B2Buckets

class B2(object):
Expand Down
18 changes: 9 additions & 9 deletions b2blaze/connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@
import requests
import datetime
from requests.auth import HTTPBasicAuth
from b2blaze.b2_exceptions import B2AuthorizationError, B2RequestError, B2InvalidRequestType
from b2blaze.b2_exceptions import B2Exception, B2AuthorizationError, B2InvalidRequestType
import sys
from hashlib import sha1
from b2blaze.utilities import b2_url_encode, decode_error, get_content_length, StreamWithHashProgress
from .api import BASE_URL, API_VERSION, API

class B2Connector(object):
"""
"""
auth_url = 'https://api.backblazeb2.com/b2api/v1'

def __init__(self, key_id, application_key):
"""
Expand Down Expand Up @@ -53,22 +52,23 @@ def _authorize(self):
:return:
"""
path = self.auth_url + '/b2_authorize_account'
path = BASE_URL + API.authorize

result = requests.get(path, auth=HTTPBasicAuth(self.key_id, self.application_key))
if result.status_code == 200:
result_json = result.json()
self.authorized_at = datetime.datetime.utcnow()
self.account_id = result_json['accountId']
self.auth_token = result_json['authorizationToken']
self.api_url = result_json['apiUrl'] + '/b2api/v1'
self.download_url = result_json['downloadUrl'] + '/file/'
self.api_url = result_json['apiUrl'] + API_VERSION
self.download_url = result_json['downloadUrl'] + API_VERSION + API.download_file_by_id
self.recommended_part_size = result_json['recommendedPartSize']
self.api_session = requests.Session()
self.api_session.headers.update({
'Authorization': self.auth_token
})
else:
raise B2AuthorizationError(decode_error(result))
raise B2Exception.parse(result)


def make_request(self, path, method='get', headers={}, params={}, account_id_required=False):
Expand Down Expand Up @@ -164,13 +164,13 @@ def download_file(self, file_id):
:param file_id:
:return:
"""
download_by_id_url = self.download_url.split('file/')[0] + '/b2api/v1/b2_download_file_by_id'
url = self.download_url
params = {
'fileId': file_id
}
headers = {
'Authorization': self.auth_token
}

return requests.get(download_by_id_url, headers=headers, params=params)
return requests.get(url, headers=headers, params=params)

Loading

0 comments on commit 5976bde

Please sign in to comment.