From d1c216f0e8951c5cb8481db9f500cf2b4b37e0ca Mon Sep 17 00:00:00 2001
From: Holger Nahrstaedt <holger@nahrstaedt.de>
Date: Thu, 1 Mar 2018 21:52:46 +0100
Subject: [PATCH] CLI added

Click and prettytable added to requirements
CLI added with following commands:
* balance
* info
Unit tests for CLI added
---
 README.rst            |  38 ++++++++++++++
 appveyor.yml          |   3 +-
 beem/cli.py           | 113 ++++++++++++++++++++++++++++++++++++++++++
 requirements-test.txt |   2 +
 requirements.txt      |   3 +-
 setup.py              |   7 +++
 tests/test_cli.py     |  44 ++++++++++++++++
 7 files changed, 208 insertions(+), 2 deletions(-)
 create mode 100644 beem/cli.py
 create mode 100644 tests/test_cli.py

diff --git a/README.rst b/README.rst
index 6849c3a5..91bf2a0d 100644
--- a/README.rst
+++ b/README.rst
@@ -11,6 +11,19 @@ The library name is derived from a beam maschine, similar to the analogy between
     :alt: Latest Version
 
 .. image:: https://img.shields.io/pypi/pyversions/beem.svg
+    :target: https://pypi.python.org/pypi/beem/
+    :alt: Python Versions
+    
+
+.. image:: https://anaconda.org/conda-forge/beem/badges/version.svg   
+    :target: https://anaconda.org/conda-forge/beem
+  
+.. image:: https://anaconda.org/conda-forge/beem/badges/downloads.svg   
+    :target: https://anaconda.org/conda-forge/beem
+
+
+Current build status
+--------------------
 
 .. image:: https://travis-ci.org/holgern/beem.svg?branch=master
     :target: https://travis-ci.org/holgern/beem
@@ -73,6 +86,24 @@ but possibly non-compiling version::
 Run tests after install::
 
     pytest
+    
+    
+Installing beem with conda-forge
+--------------------------------
+
+Installing beem from the conda-forge channel can be achieved by adding conda-forge to your channels with:
+
+    conda config --add channels conda-forge
+    
+Once the conda-forge channel has been enabled, beem can be installed with:
+
+    conda install beem
+
+CLI tool bundled
+----------------
+I started to work on a CLI tool:
+
+    beempy
 
 Documentation
 =============
@@ -80,6 +111,13 @@ Documentation is available at http://beem.readthedocs.io/en/latest/
 
 Changelog
 =========
+0.19.8
+------
+* bug fixes
+* CLI tool added
+* beem added to conda-forge
+* more unittests
+
 0.19.7
 ------
 * works on python 2.7
diff --git a/appveyor.yml b/appveyor.yml
index e25157cf..9b1e6841 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -60,7 +60,8 @@ install:
   - conda info -a
   - conda install --yes nose conda-build setuptools pip numpy pytest-pylint
   - conda install --yes pycryptodomex scrypt pyyaml pytest pytest-mock coverage mock appdirs
-  - conda install --yes ecdsa requests future websocket-client pytz six
+  - conda install --yes ecdsa requests future websocket-client pytz six Click prettytable
+
 
   # Upgrade to the latest version of pip to avoid it displaying warnings
   # about it being out of date.
diff --git a/beem/cli.py b/beem/cli.py
new file mode 100644
index 00000000..d5bd7da8
--- /dev/null
+++ b/beem/cli.py
@@ -0,0 +1,113 @@
+# This Python file uses the following encoding: utf-8
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+from builtins import bytes, int, str
+from beem.instance import set_shared_steem_instance, shared_steem_instance
+from beem.amount import Amount
+from beem.account import Account
+from beem.steem import Steem
+from beem.storage import configStorage
+from beem.version import version as __version__
+from datetime import datetime, timedelta
+import pytz
+from beembase import operations
+from beembase.account import PrivateKey, PublicKey
+import json
+from prettytable import PrettyTable
+import math
+import random
+import logging
+import click
+log = logging.getLogger(__name__)
+
+
+@click.group(chain=True)
+@click.option(
+    '--node', '-n', default="", help="URL for public Steem API")
+@click.option(
+    '--offline', is_flag=True, default=False, help="Prevent connecting to network")
+@click.option(
+    '--nobroadcast', '-d', is_flag=True, default=False, help="Do not broadcast")
+@click.option(
+    '--unsigned', is_flag=True, default=False, help="Nothing will be signed")
+@click.option(
+    '--blocking', is_flag=True, default=False,
+    help="Wait for broadcasted transactions to be included in a block and return full transaction")
+@click.option(
+    '--bundle', is_flag=True, default=False,
+    help="Do not broadcast transactions right away, but allow to bundle operations ")
+@click.option(
+    '--expiration', '-e', default=30,
+    help='Delay in seconds until transactions are supposed to expire(defaults to 60)')
+@click.option(
+    '--debug', is_flag=True, default=False, help='Enables Debug output')
+@click.version_option(version=__version__)
+def cli(node, offline, nobroadcast, unsigned, blocking, bundle, expiration, debug):
+    stm = Steem(
+        node=node,
+        nobroadcast=nobroadcast,
+        unsigned=unsigned,
+        blocking=blocking,
+        bundle=bundle,
+        expiration=expiration,
+        debug=debug
+    )
+    set_shared_steem_instance(stm)
+    pass
+
+
+@cli.command()
+@click.option(
+    '--account', '-a', multiple=True)
+def balance(account):
+    stm = shared_steem_instance()
+    if len(account) == 0:
+        if "default_account" in stm.config:
+            account = [stm.config["default_account"]]
+    for name in account:
+        a = Account(name, steem_instance=stm)
+        print("\n@%s" % a.name)
+        t = PrettyTable(["Account", "STEEM", "SBD", "VESTS"])
+        t.align = "r"
+        t.add_row([
+            'Available',
+            str(a.balances['available'][0]),
+            str(a.balances['available'][1]),
+            str(a.balances['available'][2]),
+        ])
+        t.add_row([
+            'Rewards',
+            str(a.balances['rewards'][0]),
+            str(a.balances['rewards'][1]),
+            str(a.balances['rewards'][2]),
+        ])
+        t.add_row([
+            'Savings',
+            str(a.balances['savings'][0]),
+            str(a.balances['savings'][1]),
+            'N/A',
+        ])
+        t.add_row([
+            'TOTAL',
+            str(a.balances['total'][0]),
+            str(a.balances['total'][1]),
+            str(a.balances['total'][2]),
+        ])
+        print(t)
+
+
+@cli.command()
+@click.option(
+    '--account', '-a', multiple=True)
+def info(account):
+    stm = shared_steem_instance()
+    for name in account:
+        a = Account(name, steem_instance=stm)
+        a.print_info()
+        print("\n")
+
+
+if __name__ == "__main__":
+    cli()
diff --git a/requirements-test.txt b/requirements-test.txt
index 850cd1c0..5f2e41be 100644
--- a/requirements-test.txt
+++ b/requirements-test.txt
@@ -12,3 +12,5 @@ pytest-mock
 coverage
 mock
 appdirs
+Click
+prettytable
diff --git a/requirements.txt b/requirements.txt
index dd25188c..82847f4d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -12,4 +12,5 @@ pytest-mock
 coverage
 mock
 appdirs
-
+Click
+prettytable
diff --git a/setup.py b/setup.py
index b199a10a..18f64d76 100755
--- a/setup.py
+++ b/setup.py
@@ -78,7 +78,14 @@ if __name__ == '__main__':
             "scrypt",
             "pycryptodomex",
             "pytz",
+            "Click",
+            "prettytable"
         ],
+        entry_points={
+            'console_scripts': [
+                'beempy=beem.cli:cli',
+            ],
+        },
         setup_requires=['pytest-runner'],
         tests_require=['pytest'],
         include_package_data=True,
diff --git a/tests/test_cli.py b/tests/test_cli.py
new file mode 100644
index 00000000..7ce062c3
--- /dev/null
+++ b/tests/test_cli.py
@@ -0,0 +1,44 @@
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+from builtins import str
+from builtins import super
+import unittest
+import mock
+import click
+from click.testing import CliRunner
+from pprint import pprint
+from beem import Steem, exceptions
+from beem.account import Account
+from beem.amount import Amount
+from beem.asset import Asset
+from beem.cli import cli, balance
+from beem.instance import set_shared_steem_instance
+from beembase.operationids import getOperationNameForId
+
+wif = "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"
+nodes = ["wss://steemd.pevo.science", "wss://gtg.steem.house:8090", "wss://rpc.steemliberator.com", "wss://rpc.buildteam.io",
+         "wss://rpc.steemviz.com", "wss://seed.bitcoiner.me", "wss://node.steem.ws", "wss://steemd.steemgigs.org", "wss://steemd.steemit.com",
+         "wss://steemd.minnowsupportproject.org"]
+
+
+class Testcases(unittest.TestCase):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+        self.bts = Steem(
+            node=nodes,
+            nobroadcast=True,
+            bundle=False,
+            # Overwrite wallet to use this list of wifs only
+            wif={"active": wif}
+        )
+        self.bts.set_default_account("test")
+        set_shared_steem_instance(self.bts)
+
+    def test_balance(self):
+        runner = CliRunner()
+        result = runner.invoke(cli, ['balance', '-atest'])
+        self.assertEqual(result.exit_code, 0)
-- 
GitLab