Skip to content
This repository has been archived by the owner on Oct 27, 2024. It is now read-only.

Improve loadingbar types and merge all types in one file #12

Merged
merged 6 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/install/filesize.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# Copyright (C) Martijn Faassen, Startifact
# <https://pypi.org/project/hurry.filesize/>

from ._types import SizeSystem
from ..typings import SizeSystem

traditional: SizeSystem = [
(1024 ** 5, 'P'),
Expand Down
121 changes: 86 additions & 35 deletions src/install/loadingbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,66 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.

from os import get_terminal_size
from typing import Collection, Generic, Literal, TypeVar, Optional, Type
from types import TracebackType
from typing import (
Collection, Generic, Literal, TypeVar,
Optional, overload, TYPE_CHECKING
)

if TYPE_CHECKING:
from types import TracebackType

from .filesize import size, traditional

T = TypeVar("T")
_T = TypeVar("_T")


class loadingbar(Generic[_T]):
@overload
def __init__(
# total
self, iterator: Collection[_T], /, *,
unit: Literal['it', 'B'] = 'it',
bar_length: Optional[int] = None,
bar_format: str = "{title} {percentage:3.0f}% [{bar}] {current}/{total}",
title: str = '',
show_desc: bool = False,
desc: str = '',
disappear: bool = False,
) -> None: ...

@overload
def __init__(
# total
self, /, *,
total: _T,
unit: Literal['it', 'B'] = 'it',
bar_length: Optional[int] = None,
bar_format: str = "{title} {percentage:3.0f}% [{bar}] {current}/{total}",
title: str = '',
show_desc: bool = False,
desc: str = '',
disappear: bool = False,
) -> None: ...

class loadingbar(Generic[T]):
@overload
def __init__(
self, iterator: Collection[T] | None = None, /, *,
# both
self, iterator: Optional[Collection[_T]] = None, /, *,
total: int = 0,
unit: Literal['it', 'B'] = 'it',
bar_length: int | None = None,
bar_length: Optional[int] = None,
bar_format: str = "{title} {percentage:3.0f}% [{bar}] {current}/{total}",
title: str = '',
show_desc: bool = False,
desc: str = '',
disappear: bool = False,
) -> None: ...

def __init__(
self, iterator: Optional[Collection[_T]] = None, /, *,
total: int | _T = 0,
unit: Literal['it', 'B'] = 'it',
bar_length: Optional[int] = None,
bar_format: str = "{title} {percentage:3.0f}% [{bar}] {current}/{total}",
title: str = '',
show_desc: bool = False,
Expand All @@ -54,21 +100,18 @@ def __init__(
:param disappear: If you want the bar to disappear
"""

# Define class variables
self._iter_type: Literal['iter', 'total', 'both']

if iterator is not None and total == 0:
self._iter_type = 'iter'
# iter
self.iterator = iterator
self.iterable = iter(iterator)
self.iterator_len = len(iterator)
elif iterator is None and total != 0:
self._iter_type = 'total'
# total
self.iterator = None
self.iterable = None
self.total = total
elif iterator is not None and total != 0:
self._iter_type = 'both'
# both
self.iterator = iterator
self.iterable = iter(iterator)
self.iterator_len = len(iterator)
Expand Down Expand Up @@ -112,40 +155,44 @@ def __init__(
else:
self.bar_length = bar_length

def __iter__(self) -> "loadingbar[T]":
def __iter__(self) -> "loadingbar[_T]":
"Method that allows iterators"

return self

def __next__(self) -> T:
def __next__(self) -> _T:
"Go to the next iteration"

# Update the item and idx
if self.iterable is not None:
self.item = next(self.iterable)
self.idx += 1
elif self.idx < self.total: # 'total'
self.idx += 1
else:
raise StopIteration
if TYPE_CHECKING and not isinstance(self.total, int):
raise TypeError

if self.idx < self.total: # total
self.idx += 1
else:
raise StopIteration

# Refresh the loading bar
self.refresh()

# Return the item
if self.iterator is not None: # 'both' or 'iter'
if self.iterator is not None: # both or iter
return self.item
else:
return self.idx # type: ignore

def __enter__(self) -> "loadingbar[T]":
def __enter__(self) -> "loadingbar[_T]":
"Allow a with-as statement"

return self

def __exit__(self, exc_type: Optional[Type[BaseException]],
def __exit__(self, exc_type: Optional[type[BaseException]],
exc_value: Optional[BaseException],
traceback: Optional[TracebackType]) -> bool:
traceback: Optional['TracebackType']) -> bool:
"Allow a with-as statement"

return False # No errors
Expand All @@ -154,7 +201,10 @@ def refresh(self) -> None:
"Refresh the loading bar, called automatically"

# Calculate progress
if self._iter_type in ('both', 'total'):
if hasattr(self, 'total'): # both, total
if TYPE_CHECKING and not isinstance(self.total, int):
raise TypeError

percent = round(self.idx / self.total * 100, 0)
else:
percent = round(self.idx / self.iterator_len * 100, 0)
Expand All @@ -165,12 +215,16 @@ def refresh(self) -> None:
# Define the current and total
if self.unit == 'it':
current = str(self.idx)
total = str(self.total if self._iter_type in (
'both', 'total') else self.iterator_len)
total = str(self.total if hasattr(
self, 'total') else self.iterator_len)
else:
current = size(self.idx, traditional)
total = size(self.total if self._iter_type in (
'both', 'total') else self.iterator_len, traditional)
arg = self.total if hasattr(self, 'total') else self.iterator_len

if TYPE_CHECKING and not isinstance(arg, int):
raise TypeError

total = size(arg, traditional)

# Define the text length
text_length = self.formatting_length + \
Expand All @@ -181,12 +235,10 @@ def refresh(self) -> None:
# Print the loading bar
start = '\033[F\r' if self.show_desc else '\r'

if self.show_desc and self._new_desc:
end = '\n\033[K' + self.desc
elif self.show_desc:
end = '\n' + self.desc
else:
end = ''
end = (
'\n\033[K' + self.desc if self.show_desc and self._new_desc
else '\n' + self.desc if self.show_desc else ''
)

print(start + self.bar_format.format(
title=self.title,
Expand All @@ -197,8 +249,7 @@ def refresh(self) -> None:
), end=end)

# Clear the loading bar at the end
if self.idx == (self.total if self._iter_type in (
'both', 'total') else self.iterator_len):
if self.idx == (self.total if hasattr(self, 'total') else self.iterator_len):
if self.disappear and self.show_desc:
print('\r\033[K\033[F\r\033[K', end='')
elif self.disappear:
Expand All @@ -208,7 +259,7 @@ def refresh(self) -> None:

def update(self, amount: int) -> None:
"Add 'n' amount of iterations to the loading bar"
if self._iter_type == 'iter':
if not hasattr(self, 'total'):
i = 0

# Call next(self) while less than amount
Expand Down
6 changes: 3 additions & 3 deletions src/install/media.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from .modloaders import inst_modloader, MINECRAFT_DIR
from .filesize import size, alternative

from ._types import Manifest, URLMedia, Media, MediaList, Side
from ..typings import Manifest, URLMedia, Media, MediaList, Side


class prepare:
Expand Down Expand Up @@ -218,7 +218,6 @@ def download_files(total_size: int, install_path: str, side: Side, manifest: Man
show_desc=True,
disappear=True
) as bar:
bar: loadingbar[int] # The only way it worked out
for url, fname, fsize, sides in iterator:
if side not in sides:
# As the size isn't calculated, it
Expand Down Expand Up @@ -307,7 +306,8 @@ def install(

# Print the mod info
print(
f"\n{len(mods)} mods, {len(resourcepacks)} recourcepacks, {len(shaderpacks)} shaderpacks\n"
f"\n{len(mods)} mods, {len(resourcepacks)} "
f"recourcepacks, {len(shaderpacks)} shaderpacks\n"
f"Total file size: {size(total_size, system=alternative)}"
)

Expand Down
62 changes: 20 additions & 42 deletions src/install/modloaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.

from atexit import register
from http.client import HTTPResponse
from json import load, loads, dump
from os import path, getenv, mkdir, rename
from shutil import rmtree, copyfile
Expand All @@ -24,16 +25,16 @@
from urllib import request
from zipfile import ZipFile

from .urls import forge as forge_urls, fabric as fabric_urls
from .loadingbar import loadingbar
from .urls import forge as forge_urls

from ..common.maven_coords import maven_parse

from ._types import (
from ..typings import (
Client, Server, Side, Modloader,
MinecraftJson, VersionJson,
ForgeLibrary, ForgeVersionJson,
InstallProfile, Libraries,
Library, OSLibrary
MinecraftJson, OSLibrary
)

# Define the minecraft directory
Expand Down Expand Up @@ -105,13 +106,14 @@ def __init__(self, mc_version: str,
"Please make sure you have Java installed and it is properly configured."
)

self.minecraft_json: MinecraftJson = loads(request.urlopen(
[item for item in loads(
request.urlopen(
forge_urls.version_manifest_v2
).read().decode('utf-8')
)['versions'] if item['id'] == mc_version][0]['url']
).read().decode('utf-8'))
v_man_v2: HTTPResponse = request.urlopen(
forge_urls.version_manifest_v2)

for item in loads(v_man_v2.read().decode('utf-8'))['versions']:
if item['id'] == mc_version:
_res: HTTPResponse = request.urlopen(item['url'])
self.minecraft_json: MinecraftJson = loads(
_res.read().decode('utf-8'))

# Exit if the launcher hasn't launched once
if not path.isfile(path.join(launcher_dir, 'launcher_profiles.json')) and side == 'client':
Expand All @@ -127,7 +129,7 @@ def __init__(self, mc_version: str,
with archive.open('install_profile.json') as fp:
self.install_profile: InstallProfile = load(fp)
with archive.open('version.json') as fp:
self.version_json: VersionJson = load(fp)
self.version_json: ForgeVersionJson = load(fp)

# Define the forge dir
forge_dir = path.join(
Expand Down Expand Up @@ -203,8 +205,10 @@ def download_jar_files(self) -> None:

if self.side == 'client':
# Make the required directories
for directory in [path.join(self.launcher_dir, 'versions'),
path.join(self.launcher_dir, 'versions', self.mc_version)]:
for directory in [
path.join(self.launcher_dir, 'versions'),
path.join(self.launcher_dir, 'versions', self.mc_version)
]:
if not path.isdir(directory):
mkdir(directory)

Expand All @@ -227,7 +231,7 @@ def download_jar_files(self) -> None:
break
mod_file.write(resp_data)

def download_library(self, bar: loadingbar[Library | OSLibrary], library: Library) -> None:
def download_library(self, bar: loadingbar[ForgeLibrary | OSLibrary], library: ForgeLibrary) -> None:
"""Download a library"""
# Define the java os names
osdict = {
Expand Down Expand Up @@ -384,33 +388,7 @@ def build_processors(self) -> None:


class fabric:
"I accidentally uploaded this, it's unfinished"

def __init__(self, mc_version: str,
fabric_version: str,
side: Side,
install_dir: str = MINECRAFT_DIR,
launcher_dir: str = MINECRAFT_DIR) -> None:

self.mc_version = mc_version

# Define the class variables
launcher_dir = install_dir if side == 'server' else launcher_dir

self.mc_version = mc_version
self.fabric_version = fabric_version
self.side = side
self.install_dir = install_dir
self.launcher_dir = launcher_dir

self.install_version()

def install_version(self):
print(request.urlopen(fabric_urls.api_url(
'v2', 'versions', 'loader',
self.mc_version, self.fabric_version,
'server', 'json'
)).read().decode('utf-8'))
pass


def inst_modloader(
Expand Down
8 changes: 1 addition & 7 deletions src/install/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

from ._types import Media
from ..typings import Media


def media_url(media: Media) -> str:
Expand Down Expand Up @@ -44,9 +44,3 @@ class forge:
def forge_installer_url(mc_version: str, forge_version: str) -> str:
return "https://maven.minecraftforge.net/net/minecraftforge/forge/" \
f"{mc_version}-{forge_version}/forge-{mc_version}-{forge_version}-installer.jar"


class fabric:
@staticmethod
def api_url(*paths: str) -> str:
return "https://meta.fabricmc.net/" + '/'.join(paths)
Loading