From 190c6a6ffd3ced96152dc7cf21f6771112d6efdb Mon Sep 17 00:00:00 2001 From: bleudev Date: Thu, 27 Jun 2024 23:21:09 +0300 Subject: [PATCH 01/31] download_file() --- setup.py | 9 +++++++- ufpy/__init__.py | 16 ++++++++++---- ufpy/github/__init__.py | 3 +++ ufpy/github/download.py | 47 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 ufpy/github/__init__.py create mode 100644 ufpy/github/download.py diff --git a/setup.py b/setup.py index 93029ba..0a5ea3d 100644 --- a/setup.py +++ b/setup.py @@ -14,6 +14,9 @@ project_name = 'ufpy' github_url = f'https://github.com/{organization_name}/{project_name}' +def package(name: str) -> str: + return f'{project_name}.{name}' + setup( name=project_name, version=__version__, @@ -24,7 +27,11 @@ long_description=long_description, long_description_content_type='text/markdown', url=github_url, - packages=[project_name, f'{project_name}.typ'], + packages=[ + project_name, + package('typ'), + package('github'), + ], classifiers=[ 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.12', diff --git a/ufpy/__init__.py b/ufpy/__init__.py index e15f6f8..69eb0c3 100644 --- a/ufpy/__init__.py +++ b/ufpy/__init__.py @@ -1,12 +1,20 @@ __version__ = '0.1.2' -# Typing package -from ufpy import typ from ufpy.cmp import * from ufpy.math_op import * from ufpy.path_tools import * -from ufpy.typ.protocols import * -from ufpy.typ.type_alias import * from ufpy.udict import * from ufpy.ustack import * from ufpy.utils import * + +# Typing package +__typ_version__ = '0.1' +from ufpy import typ +from ufpy.typ.protocols import * +from ufpy.typ.type_alias import * + +# Github package +__github_version__ = '0.1' +from ufpy import github +from ufpy.github.download import UGithubDownloader +from ufpy.github import download_file, download_folder, download_repo, download diff --git a/ufpy/github/__init__.py b/ufpy/github/__init__.py new file mode 100644 index 0000000..6e9240e --- /dev/null +++ b/ufpy/github/__init__.py @@ -0,0 +1,3 @@ +from .download import file as download_file +from .download import folder as download_folder +from .download import repo as download_repo diff --git a/ufpy/github/download.py b/ufpy/github/download.py new file mode 100644 index 0000000..9e3b2ae --- /dev/null +++ b/ufpy/github/download.py @@ -0,0 +1,47 @@ +import os + +from requests import get + +__all__ = ( + 'file', + 'folder', + 'repo', + 'UGithubDownloader', +) + +def file(repo: str, file_path: str, download_path: str, branch_name: str = 'main'): + file_path = file_path.replace('\\', '/') + + url = f'https://raw.githubusercontent.com/{repo}/{branch_name}/{file_path}' + r = get(url) + + download_path = download_path.replace('\\', '/') + path = f'{download_path}/{file_path}' + + directory = '/'.join(path.split('/')[:-1]) + + if not os.path.exists(directory): + os.makedirs(directory) + + with open(path, 'w+') as f: + f.write(r.text) + +def folder(repo: str, folder_path: str, download_path: str, branch_name: str = 'main'): + ... + +def repo(repo: str, download_path: str, branch_name: str = 'main'): + ... + +class UGithubDownloader: + def __init__(self, repo: str, branch_name: str = 'main'): + self.__repo = repo + self.__branch = branch_name + + def download_file(self, file_path: str, download_path: str): + file(self.__repo, file_path, download_path, self.__branch) + + def download_folder(self, folder_path: str, download_path: str): + folder(self.__repo, folder_path, download_path, self.__branch) + + def download_repo(self, download_path: str): + repo(self.__repo, download_path, self.__branch) From 4f49f9d9190056e9f3d21a894889a07e6c1488a5 Mon Sep 17 00:00:00 2001 From: bleudev Date: Fri, 28 Jun 2024 00:27:44 +0300 Subject: [PATCH 02/31] download_repo() --- requirements.txt | 1 + setup.py | 2 +- ufpy/github/download.py | 46 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index e69de29..0227f3c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -0,0 +1 @@ +requests~=2.31.0 \ No newline at end of file diff --git a/setup.py b/setup.py index 0a5ea3d..7cc0fb8 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ long_description = mdf.read() install_requires = [ - + 'requests~=2.31.0', ] organization_name = 'honey-team' diff --git a/ufpy/github/download.py b/ufpy/github/download.py index 9e3b2ae..cfb759e 100644 --- a/ufpy/github/download.py +++ b/ufpy/github/download.py @@ -1,4 +1,6 @@ import os +from shutil import copy, copytree, rmtree +from zipfile import ZipFile from requests import get @@ -30,7 +32,49 @@ def folder(repo: str, folder_path: str, download_path: str, branch_name: str = ' ... def repo(repo: str, download_path: str, branch_name: str = 'main'): - ... + filename = f'{download_path}/repo_temp.zip' + url = f'https://github.com/{repo}/archive/{branch_name}.zip' + + r = get(url) + + with open(filename, 'wb') as f: + f.write(r.content) + + repo_name = repo.split('/')[-1] + main_directory_name = f'{repo_name}-{branch_name}' + + with ZipFile(filename) as archive: + for file in archive.namelist(): + if file.startswith(main_directory_name): + archive.extract(file, download_path) + + if os.path.exists(filename): + os.remove(filename) + + repo_dir = f'{download_path}/{main_directory_name}' + for file in os.listdir(repo_dir): + file_path = f'{repo_dir}/{file}' + new_file_path = f'{download_path}/{file}' + if os.path.isdir(file_path): + if os.path.exists(new_file_path): + print( + f"Warning ({new_file_path}): Currently we don't support editing recursive folders if it's exists" + "when repo directory was downloaded. Sorry, you can just delete all folders with same name as in" + "repo before you use this function instead." + ) + continue + copytree(file_path, new_file_path) + else: + if os.path.exists(new_file_path): + with open(new_file_path, 'w') as nf: + with open(file_path, 'r') as f: + nf.write(f.read()) + else: + copy(file_path, new_file_path) + + if os.path.exists(f'{download_path}/{main_directory_name}'): + rmtree(f'{download_path}/{main_directory_name}') + class UGithubDownloader: def __init__(self, repo: str, branch_name: str = 'main'): From 3c3c65bbaece8a1bbc94a11e20214217ffd978f4 Mon Sep 17 00:00:00 2001 From: bleudev Date: Fri, 28 Jun 2024 18:54:51 +0300 Subject: [PATCH 03/31] download_folder() --- ufpy/github/download.py | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/ufpy/github/download.py b/ufpy/github/download.py index cfb759e..a0d8e58 100644 --- a/ufpy/github/download.py +++ b/ufpy/github/download.py @@ -29,16 +29,45 @@ def file(repo: str, file_path: str, download_path: str, branch_name: str = 'main f.write(r.text) def folder(repo: str, folder_path: str, download_path: str, branch_name: str = 'main'): - ... + filename = f'{download_path}/repo_temp.zip' + url = f'https://github.com/{repo}/archive/{branch_name}.zip' + + with open(filename, 'wb') as f: + f.write(get(url).content) + + repo_name = repo.split('/')[-1] + main_directory_name = f'{repo_name}-{branch_name}' + + with ZipFile(filename) as archive: + for file in archive.namelist(): + if file.startswith(main_directory_name): + archive.extract(file, download_path) + + if os.path.exists(filename): + os.remove(filename) + + repo_dir = f'{download_path}/{main_directory_name}' + dir = f'{download_path}/{main_directory_name}/{folder_path}' + new_dir = f'{download_path}/{folder_path}' + + if os.path.exists(new_dir): + print( + f"Warning ({new_dir}): Currently we don't support editing recursive folders if it's exists" + "when repo directory was downloaded. Sorry, you can just delete all folders with same name as in" + "repo before you use this function instead." + ) + else: + copytree(dir, new_dir) + + if os.path.exists(f'{download_path}/{main_directory_name}'): + rmtree(f'{download_path}/{main_directory_name}') def repo(repo: str, download_path: str, branch_name: str = 'main'): filename = f'{download_path}/repo_temp.zip' url = f'https://github.com/{repo}/archive/{branch_name}.zip' - r = get(url) - with open(filename, 'wb') as f: - f.write(r.content) + f.write(get(url).content) repo_name = repo.split('/')[-1] main_directory_name = f'{repo_name}-{branch_name}' From 38877d626fe65f0eb8312d9616c54d5972d8b07b Mon Sep 17 00:00:00 2001 From: bleudev Date: Fri, 28 Jun 2024 19:23:50 +0300 Subject: [PATCH 04/31] several folders to download --- ufpy/github/download.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/ufpy/github/download.py b/ufpy/github/download.py index a0d8e58..5f6d0ac 100644 --- a/ufpy/github/download.py +++ b/ufpy/github/download.py @@ -28,7 +28,9 @@ def file(repo: str, file_path: str, download_path: str, branch_name: str = 'main with open(path, 'w+') as f: f.write(r.text) -def folder(repo: str, folder_path: str, download_path: str, branch_name: str = 'main'): +def folder(repo: str, folder_path: str | list[str], download_path: str, branch_name: str = 'main'): + if isinstance(folder_path, str): + folder_path = [folder_path] filename = f'{download_path}/repo_temp.zip' url = f'https://github.com/{repo}/archive/{branch_name}.zip' @@ -46,18 +48,18 @@ def folder(repo: str, folder_path: str, download_path: str, branch_name: str = ' if os.path.exists(filename): os.remove(filename) - repo_dir = f'{download_path}/{main_directory_name}' - dir = f'{download_path}/{main_directory_name}/{folder_path}' - new_dir = f'{download_path}/{folder_path}' - - if os.path.exists(new_dir): - print( - f"Warning ({new_dir}): Currently we don't support editing recursive folders if it's exists" - "when repo directory was downloaded. Sorry, you can just delete all folders with same name as in" - "repo before you use this function instead." - ) - else: - copytree(dir, new_dir) + for fpath in folder_path: + dir = f'{download_path}/{main_directory_name}/{fpath}' + new_dir = f'{download_path}/{fpath}' + + if os.path.exists(new_dir): + print( + f"Warning ({new_dir}): Currently we don't support editing recursive folders if it's exists" + "when repo directory was downloaded. Sorry, you can just delete all folders with same name as in" + "repo before you use this function instead." + ) + else: + copytree(dir, new_dir) if os.path.exists(f'{download_path}/{main_directory_name}'): rmtree(f'{download_path}/{main_directory_name}') @@ -113,7 +115,7 @@ def __init__(self, repo: str, branch_name: str = 'main'): def download_file(self, file_path: str, download_path: str): file(self.__repo, file_path, download_path, self.__branch) - def download_folder(self, folder_path: str, download_path: str): + def download_folder(self, folder_path: str | list[str], download_path: str): folder(self.__repo, folder_path, download_path, self.__branch) def download_repo(self, download_path: str): From ab583e3f80d19d9622d304348e91d46a642d5daf Mon Sep 17 00:00:00 2001 From: bleudev Date: Fri, 28 Jun 2024 20:42:07 +0300 Subject: [PATCH 05/31] Fix things from review --- requirements.txt | 2 +- setup.py | 8 ++++---- ufpy/github/__init__.py | 6 +++--- ufpy/github/download.py | 27 +++++++++++++++------------ 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/requirements.txt b/requirements.txt index 0227f3c..37912b8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -requests~=2.31.0 \ No newline at end of file +requests>=2.31.0 \ No newline at end of file diff --git a/setup.py b/setup.py index 7cc0fb8..08652f8 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ long_description = mdf.read() install_requires = [ - 'requests~=2.31.0', + 'requests>=2.31.0', ] organization_name = 'honey-team' @@ -14,7 +14,7 @@ project_name = 'ufpy' github_url = f'https://github.com/{organization_name}/{project_name}' -def package(name: str) -> str: +def _package(name: str) -> str: return f'{project_name}.{name}' setup( @@ -29,8 +29,8 @@ def package(name: str) -> str: url=github_url, packages=[ project_name, - package('typ'), - package('github'), + _package('typ'), + _package('github'), ], classifiers=[ 'Programming Language :: Python :: 3', diff --git a/ufpy/github/__init__.py b/ufpy/github/__init__.py index 6e9240e..862cf1f 100644 --- a/ufpy/github/__init__.py +++ b/ufpy/github/__init__.py @@ -1,3 +1,3 @@ -from .download import file as download_file -from .download import folder as download_folder -from .download import repo as download_repo +from ufpy.github.download import file as download_file +from ufpy.github.download import folder as download_folder +from ufpy.github.download import repo as download_repo diff --git a/ufpy/github/download.py b/ufpy/github/download.py index 5f6d0ac..c5b8dd8 100644 --- a/ufpy/github/download.py +++ b/ufpy/github/download.py @@ -1,4 +1,5 @@ import os +import warnings from shutil import copy, copytree, rmtree from zipfile import ZipFile @@ -17,6 +18,9 @@ def file(repo: str, file_path: str, download_path: str, branch_name: str = 'main url = f'https://raw.githubusercontent.com/{repo}/{branch_name}/{file_path}' r = get(url) + if not r.ok: + raise Exception("Error with getting file from GitHub. Check that repo is public and that file path is correct.") + download_path = download_path.replace('\\', '/') path = f'{download_path}/{file_path}' @@ -49,17 +53,17 @@ def folder(repo: str, folder_path: str | list[str], download_path: str, branch_n os.remove(filename) for fpath in folder_path: - dir = f'{download_path}/{main_directory_name}/{fpath}' - new_dir = f'{download_path}/{fpath}' + folder_dir = f'{download_path}/{main_directory_name}/{fpath}' + new_folder_dir = f'{download_path}/{fpath}' - if os.path.exists(new_dir): - print( - f"Warning ({new_dir}): Currently we don't support editing recursive folders if it's exists" + if os.path.exists(new_folder_dir): + warnings.warn( + f"Warning ({new_folder_dir}): Currently we don't support editing recursive folders if it's exists" "when repo directory was downloaded. Sorry, you can just delete all folders with same name as in" "repo before you use this function instead." ) else: - copytree(dir, new_dir) + copytree(folder_dir, new_folder_dir) if os.path.exists(f'{download_path}/{main_directory_name}'): rmtree(f'{download_path}/{main_directory_name}') @@ -95,13 +99,12 @@ def repo(repo: str, download_path: str, branch_name: str = 'main'): ) continue copytree(file_path, new_file_path) + elif os.path.exists(new_file_path): + with open(new_file_path, 'w') as nf: + with open(file_path, 'r') as f: + nf.write(f.read()) else: - if os.path.exists(new_file_path): - with open(new_file_path, 'w') as nf: - with open(file_path, 'r') as f: - nf.write(f.read()) - else: - copy(file_path, new_file_path) + copy(file_path, new_file_path) if os.path.exists(f'{download_path}/{main_directory_name}'): rmtree(f'{download_path}/{main_directory_name}') From 5f903d87e40afecab38b4be58c6e90bdc6ea6c0c Mon Sep 17 00:00:00 2001 From: bleudev Date: Fri, 28 Jun 2024 22:16:24 +0300 Subject: [PATCH 06/31] rewrite with "with": file --- ufpy/__init__.py | 11 +++--- ufpy/github/download.py | 49 +++++++++++++++++++++++++-- ufpy/path/__init__.py | 2 ++ ufpy/path/files.py | 44 ++++++++++++++++++++++++ ufpy/{path_tools.py => path/tools.py} | 0 5 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 ufpy/path/__init__.py create mode 100644 ufpy/path/files.py rename ufpy/{path_tools.py => path/tools.py} (100%) diff --git a/ufpy/__init__.py b/ufpy/__init__.py index 69eb0c3..bec85a4 100644 --- a/ufpy/__init__.py +++ b/ufpy/__init__.py @@ -2,7 +2,6 @@ from ufpy.cmp import * from ufpy.math_op import * -from ufpy.path_tools import * from ufpy.udict import * from ufpy.ustack import * from ufpy.utils import * @@ -10,10 +9,14 @@ # Typing package __typ_version__ = '0.1' from ufpy import typ -from ufpy.typ.protocols import * -from ufpy.typ.type_alias import * +from ufpy.typ import * -# Github package +# Path package +__path_version__ = '0.1' +from ufpy import path +from ufpy.path import * + +# GitHub package __github_version__ = '0.1' from ufpy import github from ufpy.github.download import UGithubDownloader diff --git a/ufpy/github/download.py b/ufpy/github/download.py index c5b8dd8..59260b8 100644 --- a/ufpy/github/download.py +++ b/ufpy/github/download.py @@ -1,3 +1,4 @@ +import io import os import warnings from shutil import copy, copytree, rmtree @@ -5,6 +6,9 @@ from requests import get +from ufpy.path import UOpen +from ufpy.typ import Empty + __all__ = ( 'file', 'folder', @@ -110,13 +114,52 @@ def repo(repo: str, download_path: str, branch_name: str = 'main'): rmtree(f'{download_path}/{main_directory_name}') +def format_paths(*paths: str) -> list[str] | str | Empty[list]: + new_paths = [] + for path in paths: + path = path.replace('\\', '/') + + if path.startswith('/'): + path = path[1:] + if path.endswith('/'): + path = path[:-1] + + new_paths.append(path) + return new_paths[0] if len(new_paths) <= 1 else new_paths + + class UGithubDownloader: - def __init__(self, repo: str, branch_name: str = 'main'): + def __init__(self, repo: str, base_download_path: str = 'C:/', branch_name: str = 'main'): self.__repo = repo + self.__base_download_path = format_paths(base_download_path) self.__branch = branch_name - def download_file(self, file_path: str, download_path: str): - file(self.__repo, file_path, download_path, self.__branch) + def __enter__(self): + url = f'https://github.com/{self.__repo}/archive/{self.__branch}.zip' + self.__zip = ZipFile(io.BytesIO(get(url).content)) + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.__zip.close() + + def __del__(self): + self.__zip.close() + + def download_file(self, file_path: str, download_path: str = ''): + file_path, download_path = format_paths(file_path, download_path) + download_path = f'{self.__base_download_path}/{download_path}' + + url = f'https://raw.githubusercontent.com/{self.__repo}/{self.__branch}/{file_path}' + r = get(url) + + if not r.ok: + raise Exception( + "Error with getting file from GitHub. Check that repo is public and that file path is correct.") + + path = f'{download_path}{file_path}' + + with UOpen(path, 'w+') as f: + f.write(r.text) def download_folder(self, folder_path: str | list[str], download_path: str): folder(self.__repo, folder_path, download_path, self.__branch) diff --git a/ufpy/path/__init__.py b/ufpy/path/__init__.py new file mode 100644 index 0000000..738eddd --- /dev/null +++ b/ufpy/path/__init__.py @@ -0,0 +1,2 @@ +from ufpy.path.files import * +from ufpy.path.tools import * diff --git a/ufpy/path/files.py b/ufpy/path/files.py new file mode 100644 index 0000000..33dc3e8 --- /dev/null +++ b/ufpy/path/files.py @@ -0,0 +1,44 @@ +import os +from typing import AnyStr, Iterable + + +__all__ = ( + 'UOpen', +) + +class UOpen: + def __init__( + self, filepath: str, mode: str = "r", encoding: str = 'utf-8' + ): + self.__path = filepath + self.__mode = mode + self.__encoding = encoding + + def __enter__(self): + directory = '/'.join(self.__path.split('/')[:-1]) + if not directory: + directory = '\\'.join(self.__path.split('\\')[:-1]) + + if not os.path.exists(directory): + os.makedirs(directory) + + self.__f = open(file=self.__path, mode=self.__mode, encoding=self.__encoding) + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.__f.close() + + def __del__(self): + self.__f.close() + + def write(self, data: AnyStr): + self.__f.write(data) + + def writelines(self, lines: Iterable[AnyStr]): + self.__f.writelines(lines) + + def read(self, n: int = -1) -> AnyStr: + return self.__f.read(n) + + def readlines(self, hint: int = -1) -> list[AnyStr]: + return self.__f.readlines(hint) diff --git a/ufpy/path_tools.py b/ufpy/path/tools.py similarity index 100% rename from ufpy/path_tools.py rename to ufpy/path/tools.py From 80f6f49578d19d04c6c1dd3f6fd59616b27dab80 Mon Sep 17 00:00:00 2001 From: bleudev Date: Fri, 28 Jun 2024 22:54:06 +0300 Subject: [PATCH 07/31] download_files --- ufpy/github/download.py | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/ufpy/github/download.py b/ufpy/github/download.py index 59260b8..c40904f 100644 --- a/ufpy/github/download.py +++ b/ufpy/github/download.py @@ -2,12 +2,13 @@ import os import warnings from shutil import copy, copytree, rmtree +from tempfile import gettempdir +from typing import Iterable from zipfile import ZipFile from requests import get from ufpy.path import UOpen -from ufpy.typ import Empty __all__ = ( 'file', @@ -114,15 +115,18 @@ def repo(repo: str, download_path: str, branch_name: str = 'main'): rmtree(f'{download_path}/{main_directory_name}') -def format_paths(*paths: str) -> list[str] | str | Empty[list]: +def format_paths(*paths: str | list[str]) -> list[str] | list[list[str]] | list[str | list[str]] | str: new_paths = [] for path in paths: - path = path.replace('\\', '/') + if isinstance(path, list): + path = format_paths(*path) + else: + path = path.replace('\\', '/') - if path.startswith('/'): - path = path[1:] - if path.endswith('/'): - path = path[:-1] + if path.startswith('/'): + path = path[1:] + if path.endswith('/'): + path = path[:-1] new_paths.append(path) return new_paths[0] if len(new_paths) <= 1 else new_paths @@ -137,13 +141,22 @@ def __init__(self, repo: str, base_download_path: str = 'C:/', branch_name: str def __enter__(self): url = f'https://github.com/{self.__repo}/archive/{self.__branch}.zip' self.__zip = ZipFile(io.BytesIO(get(url).content)) + + temp_dir = format_paths(gettempdir()) + self.__zip.extractall(temp_dir) + repo_name = self.__repo.split('/')[-1] + self.__repo_path = f'{temp_dir}/{repo_name}-{self.__branch}' return self def __exit__(self, exc_type, exc_val, exc_tb): self.__zip.close() + if os.path.exists(self.__repo_path): + rmtree(self.__repo_path) def __del__(self): self.__zip.close() + if os.path.exists(self.__repo_path): + rmtree(self.__repo_path) def download_file(self, file_path: str, download_path: str = ''): file_path, download_path = format_paths(file_path, download_path) @@ -156,11 +169,16 @@ def download_file(self, file_path: str, download_path: str = ''): raise Exception( "Error with getting file from GitHub. Check that repo is public and that file path is correct.") - path = f'{download_path}{file_path}' + path = f'{download_path}/{file_path}' with UOpen(path, 'w+') as f: f.write(r.text) + def download_files(self, file_paths: Iterable[str], download_path: str = ''): + file_paths, download_path = format_paths(list(file_paths), download_path) + for file_path in file_paths: + self.download_file(file_path, download_path) + def download_folder(self, folder_path: str | list[str], download_path: str): folder(self.__repo, folder_path, download_path, self.__branch) From 24776f2998f9a384b784226a85cf559eeccfc1f3 Mon Sep 17 00:00:00 2001 From: bleudev Date: Fri, 28 Jun 2024 23:17:35 +0300 Subject: [PATCH 08/31] download_repo() --- ufpy/github/download.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/ufpy/github/download.py b/ufpy/github/download.py index c40904f..ddd19c5 100644 --- a/ufpy/github/download.py +++ b/ufpy/github/download.py @@ -3,7 +3,7 @@ import warnings from shutil import copy, copytree, rmtree from tempfile import gettempdir -from typing import Iterable +from typing import Iterable, TypeAlias from zipfile import ZipFile from requests import get @@ -132,8 +132,12 @@ def format_paths(*paths: str | list[str]) -> list[str] | list[list[str]] | list[ return new_paths[0] if len(new_paths) <= 1 else new_paths +CWD: TypeAlias = None + class UGithubDownloader: - def __init__(self, repo: str, base_download_path: str = 'C:/', branch_name: str = 'main'): + def __init__(self, repo: str, base_download_path: str = CWD, branch_name: str = 'main'): + if base_download_path == CWD: + base_download_path = format_paths(os.getcwd()) self.__repo = repo self.__base_download_path = format_paths(base_download_path) self.__branch = branch_name @@ -180,7 +184,19 @@ def download_files(self, file_paths: Iterable[str], download_path: str = ''): self.download_file(file_path, download_path) def download_folder(self, folder_path: str | list[str], download_path: str): - folder(self.__repo, folder_path, download_path, self.__branch) + ... + + def download_repo(self, download_path: str = ''): + download_path = format_paths(download_path) + download_path = f'{self.__base_download_path}/{download_path}' - def download_repo(self, download_path: str): - repo(self.__repo, download_path, self.__branch) + for filename in os.listdir(self.__repo_path): + src, dst = f'{self.__repo_path}/{filename}', f'{download_path}/{filename}' + if os.path.isdir(src): + if os.path.exists(dst): + rmtree(dst) + copytree(src, dst) + else: + if os.path.exists(dst): + os.remove(dst) + copy(src, dst) From 12f6fa117fbc6510c5afbd9b1e370b8df8433b97 Mon Sep 17 00:00:00 2001 From: bleudev Date: Fri, 28 Jun 2024 23:40:13 +0300 Subject: [PATCH 09/31] Fixes + download_folder(s)() --- ufpy/__init__.py | 3 +- ufpy/github/__init__.py | 3 + ufpy/github/download.py | 119 +++++++++------------------------------- 3 files changed, 29 insertions(+), 96 deletions(-) diff --git a/ufpy/__init__.py b/ufpy/__init__.py index bec85a4..57ce48c 100644 --- a/ufpy/__init__.py +++ b/ufpy/__init__.py @@ -19,5 +19,4 @@ # GitHub package __github_version__ = '0.1' from ufpy import github -from ufpy.github.download import UGithubDownloader -from ufpy.github import download_file, download_folder, download_repo, download +from ufpy.github import UGithubDownloader, download_file, download_folder, download_repo diff --git a/ufpy/github/__init__.py b/ufpy/github/__init__.py index 862cf1f..b0d148f 100644 --- a/ufpy/github/__init__.py +++ b/ufpy/github/__init__.py @@ -1,3 +1,6 @@ +# Download +import ufpy.github.download +from ufpy.github.download import UGithubDownloader from ufpy.github.download import file as download_file from ufpy.github.download import folder as download_folder from ufpy.github.download import repo as download_repo diff --git a/ufpy/github/download.py b/ufpy/github/download.py index ddd19c5..acd9543 100644 --- a/ufpy/github/download.py +++ b/ufpy/github/download.py @@ -1,6 +1,5 @@ import io import os -import warnings from shutil import copy, copytree, rmtree from tempfile import gettempdir from typing import Iterable, TypeAlias @@ -17,102 +16,23 @@ 'UGithubDownloader', ) -def file(repo: str, file_path: str, download_path: str, branch_name: str = 'main'): - file_path = file_path.replace('\\', '/') - - url = f'https://raw.githubusercontent.com/{repo}/{branch_name}/{file_path}' - r = get(url) - - if not r.ok: - raise Exception("Error with getting file from GitHub. Check that repo is public and that file path is correct.") - - download_path = download_path.replace('\\', '/') - path = f'{download_path}/{file_path}' - - directory = '/'.join(path.split('/')[:-1]) - - if not os.path.exists(directory): - os.makedirs(directory) - - with open(path, 'w+') as f: - f.write(r.text) +def file(repo: str, file_path: str | list[str], download_path: str, branch_name: str = 'main'): + with UGithubDownloader(repo, download_path, branch_name) as gd: + if isinstance(file_path, str): + gd.download_file(file_path) + else: + gd.download_files(file_path) def folder(repo: str, folder_path: str | list[str], download_path: str, branch_name: str = 'main'): - if isinstance(folder_path, str): - folder_path = [folder_path] - filename = f'{download_path}/repo_temp.zip' - url = f'https://github.com/{repo}/archive/{branch_name}.zip' - - with open(filename, 'wb') as f: - f.write(get(url).content) - - repo_name = repo.split('/')[-1] - main_directory_name = f'{repo_name}-{branch_name}' - - with ZipFile(filename) as archive: - for file in archive.namelist(): - if file.startswith(main_directory_name): - archive.extract(file, download_path) - - if os.path.exists(filename): - os.remove(filename) - - for fpath in folder_path: - folder_dir = f'{download_path}/{main_directory_name}/{fpath}' - new_folder_dir = f'{download_path}/{fpath}' - - if os.path.exists(new_folder_dir): - warnings.warn( - f"Warning ({new_folder_dir}): Currently we don't support editing recursive folders if it's exists" - "when repo directory was downloaded. Sorry, you can just delete all folders with same name as in" - "repo before you use this function instead." - ) + with UGithubDownloader(repo, download_path, branch_name) as gd: + if isinstance(folder_path, str): + gd.download_folder(folder_path) else: - copytree(folder_dir, new_folder_dir) - - if os.path.exists(f'{download_path}/{main_directory_name}'): - rmtree(f'{download_path}/{main_directory_name}') + gd.download_folders(folder_path) def repo(repo: str, download_path: str, branch_name: str = 'main'): - filename = f'{download_path}/repo_temp.zip' - url = f'https://github.com/{repo}/archive/{branch_name}.zip' - - with open(filename, 'wb') as f: - f.write(get(url).content) - - repo_name = repo.split('/')[-1] - main_directory_name = f'{repo_name}-{branch_name}' - - with ZipFile(filename) as archive: - for file in archive.namelist(): - if file.startswith(main_directory_name): - archive.extract(file, download_path) - - if os.path.exists(filename): - os.remove(filename) - - repo_dir = f'{download_path}/{main_directory_name}' - for file in os.listdir(repo_dir): - file_path = f'{repo_dir}/{file}' - new_file_path = f'{download_path}/{file}' - if os.path.isdir(file_path): - if os.path.exists(new_file_path): - print( - f"Warning ({new_file_path}): Currently we don't support editing recursive folders if it's exists" - "when repo directory was downloaded. Sorry, you can just delete all folders with same name as in" - "repo before you use this function instead." - ) - continue - copytree(file_path, new_file_path) - elif os.path.exists(new_file_path): - with open(new_file_path, 'w') as nf: - with open(file_path, 'r') as f: - nf.write(f.read()) - else: - copy(file_path, new_file_path) - - if os.path.exists(f'{download_path}/{main_directory_name}'): - rmtree(f'{download_path}/{main_directory_name}') + with UGithubDownloader(repo, download_path, branch_name) as gd: + gd.download_repo() def format_paths(*paths: str | list[str]) -> list[str] | list[list[str]] | list[str | list[str]] | str: @@ -183,8 +103,19 @@ def download_files(self, file_paths: Iterable[str], download_path: str = ''): for file_path in file_paths: self.download_file(file_path, download_path) - def download_folder(self, folder_path: str | list[str], download_path: str): - ... + def download_folder(self, folder_path: str, download_path: str = ''): + download_path = format_paths(download_path) + download_path = f'{self.__base_download_path}/{download_path}' + + src, dst = f'{self.__repo_path}/{folder_path}', f'{download_path}/{folder_path}' + if os.path.exists(dst): + rmtree(dst) + copytree(src, dst) + + def download_folders(self, folder_paths: Iterable[str], download_path: str = ''): + folder_paths, download_path = format_paths(list(folder_paths), download_path) + for folder_path in folder_paths: + self.download_folder(folder_path, download_path) def download_repo(self, download_path: str = ''): download_path = format_paths(download_path) From 1022a762b98549d4a59bc06de36a89367eddb99f Mon Sep 17 00:00:00 2001 From: bleudev Date: Fri, 28 Jun 2024 23:54:15 +0300 Subject: [PATCH 10/31] fix things from review --- ufpy/__init__.py | 5 +---- ufpy/github/download.py | 2 +- ufpy/path/files.py | 13 ++++++------- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/ufpy/__init__.py b/ufpy/__init__.py index 57ce48c..1af4da7 100644 --- a/ufpy/__init__.py +++ b/ufpy/__init__.py @@ -8,15 +8,12 @@ # Typing package __typ_version__ = '0.1' -from ufpy import typ from ufpy.typ import * # Path package __path_version__ = '0.1' -from ufpy import path from ufpy.path import * # GitHub package __github_version__ = '0.1' -from ufpy import github -from ufpy.github import UGithubDownloader, download_file, download_folder, download_repo +from ufpy.github import * diff --git a/ufpy/github/download.py b/ufpy/github/download.py index acd9543..5b21646 100644 --- a/ufpy/github/download.py +++ b/ufpy/github/download.py @@ -35,7 +35,7 @@ def repo(repo: str, download_path: str, branch_name: str = 'main'): gd.download_repo() -def format_paths(*paths: str | list[str]) -> list[str] | list[list[str]] | list[str | list[str]] | str: +def format_paths(*paths: str | list[str]) -> list[str] | list[list[str]]: new_paths = [] for path in paths: if isinstance(path, list): diff --git a/ufpy/path/files.py b/ufpy/path/files.py index 33dc3e8..11c2c52 100644 --- a/ufpy/path/files.py +++ b/ufpy/path/files.py @@ -15,21 +15,20 @@ def __init__( self.__encoding = encoding def __enter__(self): - directory = '/'.join(self.__path.split('/')[:-1]) - if not directory: - directory = '\\'.join(self.__path.split('\\')[:-1]) + directory = '/'.join(self.__path.split('/')[:-1]) or '\\'.join(self.__path.split('\\')[:-1]) - if not os.path.exists(directory): - os.makedirs(directory) + os.makedirs(directory, exist_ok=True) self.__f = open(file=self.__path, mode=self.__mode, encoding=self.__encoding) return self def __exit__(self, exc_type, exc_val, exc_tb): - self.__f.close() + if not self.__f.closed: + self.__f.close() def __del__(self): - self.__f.close() + if not self.__f.closed: + self.__f.close() def write(self, data: AnyStr): self.__f.write(data) From 651a68ab023887ccc3bf8e81636707a28590703e Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 00:08:28 +0300 Subject: [PATCH 11/31] =?UTF-8?q?fix=20things=20from=20review=20=E2=84=962?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ufpy/github/download.py | 9 +++++++-- ufpy/path/files.py | 3 +-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ufpy/github/download.py b/ufpy/github/download.py index 5b21646..e1e48b2 100644 --- a/ufpy/github/download.py +++ b/ufpy/github/download.py @@ -35,7 +35,7 @@ def repo(repo: str, download_path: str, branch_name: str = 'main'): gd.download_repo() -def format_paths(*paths: str | list[str]) -> list[str] | list[list[str]]: +def format_paths(*paths: str | list[str]) -> str | list[str] | list[list[str]]: new_paths = [] for path in paths: if isinstance(path, list): @@ -64,7 +64,12 @@ def __init__(self, repo: str, base_download_path: str = CWD, branch_name: str = def __enter__(self): url = f'https://github.com/{self.__repo}/archive/{self.__branch}.zip' - self.__zip = ZipFile(io.BytesIO(get(url).content)) + r = get(url) + + if not r.ok: + raise Exception( + "Error with getting file from GitHub. Check that repo is public and that file path is correct.") + self.__zip = ZipFile(io.BytesIO(r.content)) temp_dir = format_paths(gettempdir()) self.__zip.extractall(temp_dir) diff --git a/ufpy/path/files.py b/ufpy/path/files.py index 11c2c52..69f7099 100644 --- a/ufpy/path/files.py +++ b/ufpy/path/files.py @@ -23,8 +23,7 @@ def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): - if not self.__f.closed: - self.__f.close() + self.__f.close() def __del__(self): if not self.__f.closed: From 18747533a41bfd55d5e3f32ec29acdf7d297ee87 Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 00:17:05 +0300 Subject: [PATCH 12/31] =?UTF-8?q?fix=20things=20from=20review=20=E2=84=963?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ufpy/github/download.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ufpy/github/download.py b/ufpy/github/download.py index e1e48b2..77b13d0 100644 --- a/ufpy/github/download.py +++ b/ufpy/github/download.py @@ -6,6 +6,7 @@ from zipfile import ZipFile from requests import get +from requests.exceptions import RequestException from ufpy.path import UOpen @@ -67,7 +68,7 @@ def __enter__(self): r = get(url) if not r.ok: - raise Exception( + raise RequestException( "Error with getting file from GitHub. Check that repo is public and that file path is correct.") self.__zip = ZipFile(io.BytesIO(r.content)) @@ -95,7 +96,7 @@ def download_file(self, file_path: str, download_path: str = ''): r = get(url) if not r.ok: - raise Exception( + raise RequestExceptio( "Error with getting file from GitHub. Check that repo is public and that file path is correct.") path = f'{download_path}/{file_path}' From fe5599ec3bd738e72f395bf7cbf632d0f3cb7b88 Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 00:40:23 +0300 Subject: [PATCH 13/31] =?UTF-8?q?fix=20things=20from=20review=20=E2=84=964?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ufpy/github/download.py | 2 +- ufpy/path/files.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ufpy/github/download.py b/ufpy/github/download.py index 77b13d0..8b72310 100644 --- a/ufpy/github/download.py +++ b/ufpy/github/download.py @@ -96,7 +96,7 @@ def download_file(self, file_path: str, download_path: str = ''): r = get(url) if not r.ok: - raise RequestExceptio( + raise RequestException( "Error with getting file from GitHub. Check that repo is public and that file path is correct.") path = f'{download_path}/{file_path}' diff --git a/ufpy/path/files.py b/ufpy/path/files.py index 69f7099..885a885 100644 --- a/ufpy/path/files.py +++ b/ufpy/path/files.py @@ -26,7 +26,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): self.__f.close() def __del__(self): - if not self.__f.closed: + if self.__f and not self.__f.closed: self.__f.close() def write(self, data: AnyStr): From f1edaed08d50e2ead45611ffa120176d60869f62 Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 01:27:40 +0300 Subject: [PATCH 14/31] =?UTF-8?q?Examples=20=E2=84=961?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/github/download.md | 57 +++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 examples/github/download.md diff --git a/examples/github/download.md b/examples/github/download.md new file mode 100644 index 0000000..5dcd2ca --- /dev/null +++ b/examples/github/download.md @@ -0,0 +1,57 @@ +# Github / Download + +## Introduction + +In `ufpy` there are 3 functions and 1 class for downloading things from public GitHub repositories. +You can without GitHub token download all repository, folder or several folders, and file or several +files. You can use `UGithubDownloader` class for all this actions or other 3 functions. Class is more +optimized for multi-requesting. If you want to download anything several times: use it. He is using 1] +unpacked zip archive for all operations and by the end deletes it. If you don't want to download anything +several times -> use functions. + +Import functions and class from `ufpy`: +```python +import ufpy +from ufpy import UGithubDownloader, download_file, download_folder, download_repo, UGithubDownloader +``` + +> [!CAUTION] +> All repositories you want to download from must be public + +## Open `UGithubDownloader` class and use it + +For opening this class you should use `with` operator as you do with files and other things: +```python +with UGithubDownloader("honey-team/ufpy", "C:/Ufpy-Test", "0.1") as gd: + # First argument - "repository owner"/"repository name" + # Second - Base download path (in all methods is using download paths from base download path. How in cmd + # for example: base path: C:\; cd ufpy -> final path: C:\ufpy.) (default is cwd (current working directory) + # Third argument: Branch or tag name (default is "main" (not master!)) + gd.download_repo() # In C:/Ufpy-Test will appear all files from 0.1 tag in this repository. + gd.download_repo("ufpy-0.1") # In C:/Ufpy-Test/ufpy-0.1 will appear all files from 0.1 tag in this repository +``` + +## Download file/files + +You can use `download_file()` function, `ufpy.github.download.file()` function +(they're same, but with different names) and `UGithubDownloader.download_file()` method + +> [!NOTE] +> You can use any iterable of strings in `download_file()` function for downloading several files. +> In `UGithubDownloader` there are `download_files()` method. + +One file: +```python +download_file("honey-team/ufpy", "README.md", "C:/Users/") # copy README.md from main branch in C:/Users/ directory + +with UGithubDownloader("honey-team/ufpy", "C:/Users/") as gd: + gd.download_file("README.md") # Same +``` + +Two files: +```python +download_file("honey-team/ufpy", ["README.md", "mkdocs.yml"], "C:/Users/") # copy README.md and mkdocs.yml from main branch in C:/Users/ directory + +with UGithubDownloader("honey-team/ufpy", "C:/Users/") as gd: + gd.download_files(["README.md", "mkdocs.yml"]) # Same +``` From 7b7d0c4923c5bc689125278530ec27f83011675c Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 13:25:37 +0300 Subject: [PATCH 15/31] =?UTF-8?q?Examples=20=E2=84=962=20final?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/github/download.md | 51 ++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/examples/github/download.md b/examples/github/download.md index 5dcd2ca..b727958 100644 --- a/examples/github/download.md +++ b/examples/github/download.md @@ -31,10 +31,10 @@ with UGithubDownloader("honey-team/ufpy", "C:/Ufpy-Test", "0.1") as gd: gd.download_repo("ufpy-0.1") # In C:/Ufpy-Test/ufpy-0.1 will appear all files from 0.1 tag in this repository ``` -## Download file/files +## Download file(s) You can use `download_file()` function, `ufpy.github.download.file()` function -(they're same, but with different names) and `UGithubDownloader.download_file()` method +(they're same, but with different names) and `UGithubDownloader.download_file()` method. > [!NOTE] > You can use any iterable of strings in `download_file()` function for downloading several files. @@ -42,7 +42,8 @@ You can use `download_file()` function, `ufpy.github.download.file()` function One file: ```python -download_file("honey-team/ufpy", "README.md", "C:/Users/") # copy README.md from main branch in C:/Users/ directory +download_file("honey-team/ufpy", "README.md", "C:/Users/") +# copy README.md from main branch in C:/Users/ directory with UGithubDownloader("honey-team/ufpy", "C:/Users/") as gd: gd.download_file("README.md") # Same @@ -50,8 +51,50 @@ with UGithubDownloader("honey-team/ufpy", "C:/Users/") as gd: Two files: ```python -download_file("honey-team/ufpy", ["README.md", "mkdocs.yml"], "C:/Users/") # copy README.md and mkdocs.yml from main branch in C:/Users/ directory +download_file("honey-team/ufpy", ["README.md", "mkdocs.yml"], "C:/Users/") +# copy README.md and mkdocs.yml from main branch in C:/Users/ directory with UGithubDownloader("honey-team/ufpy", "C:/Users/") as gd: gd.download_files(["README.md", "mkdocs.yml"]) # Same ``` + +## Download folder(s) + +You can use `download_folder()` function, `ufpy.github.download.folder()` function +(they're same, but with different names) and `UGithubDownloader.download_folder()` method. + +> [!NOTE] +> You can use any iterable of strings in `download_folder()` function for downloading several folders. +> In `UGithubDownloader` there are `download_folders()` method. + +One folder: +```python +download_folder("honey-team/ufpy", "examples", "C:/Users/") +# create C:/Users//examples folder +# and copy origin/examples contents from main branch in this folder + +with UGithubDownloader("honey-team/ufpy", "C:/Users/") as gd: + gd.download_folder() # Same +``` + +Two folders: +```python +download_folder("honey-team/ufpy", ["examples", ".github"], "C:/Users/") +# create C:/Users//examples and C:/Users//.github folders +# and copy origin/examples contents and origin/.github contents from main branch in this folders + +with UGithubDownloader("honey-team/ufpy", "C:/Users/") as gd: + gd.download_folders(["examples", ".github"]) # Same +``` + +## Download all repository + +You can use `download_repo()` function, `ufpy.github.download.repo()` function +(they're same, but with different names) and `UGithubDownloader.download_repo()` method: +```python +download_repo("honey-team/ufpy", "C:/Users/") +# copy all repository files and folders with its contents from main branch in C:/Users/ directory. + +with UGithubDownloader("honey-team/ufpy", "C:/Users/") as gd: + gd.download_repo() # Same +``` From 3950575d3b5bf4a72ccdc69af305ae51bb6c3f20 Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 13:46:48 +0300 Subject: [PATCH 16/31] Add images to example --- examples/github/.assets/download1.png | Bin 0 -> 19425 bytes examples/github/.assets/download2.png | Bin 0 -> 22196 bytes examples/github/.assets/download3.png | Bin 0 -> 21588 bytes examples/github/.assets/download4.png | Bin 0 -> 28206 bytes examples/github/.assets/download5.png | Bin 0 -> 67612 bytes examples/github/download.md | 48 ++++++++++++++++++-------- 6 files changed, 34 insertions(+), 14 deletions(-) create mode 100644 examples/github/.assets/download1.png create mode 100644 examples/github/.assets/download2.png create mode 100644 examples/github/.assets/download3.png create mode 100644 examples/github/.assets/download4.png create mode 100644 examples/github/.assets/download5.png diff --git a/examples/github/.assets/download1.png b/examples/github/.assets/download1.png new file mode 100644 index 0000000000000000000000000000000000000000..1bf552ef67a7c748524bbfab6ea7956f789dcedf GIT binary patch literal 19425 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%0AYhE<(lp&jEOcwk=W-i^6;#g4-? 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 literal 0 HcmV?d00001 diff --git a/examples/github/.assets/download2.png b/examples/github/.assets/download2.png new file mode 100644 index 0000000000000000000000000000000000000000..e388d10be6942f952508b30eb58d2b446d39e2de GIT binary patch literal 22196 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 XSBCJj5HQ1@fEB*psDlqYPiOoM-N=QA literal 0 HcmV?d00001 diff --git a/examples/github/.assets/download3.png b/examples/github/.assets/download3.png new file mode 100644 index 0000000000000000000000000000000000000000..72898aa56c45b57f6c21534b5055c835478e0bdb GIT binary patch literal 21588 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 z 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

a?4=P>44Yht?OS3t`Dd#wyR(e~N6Bp~ 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

D2R(d8_QeIYYudYYTb3(acxDeDU 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 V0f+XCDJ@;yS69|nDpRls`Cp~-`VIg9 literal 0 HcmV?d00001 diff --git a/examples/github/download.md b/examples/github/download.md index b727958..5bfba77 100644 --- a/examples/github/download.md +++ b/examples/github/download.md @@ -42,22 +42,28 @@ You can use `download_file()` function, `ufpy.github.download.file()` function One file: ```python -download_file("honey-team/ufpy", "README.md", "C:/Users/") -# copy README.md from main branch in C:/Users/ directory +download_file("honey-team/ufpy", "README.md", "C:/Users//ufpy-tests") +# copy README.md from main branch in C:/Users//ufpy-tests directory -with UGithubDownloader("honey-team/ufpy", "C:/Users/") as gd: +with UGithubDownloader("honey-team/ufpy", "C:/Users//ufpy-tests") as gd: gd.download_file("README.md") # Same ``` +After changing `` to your username and running this code you'll get this: +![Download one file](.assets/download1.png) + Two files: ```python -download_file("honey-team/ufpy", ["README.md", "mkdocs.yml"], "C:/Users/") -# copy README.md and mkdocs.yml from main branch in C:/Users/ directory +download_file("honey-team/ufpy", ["README.md", "mkdocs.yml"], "C:/Users//ufpy-tests") +# copy README.md and mkdocs.yml from main branch in C:/Users//ufpy-tests directory -with UGithubDownloader("honey-team/ufpy", "C:/Users/") as gd: +with UGithubDownloader("honey-team/ufpy", "C:/Users//ufpy-tests") as gd: gd.download_files(["README.md", "mkdocs.yml"]) # Same ``` +After changing `` to your username and running this code you'll get this: +![Download two files](.assets/download2.png) + ## Download folder(s) You can use `download_folder()` function, `ufpy.github.download.folder()` function @@ -69,32 +75,46 @@ You can use `download_folder()` function, `ufpy.github.download.folder()` functi One folder: ```python -download_folder("honey-team/ufpy", "examples", "C:/Users/") +download_folder("honey-team/ufpy", "examples", "C:/Users//ufpy-tests") # create C:/Users//examples folder # and copy origin/examples contents from main branch in this folder -with UGithubDownloader("honey-team/ufpy", "C:/Users/") as gd: - gd.download_folder() # Same +with UGithubDownloader("honey-team/ufpy", "C:/Users//ufpy-tests") as gd: + gd.download_folder("examples") # Same ``` +After changing `` to your username and running this code you'll get this: +![Download one folder](.assets/download3.png) + Two folders: ```python -download_folder("honey-team/ufpy", ["examples", ".github"], "C:/Users/") +download_folder("honey-team/ufpy", ["examples", ".github"], "C:/Users//ufpy-tests") # create C:/Users//examples and C:/Users//.github folders # and copy origin/examples contents and origin/.github contents from main branch in this folders -with UGithubDownloader("honey-team/ufpy", "C:/Users/") as gd: +with UGithubDownloader("honey-team/ufpy", "C:/Users//ufpy-tests") as gd: gd.download_folders(["examples", ".github"]) # Same ``` +After changing `` to your username and running this code you'll get this: +![Download two folders](.assets/download4.png) + ## Download all repository You can use `download_repo()` function, `ufpy.github.download.repo()` function (they're same, but with different names) and `UGithubDownloader.download_repo()` method: ```python -download_repo("honey-team/ufpy", "C:/Users/") -# copy all repository files and folders with its contents from main branch in C:/Users/ directory. +download_repo("honey-team/ufpy", "C:/Users//ufpy-tests") +# copy all repository files and folders with its contents from main branch in C:/Users//ufpy-tests directory. -with UGithubDownloader("honey-team/ufpy", "C:/Users/") as gd: +with UGithubDownloader("honey-team/ufpy", "C:/Users//ufpy-tests") as gd: gd.download_repo() # Same ``` + +After changing `` to your username and running this code you'll get this: + +> [!NOTE] +> Repository code is code before merging this pull request (#37). +> When this pull request was merged, repository was changed. + +![Download all repository](.assets/download5.png) From 5474911c33c41d900331da4aa1d96efa2698cb4c Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 13:50:31 +0300 Subject: [PATCH 17/31] Add link to pull request --- examples/github/download.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/github/download.md b/examples/github/download.md index 5bfba77..abca026 100644 --- a/examples/github/download.md +++ b/examples/github/download.md @@ -114,7 +114,8 @@ with UGithubDownloader("honey-team/ufpy", "C:/Users//ufpy-tests") as gd: After changing `` to your username and running this code you'll get this: > [!NOTE] -> Repository code is code before merging this pull request (#37). +> Repository code is code before merging this pull request +> ([#37](https://github.com/honey-team/ufpy/pull/37)). > When this pull request was merged, repository was changed. ![Download all repository](.assets/download5.png) From eefb6ea7b89962a9a113b9b3ac40de0e32561ce7 Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 14:27:36 +0300 Subject: [PATCH 18/31] =?UTF-8?q?tests=20=E2=84=961?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_github_download.py | 50 +++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 tests/test_github_download.py diff --git a/tests/test_github_download.py b/tests/test_github_download.py new file mode 100644 index 0000000..bb1053e --- /dev/null +++ b/tests/test_github_download.py @@ -0,0 +1,50 @@ +import unittest +from os import remove +from tempfile import gettempdir + +import ufpy +from ufpy import UGithubDownloader, download_file + + +class UGithubDownloadTestCase(unittest.TestCase): + def test_file(self): + repo = 'honey-team/ufpy' + file = 'README.md' + + temp_dir = gettempdir() + download_path = rf'{temp_dir}\ufpy-tests' + file_path = rf'{download_path}\README.md' + + # download_file() + download_file(repo, file, download_path) + + with open(file_path, 'r') as f: + file_contents1 = f.read() + + remove(file_path) + + # file() + ufpy.github.download.file(repo, file, download_path) + + with open(file_path, 'r') as f: + file_contents2 = f.read() + + remove(file_path) + + # UGithubDownloader.download_file() + with UGithubDownloader(repo, download_path) as gd: + gd.download_file(file) + + with open(file_path, 'r') as f: + file_contents3 = f.read() + + remove(file_path) + + # Asserts + self.assertEqual(file_contents1, file_contents2) + self.assertEqual(file_contents1, file_contents3) + self.assertEqual(file_contents2, file_contents3) + + +if __name__ == '__main__': + unittest.main() From 991dd335307ee1c5a2fd271edf4848143f1f3e0f Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 14:37:23 +0300 Subject: [PATCH 19/31] fix tests --- tests/test_github_download.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/test_github_download.py b/tests/test_github_download.py index bb1053e..6dc08d5 100644 --- a/tests/test_github_download.py +++ b/tests/test_github_download.py @@ -1,5 +1,5 @@ import unittest -from os import remove +from os import remove, mkdir from tempfile import gettempdir import ufpy @@ -12,8 +12,10 @@ def test_file(self): file = 'README.md' temp_dir = gettempdir() - download_path = rf'{temp_dir}\ufpy-tests' - file_path = rf'{download_path}\README.md' + download_path = f'{temp_dir}/ufpy-tests' + file_path = f'{download_path}/README.md' + + mkdir(download_path) # download_file() download_file(repo, file, download_path) From 1ecb12cf1a91bc34690edbe41041f4de83e8fbad Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 14:43:51 +0300 Subject: [PATCH 20/31] =?UTF-8?q?fix=20tests=20=E2=84=962?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_github_download.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/test_github_download.py b/tests/test_github_download.py index 6dc08d5..45428a9 100644 --- a/tests/test_github_download.py +++ b/tests/test_github_download.py @@ -1,6 +1,5 @@ import unittest -from os import remove, mkdir -from tempfile import gettempdir +from os import remove, mkdir, getcwd import ufpy from ufpy import UGithubDownloader, download_file @@ -11,8 +10,8 @@ def test_file(self): repo = 'honey-team/ufpy' file = 'README.md' - temp_dir = gettempdir() - download_path = f'{temp_dir}/ufpy-tests' + cwd_path = getcwd() + download_path = f'{cwd_path}/ufpy-tests' file_path = f'{download_path}/README.md' mkdir(download_path) From 89261f1d245c625f476429e095f3c5cf07ead1af Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 14:47:44 +0300 Subject: [PATCH 21/31] =?UTF-8?q?fix=20tests=20=E2=84=963?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_github_download.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/test_github_download.py b/tests/test_github_download.py index 45428a9..b8e10fa 100644 --- a/tests/test_github_download.py +++ b/tests/test_github_download.py @@ -1,5 +1,5 @@ import unittest -from os import remove, mkdir, getcwd +from os import remove import ufpy from ufpy import UGithubDownloader, download_file @@ -10,11 +10,10 @@ def test_file(self): repo = 'honey-team/ufpy' file = 'README.md' - cwd_path = getcwd() - download_path = f'{cwd_path}/ufpy-tests' + download_path = '' file_path = f'{download_path}/README.md' - mkdir(download_path) + # mkdir(download_path) # download_file() download_file(repo, file, download_path) From e3e0209eab4ec27f04da93ec66aa66e8c8d53ca1 Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 14:53:25 +0300 Subject: [PATCH 22/31] =?UTF-8?q?fix=20tests=20=E2=84=964?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_github_download.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_github_download.py b/tests/test_github_download.py index b8e10fa..b561592 100644 --- a/tests/test_github_download.py +++ b/tests/test_github_download.py @@ -11,7 +11,7 @@ def test_file(self): file = 'README.md' download_path = '' - file_path = f'{download_path}/README.md' + file_path = f'{download_path}README.md' # mkdir(download_path) From fb4be180d4aaa0108c17bf3f07ad9f4d8c885c34 Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 14:56:17 +0300 Subject: [PATCH 23/31] =?UTF-8?q?fix=20tests=20=E2=84=965?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_github_download.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_github_download.py b/tests/test_github_download.py index b561592..9e07aae 100644 --- a/tests/test_github_download.py +++ b/tests/test_github_download.py @@ -10,8 +10,8 @@ def test_file(self): repo = 'honey-team/ufpy' file = 'README.md' - download_path = '' - file_path = f'{download_path}README.md' + download_path = '/usr/ufpy-tests' + file_path = f'{download_path}/README.md' # mkdir(download_path) From 190de66c8e3e22614d07bcc257a975f6a742756c Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 15:01:16 +0300 Subject: [PATCH 24/31] delete tests --- tests/test_github_download.py | 50 ----------------------------------- 1 file changed, 50 deletions(-) delete mode 100644 tests/test_github_download.py diff --git a/tests/test_github_download.py b/tests/test_github_download.py deleted file mode 100644 index 9e07aae..0000000 --- a/tests/test_github_download.py +++ /dev/null @@ -1,50 +0,0 @@ -import unittest -from os import remove - -import ufpy -from ufpy import UGithubDownloader, download_file - - -class UGithubDownloadTestCase(unittest.TestCase): - def test_file(self): - repo = 'honey-team/ufpy' - file = 'README.md' - - download_path = '/usr/ufpy-tests' - file_path = f'{download_path}/README.md' - - # mkdir(download_path) - - # download_file() - download_file(repo, file, download_path) - - with open(file_path, 'r') as f: - file_contents1 = f.read() - - remove(file_path) - - # file() - ufpy.github.download.file(repo, file, download_path) - - with open(file_path, 'r') as f: - file_contents2 = f.read() - - remove(file_path) - - # UGithubDownloader.download_file() - with UGithubDownloader(repo, download_path) as gd: - gd.download_file(file) - - with open(file_path, 'r') as f: - file_contents3 = f.read() - - remove(file_path) - - # Asserts - self.assertEqual(file_contents1, file_contents2) - self.assertEqual(file_contents1, file_contents3) - self.assertEqual(file_contents2, file_contents3) - - -if __name__ == '__main__': - unittest.main() From ed6fa86996fee8bc3d7badd2d895d5581e82e754 Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 15:14:09 +0300 Subject: [PATCH 25/31] fix things from review --- examples/github/download.md | 16 ++++++++-------- ufpy/github/download.py | 13 +++---------- ufpy/path/files.py | 4 ---- 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/examples/github/download.md b/examples/github/download.md index abca026..2a7ae61 100644 --- a/examples/github/download.md +++ b/examples/github/download.md @@ -1,12 +1,12 @@ -# Github / Download +# GitHub / Download ## Introduction In `ufpy` there are 3 functions and 1 class for downloading things from public GitHub repositories. -You can without GitHub token download all repository, folder or several folders, and file or several -files. You can use `UGithubDownloader` class for all this actions or other 3 functions. Class is more -optimized for multi-requesting. If you want to download anything several times: use it. He is using 1] -unpacked zip archive for all operations and by the end deletes it. If you don't want to download anything +You can download an entire repository, a folder or multiple folders, and a file or multiple files without +a GitHub token. You can use the `UGithubDownloader` class for all these actions or the other 3 functions. +The class is more optimized for multiple requests. If you need to download multiple times, use it. It uses +an unpacked zip archive for all operations and deletes it at the end. If you don't want to download anything several times -> use functions. Import functions and class from `ufpy`: @@ -24,8 +24,8 @@ For opening this class you should use `with` operator as you do with files and o ```python with UGithubDownloader("honey-team/ufpy", "C:/Ufpy-Test", "0.1") as gd: # First argument - "repository owner"/"repository name" - # Second - Base download path (in all methods is using download paths from base download path. How in cmd - # for example: base path: C:\; cd ufpy -> final path: C:\ufpy.) (default is cwd (current working directory) + # Second - Base download path (all methods use download paths relative to the base download path, similar to how it works in the command line. + # For example: base path: C:\; cd ufpy -> final path: C:\ufpy.) (default is the current working directory) # Third argument: Branch or tag name (default is "main" (not master!)) gd.download_repo() # In C:/Ufpy-Test will appear all files from 0.1 tag in this repository. gd.download_repo("ufpy-0.1") # In C:/Ufpy-Test/ufpy-0.1 will appear all files from 0.1 tag in this repository @@ -38,7 +38,7 @@ You can use `download_file()` function, `ufpy.github.download.file()` function > [!NOTE] > You can use any iterable of strings in `download_file()` function for downloading several files. -> In `UGithubDownloader` there are `download_files()` method. +> In `UGithubDownloader` there is a `download_files()` method. One file: ```python diff --git a/ufpy/github/download.py b/ufpy/github/download.py index 8b72310..f51cef4 100644 --- a/ufpy/github/download.py +++ b/ufpy/github/download.py @@ -6,7 +6,6 @@ from zipfile import ZipFile from requests import get -from requests.exceptions import RequestException from ufpy.path import UOpen @@ -68,8 +67,8 @@ def __enter__(self): r = get(url) if not r.ok: - raise RequestException( - "Error with getting file from GitHub. Check that repo is public and that file path is correct.") + r.raise_for_status() + self.__zip = ZipFile(io.BytesIO(r.content)) temp_dir = format_paths(gettempdir()) @@ -83,11 +82,6 @@ def __exit__(self, exc_type, exc_val, exc_tb): if os.path.exists(self.__repo_path): rmtree(self.__repo_path) - def __del__(self): - self.__zip.close() - if os.path.exists(self.__repo_path): - rmtree(self.__repo_path) - def download_file(self, file_path: str, download_path: str = ''): file_path, download_path = format_paths(file_path, download_path) download_path = f'{self.__base_download_path}/{download_path}' @@ -96,8 +90,7 @@ def download_file(self, file_path: str, download_path: str = ''): r = get(url) if not r.ok: - raise RequestException( - "Error with getting file from GitHub. Check that repo is public and that file path is correct.") + r.raise_for_status() path = f'{download_path}/{file_path}' diff --git a/ufpy/path/files.py b/ufpy/path/files.py index 885a885..1a16445 100644 --- a/ufpy/path/files.py +++ b/ufpy/path/files.py @@ -25,10 +25,6 @@ def __enter__(self): def __exit__(self, exc_type, exc_val, exc_tb): self.__f.close() - def __del__(self): - if self.__f and not self.__f.closed: - self.__f.close() - def write(self, data: AnyStr): self.__f.write(data) From 14cf5418fd1fdb5dfdfb45020bb4ade7e704e344 Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 15:30:07 +0300 Subject: [PATCH 26/31] =?UTF-8?q?fix=20things=20from=20review=20=E2=84=962?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/github/download.md | 16 ++++++++-------- setup.py | 6 +++--- ufpy/github/download.py | 8 +++----- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/examples/github/download.md b/examples/github/download.md index 2a7ae61..f9b00de 100644 --- a/examples/github/download.md +++ b/examples/github/download.md @@ -7,7 +7,7 @@ You can download an entire repository, a folder or multiple folders, and a file a GitHub token. You can use the `UGithubDownloader` class for all these actions or the other 3 functions. The class is more optimized for multiple requests. If you need to download multiple times, use it. It uses an unpacked zip archive for all operations and deletes it at the end. If you don't want to download anything -several times -> use functions. +multiple times, use the functions instead. Import functions and class from `ufpy`: ```python @@ -20,7 +20,7 @@ from ufpy import UGithubDownloader, download_file, download_folder, download_rep ## Open `UGithubDownloader` class and use it -For opening this class you should use `with` operator as you do with files and other things: +To open this class, you should use the `with` operator as you do with files and other resources: ```python with UGithubDownloader("honey-team/ufpy", "C:/Ufpy-Test", "0.1") as gd: # First argument - "repository owner"/"repository name" @@ -34,16 +34,16 @@ with UGithubDownloader("honey-team/ufpy", "C:/Ufpy-Test", "0.1") as gd: ## Download file(s) You can use `download_file()` function, `ufpy.github.download.file()` function -(they're same, but with different names) and `UGithubDownloader.download_file()` method. +(they're the same, but with different names) and `UGithubDownloader.download_file()` method. > [!NOTE] > You can use any iterable of strings in `download_file()` function for downloading several files. -> In `UGithubDownloader` there is a `download_files()` method. +> In `UGithubDownloader`, there is a `download_files()` method. One file: ```python download_file("honey-team/ufpy", "README.md", "C:/Users//ufpy-tests") -# copy README.md from main branch in C:/Users//ufpy-tests directory +# copy README.md from the main branch to the C:/Users//ufpy-tests directory with UGithubDownloader("honey-team/ufpy", "C:/Users//ufpy-tests") as gd: gd.download_file("README.md") # Same @@ -76,7 +76,7 @@ You can use `download_folder()` function, `ufpy.github.download.folder()` functi One folder: ```python download_folder("honey-team/ufpy", "examples", "C:/Users//ufpy-tests") -# create C:/Users//examples folder +# create the C:/Users//ufpy-tests/examples folder # and copy origin/examples contents from main branch in this folder with UGithubDownloader("honey-team/ufpy", "C:/Users//ufpy-tests") as gd: @@ -89,7 +89,7 @@ After changing `` to your username and running this code you'll get this: Two folders: ```python download_folder("honey-team/ufpy", ["examples", ".github"], "C:/Users//ufpy-tests") -# create C:/Users//examples and C:/Users//.github folders +# create C:/Users//ufpy-tests/examples and C:/Users//ufpy-tests/.github folders # and copy origin/examples contents and origin/.github contents from main branch in this folders with UGithubDownloader("honey-team/ufpy", "C:/Users//ufpy-tests") as gd: @@ -114,7 +114,7 @@ with UGithubDownloader("honey-team/ufpy", "C:/Users//ufpy-tests") as gd: After changing `` to your username and running this code you'll get this: > [!NOTE] -> Repository code is code before merging this pull request +> The repository code shown is from before merging this pull request > ([#37](https://github.com/honey-team/ufpy/pull/37)). > When this pull request was merged, repository was changed. diff --git a/setup.py b/setup.py index 08652f8..a8db12c 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ project_name = 'ufpy' github_url = f'https://github.com/{organization_name}/{project_name}' -def _package(name: str) -> str: +def __package(name: str) -> str: return f'{project_name}.{name}' setup( @@ -29,8 +29,8 @@ def _package(name: str) -> str: url=github_url, packages=[ project_name, - _package('typ'), - _package('github'), + __package('typ'), + __package('github'), ], classifiers=[ 'Programming Language :: Python :: 3', diff --git a/ufpy/github/download.py b/ufpy/github/download.py index f51cef4..f064f45 100644 --- a/ufpy/github/download.py +++ b/ufpy/github/download.py @@ -2,7 +2,7 @@ import os from shutil import copy, copytree, rmtree from tempfile import gettempdir -from typing import Iterable, TypeAlias +from typing import Iterable from zipfile import ZipFile from requests import get @@ -52,19 +52,17 @@ def format_paths(*paths: str | list[str]) -> str | list[str] | list[list[str]]: return new_paths[0] if len(new_paths) <= 1 else new_paths -CWD: TypeAlias = None +CWD = os.getcwd() class UGithubDownloader: def __init__(self, repo: str, base_download_path: str = CWD, branch_name: str = 'main'): - if base_download_path == CWD: - base_download_path = format_paths(os.getcwd()) self.__repo = repo self.__base_download_path = format_paths(base_download_path) self.__branch = branch_name def __enter__(self): url = f'https://github.com/{self.__repo}/archive/{self.__branch}.zip' - r = get(url) + r = get(url, timeout=10) if not r.ok: r.raise_for_status() From 44441dd427cd608ea79a28723c4bb14428adc456 Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 15:38:17 +0300 Subject: [PATCH 27/31] =?UTF-8?q?fix=20things=20from=20review=20=E2=84=963?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/github/download.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/github/download.md b/examples/github/download.md index f9b00de..8b98124 100644 --- a/examples/github/download.md +++ b/examples/github/download.md @@ -77,7 +77,7 @@ One folder: ```python download_folder("honey-team/ufpy", "examples", "C:/Users//ufpy-tests") # create the C:/Users//ufpy-tests/examples folder -# and copy origin/examples contents from main branch in this folder +# and copy the contents of origin/examples from the main branch into this folder with UGithubDownloader("honey-team/ufpy", "C:/Users//ufpy-tests") as gd: gd.download_folder("examples") # Same @@ -90,7 +90,7 @@ Two folders: ```python download_folder("honey-team/ufpy", ["examples", ".github"], "C:/Users//ufpy-tests") # create C:/Users//ufpy-tests/examples and C:/Users//ufpy-tests/.github folders -# and copy origin/examples contents and origin/.github contents from main branch in this folders +# and copy origin/examples contents and origin/.github contents from main branch in these folders with UGithubDownloader("honey-team/ufpy", "C:/Users//ufpy-tests") as gd: gd.download_folders(["examples", ".github"]) # Same @@ -114,8 +114,8 @@ with UGithubDownloader("honey-team/ufpy", "C:/Users//ufpy-tests") as gd: After changing `` to your username and running this code you'll get this: > [!NOTE] -> The repository code shown is from before merging this pull request -> ([#37](https://github.com/honey-team/ufpy/pull/37)). +> The repository code shown reflects the state before merging pull request +> [#37](https://github.com/honey-team/ufpy/pull/37). > When this pull request was merged, repository was changed. ![Download all repository](.assets/download5.png) From 01322899d23e7320dd995e1da321dd04bf63d37c Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 15:44:02 +0300 Subject: [PATCH 28/31] =?UTF-8?q?fix=20things=20from=20review=20=E2=84=964?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/github/download.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/github/download.md b/examples/github/download.md index 8b98124..5859ede 100644 --- a/examples/github/download.md +++ b/examples/github/download.md @@ -12,7 +12,7 @@ multiple times, use the functions instead. Import functions and class from `ufpy`: ```python import ufpy -from ufpy import UGithubDownloader, download_file, download_folder, download_repo, UGithubDownloader +from ufpy import UGithubDownloader, download_file, download_folder, download_repo ``` > [!CAUTION] @@ -67,7 +67,7 @@ After changing `` to your username and running this code you'll get this: ## Download folder(s) You can use `download_folder()` function, `ufpy.github.download.folder()` function -(they're same, but with different names) and `UGithubDownloader.download_folder()` method. +(they're the same, but with different names) and `UGithubDownloader.download_folder()` method. > [!NOTE] > You can use any iterable of strings in `download_folder()` function for downloading several folders. @@ -102,10 +102,11 @@ After changing `` to your username and running this code you'll get this: ## Download all repository You can use `download_repo()` function, `ufpy.github.download.repo()` function -(they're same, but with different names) and `UGithubDownloader.download_repo()` method: +(they're the same, but with different names) and `UGithubDownloader.download_repo()` method: ```python download_repo("honey-team/ufpy", "C:/Users//ufpy-tests") -# copy all repository files and folders with its contents from main branch in C:/Users//ufpy-tests directory. +# copy all files and folders from the repository along with their contents +# from the main branch to the C:/Users//ufpy-tests directory. with UGithubDownloader("honey-team/ufpy", "C:/Users//ufpy-tests") as gd: gd.download_repo() # Same From edd5dfb397833405422a5b4e718d72b411567ac0 Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 15:54:08 +0300 Subject: [PATCH 29/31] =?UTF-8?q?fix=20things=20from=20review=20=E2=84=965?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/github/download.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/github/download.md b/examples/github/download.md index 5859ede..a4da0ff 100644 --- a/examples/github/download.md +++ b/examples/github/download.md @@ -37,7 +37,7 @@ You can use `download_file()` function, `ufpy.github.download.file()` function (they're the same, but with different names) and `UGithubDownloader.download_file()` method. > [!NOTE] -> You can use any iterable of strings in `download_file()` function for downloading several files. +> You can use any iterable of strings in the `download_file()` function to download several files. > In `UGithubDownloader`, there is a `download_files()` method. One file: @@ -71,7 +71,7 @@ You can use `download_folder()` function, `ufpy.github.download.folder()` functi > [!NOTE] > You can use any iterable of strings in `download_folder()` function for downloading several folders. -> In `UGithubDownloader` there are `download_folders()` method. +> In `UGithubDownloader`, there is a `download_folders()` method. One folder: ```python @@ -117,6 +117,6 @@ After changing `` to your username and running this code you'll get this: > [!NOTE] > The repository code shown reflects the state before merging pull request > [#37](https://github.com/honey-team/ufpy/pull/37). -> When this pull request was merged, repository was changed. +> When this pull request was merged, the repository was changed. ![Download all repository](.assets/download5.png) From 5839eaa2606ebca42f164ac80206f8d6ad47d8f9 Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 16:03:59 +0300 Subject: [PATCH 30/31] =?UTF-8?q?fix=20things=20from=20review=20=E2=84=966?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/github/download.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/examples/github/download.md b/examples/github/download.md index a4da0ff..5542eda 100644 --- a/examples/github/download.md +++ b/examples/github/download.md @@ -23,12 +23,11 @@ from ufpy import UGithubDownloader, download_file, download_folder, download_rep To open this class, you should use the `with` operator as you do with files and other resources: ```python with UGithubDownloader("honey-team/ufpy", "C:/Ufpy-Test", "0.1") as gd: - # First argument - "repository owner"/"repository name" - # Second - Base download path (all methods use download paths relative to the base download path, similar to how it works in the command line. + # First argument: "repository owner"/"repository name" + # Second: Base download path (all methods use download paths relative to the base download path, similar to how it works in the command line. # For example: base path: C:\; cd ufpy -> final path: C:\ufpy.) (default is the current working directory) # Third argument: Branch or tag name (default is "main" (not master!)) - gd.download_repo() # In C:/Ufpy-Test will appear all files from 0.1 tag in this repository. - gd.download_repo("ufpy-0.1") # In C:/Ufpy-Test/ufpy-0.1 will appear all files from 0.1 tag in this repository + gd.download_repo() # All files from the 0.1 tag in this repository will appear in C:/Ufpy-Test. ``` ## Download file(s) @@ -49,7 +48,7 @@ with UGithubDownloader("honey-team/ufpy", "C:/Users//ufpy-tests") as gd: gd.download_file("README.md") # Same ``` -After changing `` to your username and running this code you'll get this: +After changing `` to your username and running this code you'll get the following result: ![Download one file](.assets/download1.png) Two files: @@ -61,7 +60,7 @@ with UGithubDownloader("honey-team/ufpy", "C:/Users//ufpy-tests") as gd: gd.download_files(["README.md", "mkdocs.yml"]) # Same ``` -After changing `` to your username and running this code you'll get this: +After changing `` to your username and running this code you'll get the following result: ![Download two files](.assets/download2.png) ## Download folder(s) @@ -83,7 +82,7 @@ with UGithubDownloader("honey-team/ufpy", "C:/Users//ufpy-tests") as gd: gd.download_folder("examples") # Same ``` -After changing `` to your username and running this code you'll get this: +After changing `` to your username and running this code you'll get the following result: ![Download one folder](.assets/download3.png) Two folders: @@ -96,7 +95,7 @@ with UGithubDownloader("honey-team/ufpy", "C:/Users//ufpy-tests") as gd: gd.download_folders(["examples", ".github"]) # Same ``` -After changing `` to your username and running this code you'll get this: +After changing `` to your username and running this code you'll get the following result: ![Download two folders](.assets/download4.png) ## Download all repository @@ -112,7 +111,7 @@ with UGithubDownloader("honey-team/ufpy", "C:/Users//ufpy-tests") as gd: gd.download_repo() # Same ``` -After changing `` to your username and running this code you'll get this: +After changing `` to your username and running this code you'll get the following result: > [!NOTE] > The repository code shown reflects the state before merging pull request From e651a4e261f25a844d8f9ed2c201e76d7205e502 Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 29 Jun 2024 16:11:37 +0300 Subject: [PATCH 31/31] =?UTF-8?q?fix=20things=20from=20review=20=E2=84=967?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/github/download.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/github/download.md b/examples/github/download.md index 5542eda..8ca1ea6 100644 --- a/examples/github/download.md +++ b/examples/github/download.md @@ -2,7 +2,7 @@ ## Introduction -In `ufpy` there are 3 functions and 1 class for downloading things from public GitHub repositories. +In `ufpy` there are 3 functions and 1 class for downloading resources from public GitHub repositories. You can download an entire repository, a folder or multiple folders, and a file or multiple files without a GitHub token. You can use the `UGithubDownloader` class for all these actions or the other 3 functions. The class is more optimized for multiple requests. If you need to download multiple times, use it. It uses @@ -98,7 +98,7 @@ with UGithubDownloader("honey-team/ufpy", "C:/Users//ufpy-tests") as gd: After changing `` to your username and running this code you'll get the following result: ![Download two folders](.assets/download4.png) -## Download all repository +## Download the entire repository You can use `download_repo()` function, `ufpy.github.download.repo()` function (they're the same, but with different names) and `UGithubDownloader.download_repo()` method: