Skip to content

Commit

Permalink
refactor: move to dataclassy (#14)
Browse files Browse the repository at this point in the history
* chore: add dataclassy as dependency

* refactor: upgrade to dataclassy and other small improvements

* refactor: create manager object instead of working with globals

* test: add integration tests

* feat: add ability to print and search tokens. clean up output

* fix: forgot click dependency
  • Loading branch information
fubuloubu committed Jul 15, 2021
1 parent c97874c commit 912a99e
Show file tree
Hide file tree
Showing 10 changed files with 247 additions and 128 deletions.
7 changes: 6 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,12 @@
long_description_content_type="text/markdown",
url="https://github.com/ApeWorX/py-tokenlists",
packages=find_packages(exclude=["tests", "tests.*"]),
install_requires=["semantic-version>=2.8.5,<3", "pyyaml>=5.4.1,<6"],
install_requires=[
"click>=8.0.0",
"dataclassy>=0.10.3,<1.0",
"pyyaml>=5.4.1,<6",
"semantic-version>=2.8.5,<3",
],
entry_points={"console_scripts": ["tokenlists=tokenlists._cli:cli"]},
extras_require=extras_require,
classifiers=[
Expand Down
File renamed without changes.
File renamed without changes.
20 changes: 20 additions & 0 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from pathlib import Path

import pytest # type: ignore
from click.testing import CliRunner

from tokenlists import TokenListManager, _cli


@pytest.fixture
def runner(monkeypatch):
runner = CliRunner()
with runner.isolated_filesystem() as temp_dir:
monkeypatch.setattr(_cli, "TokenListManager", lambda: TokenListManager(Path(temp_dir)))
yield runner


@pytest.fixture
def cli(runner):
# NOTE: Depends on `runner` fixture for config side effects
yield _cli.cli
37 changes: 37 additions & 0 deletions tests/integration/test_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
TEST_URI = "tokens.1inch.eth"


def test_empty_list(runner, cli):
result = runner.invoke(cli, ["list"])
assert result.exit_code == 0
assert "No tokenlists exist" in result.output


def test_install(runner, cli):
result = runner.invoke(cli, ["list"])
assert result.exit_code == 0
assert "No tokenlists exist" in result.output

result = runner.invoke(cli, ["install", TEST_URI])
assert result.exit_code == 0

result = runner.invoke(cli, ["list"])
assert result.exit_code == 0
assert "1inch" in result.output


def test_remove(runner, cli):
result = runner.invoke(cli, ["install", TEST_URI])
assert result.exit_code == 0

result = runner.invoke(cli, ["list"])
assert result.exit_code == 0
assert "1inch" in result.output

result = runner.invoke(cli, ["remove", "1inch"])
assert result.exit_code == 0
assert result.exit_code == 0

result = runner.invoke(cli, ["list"])
assert result.exit_code == 0
assert "No tokenlists exist" in result.output
16 changes: 2 additions & 14 deletions tokenlists/__init__.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,8 @@
from .manager import (
available_token_lists,
default_token_list,
get_token_info,
get_token_list,
install_token_list,
set_default_token_list,
)
from .manager import TokenListManager
from .typing import TokenInfo, TokenList

__all__ = [
"TokenInfo",
"TokenList",
"install_token_list",
"set_default_token_list",
"available_token_lists",
"default_token_list",
"get_token_info",
"get_token_list",
"TokenListManager",
]
110 changes: 84 additions & 26 deletions tokenlists/_cli.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
import re

import click
import yaml

import tokenlists
from .manager import TokenListManager
from .typing import TokenSymbol


class TokenlistChoice(click.Choice):
def __init__(self, case_sensitive=True):
self.case_sensitive = case_sensitive

@property
def choices(self):
return list(TokenListManager().available_tokenlists())


@click.group()
Expand All @@ -11,38 +22,85 @@ def cli():
"""


@cli.command(short_help="Display the names and versions of all installed tokenlists")
def show_lists():
click.echo("Installed Token Lists:")
for token_list in map(tokenlists.get_token_list, tokenlists.available_token_lists()):
click.echo(f"- {token_list.name} (v{token_list.version})")
@cli.command(name="list", short_help="Display the names and versions of all installed tokenlists")
def _list():
manager = TokenListManager()

available_tokenlists = manager.available_tokenlists()
if available_tokenlists:
click.echo("Installed Token Lists:")
for tokenlist in map(manager.get_tokenlist, available_tokenlists):
click.echo(f"- {tokenlist.name} (v{tokenlist.version})")

@cli.command(short_help="Display the info for a particular token")
@click.argument("symbol", type=tokenlists.typing.TokenSymbol)
@click.option(
"--token-list",
type=click.Choice(tokenlists.available_token_lists()),
default=tokenlists.default_token_list(),
)
def token_info(symbol, token_list):
token_info = tokenlists.get_token_info(symbol, token_list)
click.echo(yaml.dump(token_info.to_dict()))


@cli.command(short_help="Install a new token list")
else:
click.echo("WARNING: No tokenlists exist!")


@cli.command(short_help="Install a new tokenlist")
@click.argument("uri")
def install(uri):
tokenlists.install_token_list(uri)
manager = TokenListManager()

manager.install_tokenlist(uri)


@cli.command(short_help="Remove an existing token list")
@click.argument("name", type=click.Choice(tokenlists.available_token_lists()))
@cli.command(short_help="Remove an existing tokenlist")
@click.argument("name", type=TokenlistChoice())
def remove(name):
tokenlists.uninstall_token_list(name)
manager = TokenListManager()

manager.remove_tokenlist(name)


@cli.command(short_help="Set the default tokenlist")
@click.argument("name", type=click.Choice(tokenlists.available_token_lists()))
@click.argument("name", type=TokenlistChoice())
def set_default(name):
tokenlists.set_default_token_list(name)
manager = TokenListManager()

manager.set_default_tokenlist(name)


@cli.command(short_help="Display the names and versions of all installed tokenlists")
@click.option("--search", default="")
@click.option("--tokenlist-name", type=TokenlistChoice(), default=None)
@click.option("--chain-id", default=1, type=int)
def list_tokens(search, tokenlist_name, chain_id):
manager = TokenListManager()

if not manager.default_tokenlist:
raise click.ClickException("No tokenlists available!")

pattern = re.compile(search or ".*")

for token_info in filter(
lambda t: pattern.match(t.symbol),
manager.get_tokens(tokenlist_name, chain_id),
):
click.echo("{address} ({symbol})".format(**token_info.to_dict()))


@cli.command(short_help="Display the info for a particular token")
@click.argument("symbol", type=TokenSymbol)
@click.option("--tokenlist-name", type=TokenlistChoice(), default=None)
@click.option("--case-insensitive", default=False, is_flag=True)
@click.option("--chain-id", default=1, type=int)
def token_info(symbol, tokenlist_name, chain_id, case_insensitive):
manager = TokenListManager()

if not manager.default_tokenlist:
raise click.ClickException("No tokenlists available!")

token_info = manager.get_token_info(symbol, tokenlist_name, chain_id, case_insensitive)

click.echo(
"""
Symbol: {symbol}
Name: {name}
Chain ID: {chainId}
Address: {address}
Decimals: {decimals}
Tags: {tags}
""".format(
tags=[], **token_info.to_dict()
)
)
4 changes: 2 additions & 2 deletions tokenlists/config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from pathlib import Path
from typing import Optional

DATA_FOLDER = Path.home().joinpath(".tokenlists")
DEFAULT_TOKEN_LIST: Optional[str] = None
DEFAULT_CACHE_PATH = Path.home().joinpath(".tokenlists")
DEFAULT_TOKENLIST: Optional[str] = None

UNISWAP_ENS_TOKENLISTS_HOST = "https://wispy-bird-88a7.uniswap.workers.dev/?url=http://{}.link"
Loading

0 comments on commit 912a99e

Please sign in to comment.