Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
async def test_resolve_wowi_pkgs(manager):
results = await manager.resolve(
[Defn('wowi', '13188-molinari'), Defn('wowi', '13188', Strategies.latest)]
)
either, invalid = results.values()
assert isinstance(either, Pkg)
assert (
isinstance(invalid, E.PkgStrategyUnsupported)
and invalid.message == "'latest' strategy is not valid for source"
)
async def test_resolve_curse_simple_pkgs(manager, request, strategy):
results = await manager.resolve(
[
Defn('curse', 'tomcats', strategy),
Defn('curse', 'mythic-dungeon-tools', strategy),
Defn('curse', 'classiccastbars', strategy),
Defn('curse', 'elkbuffbars', strategy),
]
)
separate, retail_only, classic_only, flavour_explosion = results.values()
assert isinstance(separate, Pkg)
if manager.config.is_classic:
if strategy is Strategies.any_flavour:
assert 'classic' not in separate.version
assert isinstance(retail_only, Pkg)
else:
assert 'classic' in separate.version
assert (
isinstance(retail_only, E.PkgFileUnavailable)
and retail_only.message
== f"no files compatible with classic using '{strategy.name}' strategy"
)
assert isinstance(classic_only, Pkg)
else:
assert 'classic' not in separate.version
assert isinstance(retail_only, Pkg)
if strategy is Strategies.any_flavour:
assert isinstance(classic_only, Pkg)
else:
def supports_rollback(self) -> bool:
"Whether the resolver supports rollback operations."
return Strategies.version in self.strategies
v.startswith(classic_version_prefix) is self.config.is_classic
for v in f['gameVersion']
)
# 1 = stable; 2 = beta; 3 = alpha
if defn.strategy is Strategies.latest:
def is_of_specified_quality(f: JsonDict):
return True
elif defn.strategy is Strategies.curse_latest_beta:
def is_of_specified_quality(f: JsonDict):
return f['releaseType'] == 2
elif defn.strategy is Strategies.curse_latest_alpha:
def is_of_specified_quality(f: JsonDict):
return f['releaseType'] == 3
else:
def is_of_specified_quality(f: JsonDict):
return f['releaseType'] == 1
def is_compatible(f: JsonDict):
return (
is_not_libless(f) and supports_game_version(f) and is_of_specified_quality(f)
)
if not files:
raise E.PkgFileUnavailable('no files available for download')
async def resolve_one(self, defn: Defn, metadata: O[JsonDict] = None) -> m.Pkg:
"Resolve an individual definition into a package."
raise NotImplementedError
async def collect_items(self) -> AsyncIterable[_CItem]:
"Yield add-ons from source for cataloguing."
return
yield
class CurseResolver(Resolver):
source = 'curse'
name = 'CurseForge'
strategies = {
Strategies.default,
Strategies.latest,
Strategies.curse_latest_beta,
Strategies.curse_latest_alpha,
Strategies.any_flavour,
Strategies.version,
}
# Reference: https://twitchappapi.docs.apiary.io/
addon_api_url = URL('https://addons-ecs.forgesvc.net/api/v2/addon')
@staticmethod
def get_name_from_url(value: str) -> O[str]:
url = URL(value)
if url.host == 'www.wowace.com' and len(url.parts) > 2 and url.parts[1] == 'projects':
return url.parts[2].lower()
elif (
url.host == 'www.curseforge.com'
type=(_EnumParam(Strategies, excluded_strategies), str),
callback=_combine_into('addons', parse_into_defn_with_strategy),
expose_value=False,
metavar='...',
help='A strategy followed by an add-on definition. '
'The strategies are: '
f'{", ".join(s.name for s in Strategies if s not in excluded_strategies)}.',
)
@click.option(
'--version',
multiple=True,
type=(str, str),
callback=_combine_into('addons', parse_into_defn_with_version),
expose_value=False,
metavar='...',
help='A version followed by an add-on definition.',
)
json_response = await response.json()
for item in json_response:
yield _CItem(
source=self.source,
id=item['UID'],
name=item['UIName'],
folders=[item['UIDir']],
compatibility={'retail', 'classic'},
)
class TukuiResolver(Resolver):
source = 'tukui'
name = 'Tukui'
strategies = {Strategies.default}
api_url = URL('https://www.tukui.org/api.php')
retail_uis = {'-1': 'tukui', '-2': 'elvui', 'tukui': 'tukui', 'elvui': 'elvui'}
@staticmethod
def get_name_from_url(value: str) -> O[str]:
url = URL(value)
if url.host == 'www.tukui.org' and url.path in {
'/addons.php',
'/classic-addons.php',
'/download.php',
}:
name = url.query.get('id') or url.query.get('ui')
if name:
return name
JsonDict = Dict[str, Any]
class Strategies(enum.Enum):
default = enum.auto()
latest = enum.auto()
curse_latest_beta = enum.auto()
curse_latest_alpha = enum.auto()
any_flavour = enum.auto()
version = enum.auto()
class Defn(NamedTuple):
source: str
name: str
strategy: Strategies = Strategies.default
strategy_vals: Tuple[str, ...] = ()
source_id: O[str] = None
@classmethod
def from_pkg(cls, pkg: m.Pkg) -> Defn:
strategy = Strategies[pkg.options.strategy]
strategy_vals = (pkg.version,) if strategy is Strategies.version else ()
return cls(pkg.source, pkg.slug, strategy, strategy_vals, pkg.id)
def with_name(self, name: str) -> Defn:
return self.__class__(self.source, name, self.strategy, self.strategy_vals, self.source_id)
def with_strategy(self, strategy: Strategies) -> Defn:
return self.__class__(self.source, self.name, strategy, (), self.source_id)
def with_version(self, version: str) -> Defn:
)
def is_compatible(f: JsonDict):
return defn.strategy_vals[0] == f['displayName']
else:
files = metadata['latestFiles']
def is_not_libless(f: JsonDict):
# There's also an 'isAlternate' field that's missing from some
# 50 lib-less files from c. 2008. 'exposeAsAlternative' is
# absent from the /file endpoint
return not f['exposeAsAlternative']
if defn.strategy is Strategies.any_flavour:
def supports_game_version(f: JsonDict):
return True
else:
classic_version_prefix = '1.13'
flavour = 'wow_classic' if self.config.is_classic else 'wow_retail'
def supports_game_version(f: JsonDict):
# Files can belong both to retail and classic
# but ``gameVersionFlavor`` can only be one of
# 'wow_retail' or 'wow_classic'. To spice things up,
# ``gameVersion`` might not be populated so we still have to
# check the value of ``gameVersionFlavor``
return f['gameVersionFlavor'] == flavour or any(
v.startswith(classic_version_prefix) is self.config.is_classic
def parse_into_defn_from_json_file(manager: CliManager, path: Path) -> List[Defn]:
faux_pkgs = models.MultiPkgModel.parse_file(path, encoding='utf-8')
return list(map(Defn.from_pkg, cast('List[models.Pkg]', faux_pkgs.__root__)))
def _combine_into(param_name: str, fn: Callable[[CliManager, Any], List[Any]]):
def combine(ctx: click.Context, _param: click.Parameter, value: Any):
# Add param by ``param_name`` to param dict regardless of output
param = ctx.params.setdefault(param_name, [])
if value:
param.extend(fn(ctx.obj.m, value))
return combine
excluded_strategies = {Strategies.default, Strategies.version}
@main.command()
@click.argument(
'addons', nargs=-1, callback=_combine_into('addons', parse_into_defn), expose_value=False
)
@click.option(
'--import',
'-i',
type=_PathParam(dir_okay=False, exists=True),
callback=_combine_into('addons', parse_into_defn_from_json_file),
expose_value=False,
help='Install add-ons from the output of `list -f json`.',
)
@click.option(
'--with-strategy',