From b0fa7a9cb1a1b3cb7e4d56d97416423be2353aab Mon Sep 17 00:00:00 2001 From: Holger Nahrstaedt <holger@nahrstaedt.de> Date: Tue, 17 Apr 2018 15:06:27 +0200 Subject: [PATCH] Follower and following added to cli cli * follower and following added witness * is_active added Witnesses * printAsTable improved unit tests * follower and following added to test_cli --- README.rst | 6 +++ beem/cli.py | 120 ++++++++++++++++++++++++++++++++++++++++- beem/witness.py | 32 +++++++---- docs/cli.rst | 13 +++-- tests/beem/test_cli.py | 10 ++++ 5 files changed, 166 insertions(+), 15 deletions(-) diff --git a/README.rst b/README.rst index 24da62d4..1fd20aef 100644 --- a/README.rst +++ b/README.rst @@ -128,6 +128,12 @@ Documentation is available at http://beem.readthedocs.io/en/latest/ Changelog ========= +0.19.22 +------- +* beempy (command line tool) improved and all missing functions which are available in steempy are added +* new functions to beempy added: witnesses, walletinfo, openorders, orderbook and claimreward +* unit tests for cli added + 0.19.21 ------- * Transactionbuilder and Wallet improved diff --git a/beem/cli.py b/beem/cli.py index 44296250..11b45854 100644 --- a/beem/cli.py +++ b/beem/cli.py @@ -514,6 +514,124 @@ def interest(account): print(t) +@cli.command() +@click.argument('account', nargs=-1, required=False) +def follower(account): + """ Get information about followers + """ + stm = shared_steem_instance() + if not account: + if "default_account" in stm.config: + account = [stm.config["default_account"]] + for a in account: + t = PrettyTable([ + "Key", "value" + ]) + t.align = "r" + a = Account(a, steem_instance=stm) + print("\nFollowers statistics for @%s (please wait...)" % a.name) + follower_count = a.get_follow_count()["follower_count"] + t.add_row(["follower_count", str(follower_count)]) + followers = a.get_followers(False) + own_mvest = [] + eff_sp = [] + rep = [] + last_vote_h = [] + last_post_d = [] + no_vote = 0 + no_post = 0 + for f in followers: + rep.append(f.rep) + own_mvest.append(f.balances["available"][2].amount / 1e6) + eff_sp.append(f.get_steem_power()) + utc = pytz.timezone('UTC') + last_vote = utc.localize(datetime.utcnow()) - formatTimeString(f["last_vote_time"]) + if last_vote.days >= 365: + no_vote += 1 + else: + last_vote_h.append(last_vote.total_seconds() / 60 / 60) + last_post = utc.localize(datetime.utcnow()) - formatTimeString(f["last_root_post"]) + if last_post.days >= 365: + no_post += 1 + else: + last_post_d.append(last_post.total_seconds() / 60 / 60 / 24) + + t.add_row(["Summed MVest value", "%.2f" % sum(own_mvest)]) + if (len(rep) > 0): + t.add_row(["Mean Rep.", "%.2f" % (sum(rep) / len(rep))]) + t.add_row(["Max Rep.", "%.2f" % (max(rep))]) + if (len(eff_sp) > 0): + t.add_row(["Summed eff. SP", "%.2f" % sum(eff_sp)]) + t.add_row(["Mean eff. SP", "%.2f" % (sum(eff_sp) / len(eff_sp))]) + t.add_row(["Max eff. SP", "%.2f" % max(eff_sp)]) + if (len(last_vote_h) > 0): + t.add_row(["Mean last vote diff in hours", "%.2f" % (sum(last_vote_h) / len(last_vote_h))]) + if len(last_post_d) > 0: + t.add_row(["Mean last post diff in days", "%.2f" % (sum(last_post_d) / len(last_post_d))]) + t.add_row(["Followers without vote in 365 days", no_vote]) + t.add_row(["Followers without post in 365 days", no_post]) + print(t) + + +@cli.command() +@click.argument('account', nargs=-1, required=False) +def following(account): + """ Get information about following + """ + stm = shared_steem_instance() + if not account: + if "default_account" in stm.config: + account = [stm.config["default_account"]] + for a in account: + t = PrettyTable([ + "Key", "value" + ]) + t.align = "r" + a = Account(a, steem_instance=stm) + print("\nFollowing statistics for @%s (please wait...)" % a.name) + following_count = a.get_follow_count()["following_count"] + t.add_row(["following_count", str(following_count)]) + following = a.get_following(False) + own_mvest = [] + eff_sp = [] + rep = [] + last_vote_h = [] + last_post_d = [] + no_vote = 0 + no_post = 0 + for f in following: + rep.append(f.rep) + own_mvest.append(f.balances["available"][2].amount / 1e6) + eff_sp.append(f.get_steem_power()) + utc = pytz.timezone('UTC') + last_vote = utc.localize(datetime.utcnow()) - formatTimeString(f["last_vote_time"]) + if last_vote.days >= 365: + no_vote += 1 + else: + last_vote_h.append(last_vote.total_seconds() / 60 / 60) + last_post = utc.localize(datetime.utcnow()) - formatTimeString(f["last_root_post"]) + if last_post.days >= 365: + no_post += 1 + else: + last_post_d.append(last_post.total_seconds() / 60 / 60 / 24) + + t.add_row(["Summed MVest value", "%.2f" % sum(own_mvest)]) + if (len(rep) > 0): + t.add_row(["Mean Rep.", "%.2f" % (sum(rep) / len(rep))]) + t.add_row(["Max Rep.", "%.2f" % (max(rep))]) + if (len(eff_sp) > 0): + t.add_row(["Summed eff. SP", "%.2f" % sum(eff_sp)]) + t.add_row(["Mean eff. SP", "%.2f" % (sum(eff_sp) / len(eff_sp))]) + t.add_row(["Max eff. SP", "%.2f" % max(eff_sp)]) + if (len(last_vote_h) > 0): + t.add_row(["Mean last vote diff in hours", "%.2f" % (sum(last_vote_h) / len(last_vote_h))]) + if len(last_post_d) > 0: + t.add_row(["Mean last post diff in days", "%.2f" % (sum(last_post_d) / len(last_post_d))]) + t.add_row(["Following without vote in 365 days", no_vote]) + t.add_row(["Following without post in 365 days", no_post]) + print(t) + + @cli.command() @click.argument('account', nargs=1, required=False) def permissions(account): @@ -1091,7 +1209,7 @@ def witnesscreate(witness, signing_key, maximum_block_size, account_creation_fee @cli.command() -@click.option('--account', '-a', help='List the voted witnesses of your account') +@click.argument('account', nargs=1, required=False) @click.option('--limit', help='How many witnesses should be shown', default=100) def witnesses(account, limit): """ List witnesses diff --git a/beem/witness.py b/beem/witness.py index 6cf977a8..49b67dc3 100644 --- a/beem/witness.py +++ b/beem/witness.py @@ -15,6 +15,7 @@ from datetime import datetime, timedelta from beembase import transactions, operations from beemgraphenebase.account import PrivateKey, PublicKey import pytz +from prettytable import PrettyTable class Witness(BlockchainObject): @@ -60,7 +61,7 @@ class Witness(BlockchainObject): else: witness = self.steem.rpc.get_witness_by_account(self.identifier) if not witness: - raise WitnessDoesNotExistsException + raise WitnessDoesNotExistsException(self.identifier) super(Witness, self).__init__(witness, id_item="owner", steem_instance=self.steem) self.identifier = self["owner"] @@ -68,6 +69,10 @@ class Witness(BlockchainObject): def account(self): return Account(self["owner"], steem_instance=self.steem) + @property + def is_active(self): + return len(self['signing_key']) > 3 and self['signing_key'][3:] != '1111111111111111111111111111111114T1Anm' + def feed_publish(self, base, quote="1.000 STEEM", @@ -136,6 +141,8 @@ class Witness(BlockchainObject): class WitnessesObject(list): def printAsTable(self, sort_key="votes", reverse=True): utc = pytz.timezone('UTC') + t = PrettyTable(["name", "Votes [PV]", "disabled", "missed blocks", "feed base", "feed quote", "feed update", "fee", "size", "interest", "version"]) + t.align = "l" if sort_key == 'base': sortedList = sorted(self, key=lambda self: self['sbd_exchange_rate']['base'], reverse=reverse) elif sort_key == 'quote': @@ -153,15 +160,22 @@ class WitnessesObject(list): else: sortedList = sorted(self, key=lambda self: self[sort_key], reverse=reverse) for witness in sortedList: - outstr = '' - outstr += witness['owner'][:15].ljust(15) + " \t " + str(round(int(witness['votes']) / 1e15, 2)).ljust(5) + " PV - " + str(witness['total_missed']).ljust(5) - outstr += " missed - feed:" + str(Amount(witness['sbd_exchange_rate']['base'], steem_instance=self.steem)) + "/" - outstr += str(Amount(witness['sbd_exchange_rate']['quote'], steem_instance=self.steem)) td = utc.localize(datetime.now()) - formatTimeString(witness['last_sbd_exchange_update']) - outstr += " " + str(td.days) + " days " + str(td.seconds // 3600) + ":" + str((td.seconds // 60) % 60) + " \t " - outstr += str(witness['props']['account_creation_fee']) + " " + str(witness['props']['maximum_block_size']) + " Blocks " - outstr += str(witness['props']['sbd_interest_rate']) + " \t " + witness['running_version'] - print(outstr) + disabled = "" + if not witness.is_active: + disabled = "yes" + t.add_row([witness['owner'], + str(round(int(witness['votes']) / 1e15, 2)), + disabled, + str(witness['total_missed']), + str(Amount(witness['sbd_exchange_rate']['base'], steem_instance=self.steem)), + str(Amount(witness['sbd_exchange_rate']['quote'], steem_instance=self.steem)), + str(td.days) + " days " + str(td.seconds // 3600) + ":" + str((td.seconds // 60) % 60), + str(witness['props']['account_creation_fee']), + str(witness['props']['maximum_block_size']), + str(witness['props']['sbd_interest_rate'] / 100) + " %", + witness['running_version']]) + print(t) class Witnesses(WitnessesObject): diff --git a/docs/cli.rst b/docs/cli.rst index 5d4f1fc4..67e643d7 100644 --- a/docs/cli.rst +++ b/docs/cli.rst @@ -98,7 +98,7 @@ You can see all available commands with ``beempy --help`` :: ~ % beempy --help - Usage: beempy [OPTIONS] COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]... + Usage: cli.py [OPTIONS] COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]... Options: -n, --node TEXT URL for public Steem API (e.g. @@ -107,10 +107,6 @@ You can see all available commands with ``beempy --help`` -d, --no-broadcast Do not broadcast -p, --no-wallet Do not load the wallet -x, --unsigned Nothing will be signed - --blocking Wait for broadcasted transactions to be included in a - block and return full transaction - --bundle Do not broadcast transactions right away, but allow - to bundle operations -e, --expires INTEGER Delay in seconds until transactions are supposed to expire(defaults to 60) -v, --verbose INTEGER Verbosity @@ -122,17 +118,22 @@ You can see all available commands with ``beempy --help`` allow Allow an account/key to interact with your... approvewitness Approve a witnesses balance Shows balance + broadcast broadcast a signed transaction buy Buy STEEM or SBD from the internal market... cancel Cancel order in the internal market changewalletpassphrase Change wallet password + claimreward Claim reward balances By default, this will... config Shows local configuration convert Convert STEEMDollars to Steem (takes a week... createwallet Create new wallet with password delkey Delete key from the wallet PUB is the public... + delprofile Delete a variable in an account's profile disallow Remove allowance an account/key to interact... disapprovewitness Disapprove a witnesses downvote Downvote a post/comment POST is... follow Follow another account + follower Get information about followers + following Get information about following importaccount Import an account using a passphrase info Show basic blockchain info General... interest Get information about interest payment @@ -148,6 +149,8 @@ You can see all available commands with ``beempy --help`` resteem Resteem an existing post sell Sell STEEM or SBD from the internal market... set Set default_account, default_vote_weight or... + setprofile Set a variable in an account's profile + sign Sign a provided transaction with available... transfer Transfer SBD/STEEM unfollow Unfollow another account updatememokey Update an account's memo key diff --git a/tests/beem/test_cli.py b/tests/beem/test_cli.py index 3c50bc06..36c0d51d 100644 --- a/tests/beem/test_cli.py +++ b/tests/beem/test_cli.py @@ -172,6 +172,16 @@ class Testcases(unittest.TestCase): result = runner.invoke(cli, ['permissions', 'test']) self.assertEqual(result.exit_code, 0) + def test_follower(self): + runner = CliRunner() + result = runner.invoke(cli, ['follower', 'beem2']) + self.assertEqual(result.exit_code, 0) + + def test_following(self): + runner = CliRunner() + result = runner.invoke(cli, ['following', 'beem']) + self.assertEqual(result.exit_code, 0) + def test_allow_disallow(self): runner = CliRunner() result = runner.invoke(cli, ['-d', 'allow', 'beem1', '--account beem', '--permission posting'], input="test\n") -- GitLab