| Conditions | 17 | 
| Total Lines | 107 | 
| Lines | 0 | 
| Ratio | 0 % | 
| Changes | 2 | ||
| Bugs | 0 | Features | 0 | 
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like unzip() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | from __future__ import absolute_import | ||
| 18 | def unzip(zip_uri, is_url, clone_to_dir='.', no_input=False, password=None): | ||
| 19 | """Download and unpack a zipfile at a given URI. | ||
| 20 | |||
| 21 | This will download the zipfile to the cookiecutter repository, | ||
| 22 | and unpack into a temporary directory. | ||
| 23 | |||
| 24 | :param zip_uri: The URI for the zipfile. | ||
| 25 | :param is_url: Is the zip URI a URL or a file? | ||
| 26 | :param clone_to_dir: The cookiecutter repository directory | ||
| 27 | to put the archive into. | ||
| 28 | :param no_input: Supress any prompts | ||
| 29 | :param password: The password to use when unpacking the repository. | ||
| 30 | """ | ||
| 31 | # Ensure that clone_to_dir exists | ||
| 32 | clone_to_dir = os.path.expanduser(clone_to_dir) | ||
| 33 | make_sure_path_exists(clone_to_dir) | ||
| 34 | |||
| 35 | if is_url: | ||
| 36 | # Build the name of the cached zipfile, | ||
| 37 | # and prompt to delete if it already exists. | ||
| 38 |         identifier = zip_uri.rsplit('/', 1)[1] | ||
| 39 | zip_path = os.path.join(clone_to_dir, identifier) | ||
| 40 | |||
| 41 | if os.path.exists(zip_path): | ||
| 42 | download = prompt_and_delete(zip_path, no_input=no_input) | ||
| 43 | else: | ||
| 44 | download = True | ||
| 45 | |||
| 46 | if download: | ||
| 47 | # (Re) download the zipfile | ||
| 48 | r = requests.get(zip_uri, stream=True) | ||
| 49 | with open(zip_path, 'wb') as f: | ||
| 50 | for chunk in r.iter_content(chunk_size=1024): | ||
| 51 | if chunk: # filter out keep-alive new chunks | ||
| 52 | f.write(chunk) | ||
| 53 | else: | ||
| 54 | # Just use the local zipfile as-is. | ||
| 55 | zip_path = os.path.abspath(zip_uri) | ||
| 56 | |||
| 57 | # Now unpack the repository. The zipfile will be unpacked | ||
| 58 | # into a temporary directory | ||
| 59 | try: | ||
| 60 | zip_file = ZipFile(zip_path) | ||
| 61 | |||
| 62 | if len(zip_file.namelist()) == 0: | ||
| 63 | raise InvalidZipRepository( | ||
| 64 |                 'Zip repository {} is empty'.format(zip_uri) | ||
| 65 | ) | ||
| 66 | |||
| 67 | # The first record in the zipfile should be the directory entry for | ||
| 68 | # the archive. If it isn't a directory, there's a problem. | ||
| 69 | first_filename = zip_file.namelist()[0] | ||
| 70 |         if not first_filename.endswith('/'): | ||
| 71 | raise InvalidZipRepository( | ||
| 72 |                 'Zip repository {} does not include ' | ||
| 73 | 'a top-level directory'.format(zip_uri) | ||
| 74 | ) | ||
| 75 | |||
| 76 | # Construct the final target directory | ||
| 77 | project_name = first_filename[:-1] | ||
| 78 | unzip_base = tempfile.mkdtemp() | ||
| 79 | unzip_path = os.path.join(unzip_base, project_name) | ||
| 80 | |||
| 81 | # Extract the zip file into the temporary directory | ||
| 82 | try: | ||
| 83 | zip_file.extractall(path=unzip_base) | ||
| 84 | except RuntimeError: | ||
| 85 | # File is password protected; try to get a password from the | ||
| 86 | # environment; if that doesn't work, ask the user. | ||
| 87 | if password is not None: | ||
| 88 | try: | ||
| 89 | zip_file.extractall( | ||
| 90 | path=unzip_base, | ||
| 91 |                         pwd=password.encode('utf-8') | ||
| 92 | ) | ||
| 93 | except RuntimeError: | ||
| 94 | raise InvalidZipRepository( | ||
| 95 | 'Invalid password provided for protected repository' | ||
| 96 | ) | ||
| 97 | elif no_input: | ||
| 98 | raise InvalidZipRepository( | ||
| 99 | 'Unable to unlock password protected repository' | ||
| 100 | ) | ||
| 101 | else: | ||
| 102 | retry = 0 | ||
| 103 | while retry is not None: | ||
| 104 | try: | ||
| 105 |                         password = read_repo_password('Repo password') | ||
| 106 | zip_file.extractall( | ||
| 107 | path=unzip_base, | ||
| 108 |                             pwd=password.encode('utf-8') | ||
| 109 | ) | ||
| 110 | retry = None | ||
| 111 | except RuntimeError: | ||
| 112 | retry += 1 | ||
| 113 | if retry == 3: | ||
| 114 | raise InvalidZipRepository( | ||
| 115 | 'Invalid password provided ' | ||
| 116 | 'for protected repository' | ||
| 117 | ) | ||
| 118 | |||
| 119 | except BadZipFile: | ||
| 120 | raise InvalidZipRepository( | ||
| 121 |             'Zip repository {} is not a valid zip archive:'.format(zip_uri) | ||
| 122 | ) | ||
| 123 | |||
| 124 | return unzip_path | ||
| 125 |