From 74939e07b4e11aeb208ebb94276f0d91aadb1a07 Mon Sep 17 00:00:00 2001 From: Richard O'Dwyer Date: Thu, 25 Jun 2020 21:16:12 +0100 Subject: [PATCH] lint --- HISTORY.md | 86 +++++++++++++++++ HISTORY.rst | 79 ---------------- MANIFEST.in | 6 +- README.md | 169 ++++++++++++++++++++++++++++++++++ README.rst | 204 ----------------------------------------- setup.py | 15 ++- src/mega/errors.py | 70 +++++--------- src/mega/mega.py | 27 +++--- src/tests/test_mega.py | 1 - 9 files changed, 305 insertions(+), 352 deletions(-) create mode 100644 HISTORY.md delete mode 100644 HISTORY.rst create mode 100644 README.md delete mode 100644 README.rst diff --git a/HISTORY.md b/HISTORY.md new file mode 100644 index 0000000..bb4ff7c --- /dev/null +++ b/HISTORY.md @@ -0,0 +1,86 @@ +Release History +=============== + +1.0.8 (unreleased) +------------------ + +- Fixes find method returning the wrong file when more than one file + exists with that name. +- Handle new shared file URLS. + +1.0.7 (2020-03-25) +------------------ + +- Fix login by calculating public RSA exponent instead of hardcoding. + +1.0.6 (2020-02-03) +------------------ + +- Fixes RSA public exponent issue. +- Switches dependency pycrypto to pycryptodome. + +1.0.5 (2019-11-18) +------------------ + +- Increase the wait time in between failed API request retries. + +1.0.4 (2019-11-18) +------------------ + +- Increase the wait time in between failed API request retries. + +1.0.3 (2019-11-12) +------------------ + +- Fixes broken `download` method. +- Changes `download` and `download_url` methods to return the path to + the downloaded file, previously returned `None`. +- Added LICENSE. + +1.0.2 (2019-11-07) +------------------ + +- Reverts, "Replace pycrypto dependency with pycryptodome" as breaks + login process. + +1.0.1 (2019-11-06) +------------------ + +- When a request fails due to EAGAIN response, retry with exp backoff + up to 20 seconds. +- Adds logging, removes print statements. +- Replace pycrypto dependency with pycryptodome. +- Removes Python 2 specific code. + +1.0.0 (2019-10-31) +------------------ + +- Removes broken method `get_contacts()`. +- Adds support for login with a v2 Mega user account. +- Adds `export()` method to share a file or folder, returning public + share URL with key. +- Adds code, message attrs to RequestError exception, makes message in + raised exceptions include more details. +- Alters `create_folder()` to accept a path including multiple sub + directories, adds support to create them all (similar to 'mkdir -p' + on unix systems). +- Adds `exclude_deleted=True` optional arg to `find()` method, to + exclude deleted nodes from results. + +0.9.20 (2019-10-17) +------------------- + +- Python 3 bugfix to `upload` method. + +0.9.19 (2019-10-16) +------------------- + +- Python 3 support and bugfixes. +- Update packaging code. +- Added changelog. + +0.9.18 (2013-07-04) +------------------- + +- Unknown + diff --git a/HISTORY.rst b/HISTORY.rst deleted file mode 100644 index 250c6b9..0000000 --- a/HISTORY.rst +++ /dev/null @@ -1,79 +0,0 @@ -.. :changelog: - -Release History -=============== - -1.0.7 (2020-03-25) ------------------- - -- Fix login by calculating public RSA exponent instead of hardcoding. - - -1.0.6 (2020-02-03) ------------------- - -- Fixes RSA public exponent issue. -- Switches dependency pycrypto to pycryptodome. - - -1.0.5 (2019-11-18) ------------------- - -- Increase the wait time in between failed API request retries. - - -1.0.4 (2019-11-18) ------------------- - -- Increase the wait time in between failed API request retries. - - -1.0.3 (2019-11-12) ------------------- - -- Fixes broken ``download`` method. -- Changes ``download`` and ``download_url`` methods to return the path to the downloaded file, previously returned ``None``. -- Added LICENSE. - - -1.0.2 (2019-11-07) ------------------- - -- Reverts, "Replace pycrypto dependency with pycryptodome" as breaks login process. - - -1.0.1 (2019-11-06) ------------------- - -- When a request fails due to EAGAIN response, retry with exp backoff up to 20 seconds. -- Adds logging, removes print statements. -- Replace pycrypto dependency with pycryptodome. -- Removes Python 2 specific code. - - -1.0.0 (2019-10-31) ------------------- - -- Removes broken method ``get_contacts()``. -- Adds support for login with a v2 Mega user account. -- Adds ``export()`` method to share a file or folder, returning public share URL with key. -- Adds code, message attrs to RequestError exception, makes message in raised exceptions include more details. -- Alters ``create_folder()`` to accept a path including multiple sub directories, adds support to create them all (similar to 'mkdir -p' on unix systems). -- Adds ``exclude_deleted=True`` optional arg to ``find()`` method, to exclude deleted nodes from results. - -0.9.20 (2019-10-17) -------------------- - -- Python 3 bugfix to ``upload`` method. - -0.9.19 (2019-10-16) -------------------- - -- Python 3 support and bugfixes. -- Update packaging code. -- Added changelog. - -0.9.18 (2013-07-04) -------------------- - -- Unknown diff --git a/MANIFEST.in b/MANIFEST.in index 22e548e..1c9d257 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,9 +1,9 @@ -include HISTORY.rst -include README.rst +include HISTORY.md +include README.md include requirements.txt recursive-include tests * recursive-exclude * __pycache__ recursive-exclude * *.py[co] -recursive-include docs *.rst conf.py Makefile make.bat +recursive-include docs *.md conf.py Makefile make.bat diff --git a/README.md b/README.md new file mode 100644 index 0000000..4c4a88c --- /dev/null +++ b/README.md @@ -0,0 +1,169 @@ +Mega.py +======= + +[![Build +Status](https://travis-ci.org/odwyersoftware/mega.py.png?branch=master)](https://travis-ci.org/odwyersoftware/mega.py) +[![Downloads](https://pypip.in/d/mega.py/badge.png)](https://crate.io/packages/mega.py/) [![PyPI version](https://badge.fury.io/py/mega.py.svg)](https://pypi.org/project/mega.py/) + +Python library for the [Mega.co.nz](https://mega.nz/aff=Zo6IxNaHw14) +API, currently supporting: + +- login +- uploading +- downloading +- deleting +- searching +- sharing +- renaming +- moving files + +This is a work in progress, further functionality coming shortly. + +For more detailed information see API\_INFO.md + +How To Use +---------- + +### Create a Mega account + +First, [create an account with Mega](https://mega.nz/aff=Zo6IxNaHw14) . + +### Install mega.py package + +Run the following command, or run setup from the latest github source. + +```python +pip install mega.py +``` + +### Import mega.py + +```python +from mega import Mega +``` + +### Create an instance of Mega.py + +```python +mega = Mega() +``` + +### Login to Mega + +```python +m = mega.login(email, password) +# login using a temporary anonymous account +m = mega.login() +``` + +### Get user details + +```python +details = m.get_user() +``` + +### Get account balance (Pro accounts only) + +```python +balance = m.get_balance() +``` + +### Get account disk quota + +```python +quota = m.get_quota() +``` + +### Get account storage space + +```python +# specify unit output kilo, mega, gig, else bytes will output +space = m.get_storage_space(kilo=True) +``` + +### Get account files + +```python +files = m.get_files() +``` + +### Upload a file, and get its public link + +```python +file = m.upload('myfile.doc') +m.get_upload_link(file) +# see mega.py for destination and filename options +``` + +### Export a file or folder + +```python +public_exported_web_link = m.export('myfile.doc') +public_exported_web_link = m.export('my_mega_folder/my_sub_folder_to_share') +# e.g. https://mega.nz/#F!WlVl1CbZ!M3wmhwZDENMNUJoBsdzFng +``` + +### Find a file or folder + +```python +folder = m.find('my_mega_folder') +# Excludes results which are in the Trash folder (i.e. deleted) +folder = m.find('my_mega_folder', exclude_deleted=True) +``` + +### Upload a file to a destination folder + +```python +folder = m.find('my_mega_folder') +m.upload('myfile.doc', folder[0]) +``` + +### Download a file from URL or file obj, optionally specify destination folder + +```python +file = m.find('myfile.doc') +m.download(file) +m.download_url('https://mega.co.nz/#!utYjgSTQ!OM4U3V5v_W4N5edSo0wolg1D5H0fwSrLD3oLnLuS9pc') +m.download(file, '/home/john-smith/Desktop') +# specify optional download filename (download_url() supports this also) +m.download(file, '/home/john-smith/Desktop', 'myfile.zip') +``` + +### Import a file from URL, optionally specify destination folder + +```python +m.import_public_url('https://mega.co.nz/#!utYjgSTQ!OM4U3V5v_W4N5edSo0wolg1D5H0fwSrLD3oLnLuS9pc') +folder_node = m.find('Documents')[1] +m.import_public_url('https://mega.co.nz/#!utYjgSTQ!OM4U3V5v_W4N5edSo0wolg1D5H0fwSrLD3oLnLuS9pc', dest_node=folder_node) +``` + +### Create a folder + +```python +m.create_folder('new_folder') +m.create_folder('new_folder/sub_folder/subsub_folder') +``` + +Returns a dict of folder node name and node\_id, e.g. + +```python +{ + 'new_folder': 'qpFhAYwA', + 'sub_folder': '2pdlmY4Z', + 'subsub_folder': 'GgMFCKLZ' +} +``` + +### Rename a file or a folder + +```python +file = m.find('myfile.doc') +m.rename(file, 'my_file.doc') +``` + +## Contact Support + +For paid priority support contact [mega@odwyer.software](mailto:mega@odwyer.software). +**[UK Python Development Agency](https://odwyer.software/)** + + diff --git a/README.rst b/README.rst deleted file mode 100644 index d679648..0000000 --- a/README.rst +++ /dev/null @@ -1,204 +0,0 @@ -**NOTICE**: If you're reading this on GitHub.com please be aware this is -a mirror of the primary remote located at https://code.richard.do/richardARPANET/mega.py_. Please direct issues and -pull requests there. - --------------- - -.. _megapy: - -Mega.py -======= - -|Build Status| |Downloads| - -Python library for the `Mega.co.nz `_ API, currently supporting: - -- login -- uploading -- downloading -- deleting -- searching -- sharing -- renaming -- moving files - -This is a work in progress, further functionality coming shortly. - -For more detailed information see API_INFO.md - -How To Use ----------- - -.. _create-mega-account: - -Create a Mega account -~~~~~~~~~~~~~~~~~~~~~~~ - -First, `create an account with Mega `_ -. - -.. _install-megapy-package: - -Install mega.py package -~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - Run the following command, or run setup from the latest github source - pip install mega.py - -.. _import-megapy: - -Import mega.py -~~~~~~~~~~~~~~ - -.. code:: python - - from mega import Mega - -.. _create-an-instance-of-megapy: - -Create an instance of Mega.py -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - mega = Mega() - -Login to Mega -~~~~~~~~~~~~~ - -.. code:: python - - m = mega.login(email, password) - # login using a temporary anonymous account - m = mega.login() - -Get user details -~~~~~~~~~~~~~~~~ - -.. code:: python - - details = m.get_user() - -Get account balance (Pro accounts only) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - balance = m.get_balance() - -Get account disk quota -~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - quota = m.get_quota() - -Get account storage space -~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - # specify unit output kilo, mega, gig, else bytes will output - space = m.get_storage_space(kilo=True) - -Get account files -~~~~~~~~~~~~~~~~~ - -.. code:: python - - files = m.get_files() - -Upload a file, and get its public link -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - file = m.upload('myfile.doc') - m.get_upload_link(file) - # see mega.py for destination and filename options - -Export a file or folder -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - public_exported_web_link = m.export('myfile.doc') - public_exported_web_link = m.export('my_mega_folder/my_sub_folder_to_share') - # e.g. https://mega.nz/#F!WlVl1CbZ!M3wmhwZDENMNUJoBsdzFng - -Find a file or folder -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - folder = m.find('my_mega_folder') - # Excludes results which are in the Trash folder (i.e. deleted) - folder = m.find('my_mega_folder', exclude_deleted=True) - -Upload a file to a destination folder -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - folder = m.find('my_mega_folder') - m.upload('myfile.doc', folder[0]) - -Download a file from URL or file obj, optionally specify destination folder -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - file = m.find('myfile.doc') - m.download(file) - m.download_url('https://mega.co.nz/#!utYjgSTQ!OM4U3V5v_W4N5edSo0wolg1D5H0fwSrLD3oLnLuS9pc') - m.download(file, '/home/john-smith/Desktop') - # specify optional download filename (download_url() supports this also) - m.download(file, '/home/john-smith/Desktop', 'myfile.zip') - -Import a file from URL, optionally specify destination folder -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - m.import_public_url('https://mega.co.nz/#!utYjgSTQ!OM4U3V5v_W4N5edSo0wolg1D5H0fwSrLD3oLnLuS9pc') - folder_node = m.find('Documents')[1] - m.import_public_url('https://mega.co.nz/#!utYjgSTQ!OM4U3V5v_W4N5edSo0wolg1D5H0fwSrLD3oLnLuS9pc', dest_node=folder_node) - -Create a folder -~~~~~~~~~~~~~~~ - -.. code:: python - - m.create_folder('new_folder') - m.create_folder('new_folder/sub_folder/subsub_folder') - -Returns a dict of folder node name and node_id, e.g. - -.. code:: python - - { - 'new_folder': 'qpFhAYwA', - 'sub_folder': '2pdlmY4Z', - 'subsub_folder': 'GgMFCKLZ' - } - -Rename a file or a folder -~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - file = m.find('myfile.doc') - m.rename(file, 'my_file.doc') - - -~ - -.. _`https://code.richard.do/richardARPANET/mega.py`: https://code.richard.do/richardARPANET/mega.py -.. _`https://github.com/meganz/sdk`: https://github.com/meganz/sdk - -.. |Build Status| image:: https://travis-ci.org/richardARPANET/mega.py.png?branch=master - :target: https://travis-ci.org/richardARPANET/mega.py -.. |Downloads| image:: https://pypip.in/d/mega.py/badge.png - :target: https://crate.io/packages/mega.py/ diff --git a/setup.py b/setup.py index a339e95..b607ce7 100644 --- a/setup.py +++ b/setup.py @@ -14,22 +14,24 @@ os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) with open('requirements.txt') as f: install_requires = f.read().splitlines() -with open('README.rst', 'r', encoding='utf-8') as rm_file: +with open('README.md', 'r', encoding='utf-8') as rm_file: readme = rm_file.read() -with open('HISTORY.rst', 'r', encoding='utf-8') as hist_file: +with open('HISTORY.md', 'r', encoding='utf-8') as hist_file: history = hist_file.read() setup(name='mega.py', - version='1.0.7', + version='1.0.8.dev0', packages=find_packages('src', exclude=('tests', )), package_dir={'': 'src'}, include_package_data=True, zip_safe=False, + url='https://github.com/odwyersoftware/mega.py', description='Python lib for the Mega.co.nz API', long_description=readme + '\n\n' + history, - author='Richard O\'Dwyer', - author_email='richard@richard.do', + long_description_content_type='text/markdown', + author='O\'Dwyer Software', + author_email='hello@odwyer.software', license='Creative Commons Attribution-Noncommercial-Share Alike license', install_requires=install_requires, classifiers=[ @@ -37,8 +39,5 @@ setup(name='mega.py', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', 'Topic :: Internet :: WWW/HTTP', ]) diff --git a/src/mega/errors.py b/src/mega/errors.py index bd24852..00332ae 100644 --- a/src/mega/errors.py +++ b/src/mega/errors.py @@ -6,61 +6,41 @@ class ValidationError(Exception): _CODE_TO_DESCRIPTIONS = { - -1: ( - 'EINTERNAL', ( - 'An internal error has occurred. Please submit a bug report, ' - 'detailing the exact circumstances in which this error occurred' - ) - ), + -1: ('EINTERNAL', + ('An internal error has occurred. Please submit a bug report, ' + 'detailing the exact circumstances in which this error occurred')), -2: ('EARGS', 'You have passed invalid arguments to this command'), - -3: ( - 'EAGAIN', ( - '(always at the request level) A temporary congestion or server ' - 'malfunction prevented your request from being processed. ' - 'No data was altered. Retry. Retries must be spaced with ' - 'exponential backoff' - ) - ), - -4: ( - 'ERATELIMIT', ( - 'You have exceeded your command weight per time quota. Please ' - 'wait a few seconds, then try again (this should never happen ' - 'in sane real-life applications)' - ) - ), + -3: ('EAGAIN', + ('(always at the request level) A temporary congestion or server ' + 'malfunction prevented your request from being processed. ' + 'No data was altered. Retry. Retries must be spaced with ' + 'exponential backoff')), + -4: ('ERATELIMIT', + ('You have exceeded your command weight per time quota. Please ' + 'wait a few seconds, then try again (this should never happen ' + 'in sane real-life applications)')), -5: ('EFAILED', 'The upload failed. Please restart it from scratch'), - -6: ( - 'ETOOMANY', - 'Too many concurrent IP addresses are accessing this upload target URL' - ), - -7: ( - 'ERANGE', ( - 'The upload file packet is out of range or not starting and ' - 'ending on a chunk boundary' - ) - ), - -8: ( - 'EEXPIRED', ( - 'The upload target URL you are trying to access has expired. ' - 'Please request a fresh one' - ) - ), + -6: + ('ETOOMANY', + 'Too many concurrent IP addresses are accessing this upload target URL'), + -7: + ('ERANGE', ('The upload file packet is out of range or not starting and ' + 'ending on a chunk boundary')), + -8: ('EEXPIRED', + ('The upload target URL you are trying to access has expired. ' + 'Please request a fresh one')), -9: ('ENOENT', 'Object (typically, node or user) not found'), -10: ('ECIRCULAR', 'Circular linkage attempted'), - -11: ( - 'EACCESS', - 'Access violation (e.g., trying to write to a read-only share)' - ), + -11: ('EACCESS', + 'Access violation (e.g., trying to write to a read-only share)'), -12: ('EEXIST', 'Trying to create an object that already exists'), -13: ('EINCOMPLETE', 'Trying to access an incomplete resource'), -14: ('EKEY', 'A decryption operation failed (never returned by the API)'), -15: ('ESID', 'Invalid or expired user session, please relogin'), -16: ('EBLOCKED', 'User blocked'), -17: ('EOVERQUOTA', 'Request over quota'), - -18: ( - 'ETEMPUNAVAIL', - 'Resource temporarily not available, please try again later' - ), + -18: ('ETEMPUNAVAIL', + 'Resource temporarily not available, please try again later'), -19: ('ETOOMANYCONNECTIONS', 'many connections on this resource'), -20: ('EWRITE', 'Write failed'), -21: ('EREAD', 'Read failed'), diff --git a/src/mega/mega.py b/src/mega/mega.py index 9d6f851..906b0db 100644 --- a/src/mega/mega.py +++ b/src/mega/mega.py @@ -325,22 +325,25 @@ class Mega: parent_dir_name = path.parent.name for file in list(files.items()): parent_node_id = None - if parent_dir_name: - parent_node_id = self.find_path_descriptor(parent_dir_name, - files=files) - if (filename and parent_node_id and file[1]['a'] - and file[1]['a']['n'] == filename - and parent_node_id == file[1]['p']): + try: + if parent_dir_name: + parent_node_id = self.find_path_descriptor(parent_dir_name, + files=files) + if (filename and parent_node_id and file[1]['a'] + and file[1]['a']['n'] == filename + and parent_node_id == file[1]['p']): + if (exclude_deleted and self._trash_folder_node_id + == file[1]['p']): + continue + return file + elif (filename and file[1]['a'] + and file[1]['a']['n'] == filename): if (exclude_deleted and self._trash_folder_node_id == file[1]['p']): continue return file - elif (filename and file[1]['a'] - and file[1]['a']['n'] == filename): - if (exclude_deleted - and self._trash_folder_node_id == file[1]['p']): - continue - return file + except TypeError: + continue def get_files(self): logger.info('Getting all files...') diff --git a/src/tests/test_mega.py b/src/tests/test_mega.py index 34b5fb1..5cf364e 100644 --- a/src/tests/test_mega.py +++ b/src/tests/test_mega.py @@ -155,7 +155,6 @@ class TestFind: # Check that the correct test.py was found assert file1 != file2 - def test_path_not_found_returns_none(self, mega): assert mega.find('not_found') is None