GithubHelp home page GithubHelp logo

pykeybasebot's Issues

Version 0.1.4 crashes on import

When I run import pykeybasebot, I get this error:

$ python3
Python 3.7.4 (v3.7.4:e09359112e, Jul  8 2019, 14:54:52) 
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pykeybasebot
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pykeybasebot/__init__.py", line 1, in <module>
    from .bot import *
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pykeybasebot/bot.py", line 8, in <module>
    from .chat_client import ChatClient
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pykeybasebot/chat_client.py", line 3, in <module>
    from .types import chat1
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pykeybasebot/types/chat1/__init__.py", line 20, in <module>
    from typing_extensions import Literal
ModuleNotFoundError: No module named 'typing_extensions'
>>> 

This didn't happen in version 0.1.1.

setup travis

this project needs CI on travis. peek at make test to get started. and please either add mypy to it (it currently fails) or make a new issue just to get mypy passing and added.

add ci

at the very least to run the checks the precommit hooks run, unit tests would be nice.

locally i get this on precommit:

isort....................................................................Passed
black....................................................................Passed
flake8...................................................................Passed
mypy.....................................................................Failed
hookid: mypy

mypy: can't read file '**/*.py': No such file or directory

running mypy manually seems to error out:

$ poetry run mypy pykeybasebot/*.py
pykeybasebot/types/gregor1/__init__.py:18: error: Cannot find module named 'dataclasses_json'
pykeybasebot/types/keybase1/__init__.py:128: error: Cannot find module named 'dataclasses_json'
pykeybasebot/types/stellar1/__init__.py:18: error: Cannot find module named 'dataclasses_json'
pykeybasebot/types/chat1/__init__.py:25: error: Cannot find module named 'dataclasses_json'
pykeybasebot/kbevent.py:5: error: Cannot find module named 'dataclasses_json'
pykeybasebot/kbevent.py:5: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports
pykeybasebot/chat_client.py:17: error: "ChatChannel" has no attribute "to_dict"
pykeybasebot/chat_client.py:23: error: "Type[SendRes]" has no attribute "from_dict"
pykeybasebot/chat_client.py:34: error: "ChatChannel" has no attribute "to_dict"
pykeybasebot/chat_client.py:41: error: "Type[SendRes]" has no attribute "from_dict"
pykeybasebot/chat_client.py:52: error: "ChatChannel" has no attribute "to_dict"
pykeybasebot/chat_client.py:59: error: "Type[SendRes]" has no attribute "from_dict"
pykeybasebot/chat_client.py:70: error: "ChatChannel" has no attribute "to_dict"
pykeybasebot/chat_client.py:77: error: "Type[SendRes]" has no attribute "from_dict"
pykeybasebot/chat_client.py:88: error: "ChatChannel" has no attribute "to_dict"
pykeybasebot/chat_client.py:95: error: "Type[SendRes]" has no attribute "from_dict"
pykeybasebot/cli.py:41: error: Item "None" of "Optional[StreamReader]" has no attribute "readline"
pykeybasebot/cli.py:48: error: "Type[KbEvent]" has no attribute "from_json"

would be good to catch these issues in CI before they're merged in.

Support restricted bots

I'm trying to make a keybase bot work as a restricted bot, but I'm running into issues when trying to send messages to a keybase team.

If I create a channel like this:

channel = pykeybasebot.types.chat1.ChatChannel(
    name=os.environ.get("KEYBASE_TEAM"),
    topic_name=os.environ.get("KEYBASE_CHANNEL"),
    members_type="team",
)

Then try sending a message like this:

await bot.chat.send(channel, "test")

I get this exception:

Exception: {'code': 0, 'message': 'error from chat server: team readers are unable to create conversations, found role RESTRICTEDBOT'}

If I receive an event, I also can't respond to it using the channel that's attached to the event like this:

await bot.chat.send(event.msg.channel, "test")

It throws this exception:

Exception: {'code': 0, 'message': 'invalid send v1 options: need channel or conversation_id'}

I believe this one is because event.msg.channel is ChatChannel(name='', public=None, members_type='team', topic_type='chat', topic_name=None), I think because the bot is restricted.

And it won't let me use the conv_id as the channel either. When I receive an event and try responding like this:

await bot.chat.send(event.msg.conv_id, "test")

I get the exception:

File "/home/user/.local/share/virtualenvs/app-4PlAip0Q/lib/python3.8/site-packages/pykeybasebot/chat_client.py", line 43, in send
    "channel": channel.to_dict(),
AttributeError: 'str' object has no attribute 'to_dict'

I'm using pykeybasebot 0.2.0.

Possible to get a lookup keybase user search example?

The keybase API provides lookup:
https://keybase.io/_/api/1.0/user/lookup.json?usernames=SOMEUSER

I found Keybase class on another dead python API project & was tempted to dig into that code to see how it was done:
https://keybase-python-api.readthedocs.io/en/latest/keybase.html#the-keybase-class-accessing-public-user-data

I see no lookup on pykeybasebot so I tried extending the class & get :
ERROR:['chat api' exited with 2]
ERROR:2020-03-15T19:10:10.557769-04:00 ▶ [ERRO keybase main.go:87] 001 invalid v1 method "lookup"
Am I missing something? But an example of how to search/lookup keybase user using pykeybasebot would be greatly appreciated!

Exception: Logged in as instead of [username]. Please logout first

I'm trying to port my code from pykeybasebot 0.1.1 to 0.1.5 and running into a strange exception. First, I set the environment variables:

export KEYBASE_USERNAME=my_username
export KEYBASE_PAPERKEY="insert paperkey here"

Then I open a python interpreter and copy and paste this very simple script:

import os
import asyncio
import pykeybasebot

class Handler:
    async def __call__(self, bot, event):
        print(event)

bot = pykeybasebot.Bot(
    username=os.environ.get("KEYBASE_USERNAME"),
    paperkey=os.environ.get("KEYBASE_PAPERKEY"),
    handler=Handler()
)

async def main():
    await bot.start({
        "local": False,
        "wallet": False,
        "dev": False,
        "hide-exploding": False,
        "filter_channels": None,
        "filter_channel": None
    })

asyncio.run(main())

I'm running this in a python:3.7.4-buster docker container with keybase installed via the instructions at https://keybase.io/docs/the_app/install_linux. So inside the container, I'm not logged into any keybase account.

When I try running it, it throws this exception:

>>> asyncio.run(main())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.7/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/usr/local/lib/python3.7/asyncio/base_events.py", line 579, in run_until_complete
    return future.result()
  File "<stdin>", line 8, in main
  File "/home/user/.local/share/virtualenvs/app-4PlAip0Q/lib/python3.7/site-packages/pykeybasebot/bot.py", line 24, in wrapped_f
    await keybase_bot_start_function(self, *args, **kwargs)
  File "/home/user/.local/share/virtualenvs/app-4PlAip0Q/lib/python3.7/site-packages/pykeybasebot/bot.py", line 87, in start
    async with _botlifecycle(self, listen_options) as events:
  File "/home/user/.local/share/virtualenvs/app-4PlAip0Q/lib/python3.7/site-packages/pykeybasebot/bot.py", line 54, in __aenter__
    await self.bot.ensure_initialized()
  File "/home/user/.local/share/virtualenvs/app-4PlAip0Q/lib/python3.7/site-packages/pykeybasebot/bot.py", line 113, in ensure_initialized
    if not await self._is_initialized():
  File "/home/user/.local/share/virtualenvs/app-4PlAip0Q/lib/python3.7/site-packages/pykeybasebot/bot.py", line 132, in _is_initialized
    f"Logged in as {actual_username} instead of {self.username}. Please logout first"
Exception: Logged in as  instead of my_username. Please logout first
>>> 

But I'm not logged in at all:

$ keybase status
Username:      
Logged in:     no
Session:
    is valid:  no
    keys:      locked

Key status:
    stream:    not cached
    secret:    not stored
    dev sig:   not cached
    dev enc:   not cached
    paper sig: not cached
    paper enc: not cached
    prompt:    show
    tsec:      not cached
[...snip...]

flip_conv_id empty

Here's my simple handler class:

class Handler:
    async def __call__(self, bot, event):
        if event.msg.content.type_name == chat1.MessageTypeStrings.FLIP.value:
            print(event.msg.content, flush=1)

And this is what it prints out (formatting my own):

MsgContent(type_name='flip',
    text=None,
    attachment=None,
    edit=None,
    reaction=None,
    delete=None,
    metadata=None,
    headline=None,
    attachment_uploaded=None,
    system=None,
    send_payment=None,
    request_payment=None,
    unfurl=None,
    flip=MsgFlipContent(
        text='gqF2AaJ2MYKkYm9keYKmcmV2ZWFsgqNjY2jEIKTHVHrHQJtd85tM4MELrONjgBXuaB3PsIIdgRZcA7ddpnNlY3JldMQgduj/lmQiq2dmbcWCXJIzSjD9f6HXVb9YANbGbuC26VShdASibWSDrmNvbnZlcnNhdGlvbklExCAAAD3GsBhtlbdws7qRZMGtu622IrxZ4oI1kcznobh57qZnYW1lSUTEDHppaPupROHnFP9A8Klpbml0aWF0b3KCoWTEEH+L21NwNBEjt89tNLzmoBihdcQQlWMS5SCyN0fr1Ncg52mqAA==',
        game_id='7a6968fba944e1e714ff40f0',
        flip_conv_id='',
        user_mentions=None,
        team_mentions=None
    )
)

Note that flip_conv_id is an empty string here, thus we're unable to properly call loadflip later. It is however available in API directly (i. e. when calling keybase chat api-listen, it appears as intended). Any idea how to deal with that?

Support for command advertisements?

Having a bot advertise its available commands is super helpful. It looks like this framework doesn't support that function yet. I started looking around in the NodeJS example of how it's implemented there (Chat.prototype.advertiseCommands), but I'm not sure how to approach implementing something similar here..

Newer Versions of Keybase seem to break bot

In Keybase version 4.5.0-20190919193603+93e889ab01 on Ubuntu Linux 18.04, I'm getting the following error whenever a message is received by the bot user:

mashumaro.exceptions.MissingField: Field "public" of type builtins.bool is missing in pykeybasebot.kbevent.Channel instance

This error causes the bot to error out and the systemd service to restart whenever a message is received. Sent in Keybase log 52883b0197aa196367513a1c to possibly help debug.

Error running pykeybasebot tests: f-string is missing placeholders

After following the install instructions make test fails on the following error:

(pykeybasebot) ➜  pykeybasebot git:(master) ✗ make test
poetry run mypy pykeybasebot/
poetry run flake8
./pykeybasebot/bot.py:126:23: F541 f-string is missing placeholders
make: *** [test-static] Error 1

L126 in boy.py

I wasn't sure what to pass into the logging statement, so I just passed self and the tests worked

        logging.debug(f"finished logsend {self}")

Imports crashes

Hello, upon firing up the program Imports crash it...
Is there a way to get the older functioning version?

Incoming message processed multiple times

My message handler is being called multiple times for the same message.
Here's a minimal example:

import asyncio
from pykeybasebot import Bot

class Handler:
    async def __call__(self, bot, event):
        print("handling message")
        await bot.chat.send(event.msg.conv_id, "Response")

bot = Bot(
    username="yourtestbot", handler=Handler()
)

asyncio.run(bot.start({}))

Ran this and sent a message to the bot. Expected to see a single "Response" reply. Instead, I get continuous "Response" messages about 2 per second. Printing shows the message handler keeps being called for the same message.

Running keybase chat api-listen from the command line returns the message only once, so I suspect the problem is with this library rather than the underlying api.

keybase version: keybase version 5.6.0-20200807080010+1c032f6216
pykeybasebot version: 0.2.1

Bunch of error logs when using filters

When we setup the listen-options, then errors are always shown, because python api is expecting JSON data:

listen_options = {
    "filter-channels": [
        {"name": "name": "bot,myname"}
    ]
}
INFO:root:
DEBUG:root:executing command: ['keybase', 'chat', 'api-listen', '--filter-channels', '[{"name": "bot,myname"}]']
ERROR:root:Unable to decode JSON output: b'Message filtering is active with 1 filters\n'
ERROR:root:Unable to decode JSON output: b'filter 0: <REDACTED>\n'
ERROR:root:Unable to decode JSON output: b'Listening for chat notifications. Config: {showLocal:false showNewConvs:false hideExploding:false}, subscribeDevChannels: false\n'

ValueError: I/O operation on closed pipe when i recieve message

I get the error below when I receive a message after I run the script.

OS: Windows 10
Python version: 3.8.0

My code:

import asyncio
import pykeybasebot

def handler(bot,event):
	print(event)

bot = pykeybasebot.Bot(handler=handler, username="xxxx")

listen_options = {
	"local": True,
	"wallet": True,
	"dev": True,
	"hide-exploding": False,
	"filter_channel": None,
	"filter_channels": None,
}

asyncio.run(bot.start(listen_options))

Error

ERROR:root:Unable to decode JSON output: Listening for chat notifications. Config: hideExploding: false, showLocal: true, subscribeDevChannels: true
ERROR:root:Unable to decode JSON output: Listening for wallet notifications
Traceback (most recent call last):
  File ".\test.py", line 12, in <module>
    bot.run()
  File "C:\Users\dnorh\OneDrive\Projects\Python\OOP\keybase_bot\keybase\bot.py", line 37, in run
    asyncio.run(self.bot.start(listen_options))
  File "C:\Users\dnorh\AppData\Local\Programs\Python\Python38\lib\asyncio\runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "C:\Users\dnorh\AppData\Local\Programs\Python\Python38\lib\asyncio\base_events.py", line 608, in run_until_complete
    return future.result()
  File "C:\Users\dnorh\AppData\Local\Programs\Python\Python38\lib\site-packages\pykeybasebot\bot.py", line 23, in wrapped_f
    await keybase_bot_start_function(self, *args, **kwargs)
  File "C:\Users\dnorh\AppData\Local\Programs\Python\Python38\lib\site-packages\pykeybasebot\bot.py", line 91, in start
    asyncio.create_task(self.handler(self, event))
  File "C:\Users\dnorh\AppData\Local\Programs\Python\Python38\lib\asyncio\tasks.py", line 382, in create_task
    task = loop.create_task(coro)
  File "C:\Users\dnorh\AppData\Local\Programs\Python\Python38\lib\asyncio\base_events.py", line 427, in create_task
    task = tasks.Task(coro, loop=self, name=name)
TypeError: a coroutine was expected, got None
Exception ignored in: <function BaseSubprocessTransport.__del__ at 0x0000027FA991BA60>
Traceback (most recent call last):
  File "C:\Users\dnorh\AppData\Local\Programs\Python\Python38\lib\asyncio\base_subprocess.py", line 126, in __del__
    self.close()
  File "C:\Users\dnorh\AppData\Local\Programs\Python\Python38\lib\asyncio\base_subprocess.py", line 104, in close
    proto.pipe.close()
  File "C:\Users\dnorh\AppData\Local\Programs\Python\Python38\lib\asyncio\proactor_events.py", line 108, in close
    self._loop.call_soon(self._call_connection_lost, None)
  File "C:\Users\dnorh\AppData\Local\Programs\Python\Python38\lib\asyncio\base_events.py", line 711, in call_soon
    self._check_closed()
  File "C:\Users\dnorh\AppData\Local\Programs\Python\Python38\lib\asyncio\base_events.py", line 504, in _check_closed
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
Exception ignored in: <function _ProactorBasePipeTransport.__del__ at 0x0000027FA993D160>
Traceback (most recent call last):
  File "C:\Users\dnorh\AppData\Local\Programs\Python\Python38\lib\asyncio\proactor_events.py", line 116, in __del__
    self.close()
  File "C:\Users\dnorh\AppData\Local\Programs\Python\Python38\lib\asyncio\proactor_events.py", line 108, in close
    self._loop.call_soon(self._call_connection_lost, None)
  File "C:\Users\dnorh\AppData\Local\Programs\Python\Python38\lib\asyncio\base_events.py", line 711, in call_soon
    self._check_closed()
  File "C:\Users\dnorh\AppData\Local\Programs\Python\Python38\lib\asyncio\base_events.py", line 504, in _check_closed
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed

Login not persisting

Hello,

I am probably doing something unusual here with asyncio; basically my concept called for running aiohttp and pykeybasebot at the same time (I want my bot to listen to the channel and also receive webhooks) and I wasn't sure how else to do that (have tried threading, etc.) so I just throw two asyncio future tasks into the event loop.

My code is here: https://gist.github.com/ageis/b29b2565aecabe6e96e63460e26155fe it's a simple server listening on port 8080 plus sitting in a Keybase channel via your library. I've omitted the message handler, it's immaterial to the bug.

What I'm finding is that my bot successfully receives several webhooks and posts them to the channel, but then its authentication fails or something. This is being run on a headless server. So I have the systemd service running in my user session, I did keybase login before running the script, and I also export KEYBASE_PAPERKEY to the environment. In addition, the script has the correct paperkey hardcoded in the bot instantiation.

Any ideas why this would work initially and then throw "Login required" ?

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/aiohttp/web_protocol.py", line 418, in start
    resp = await task
  File "/usr/local/lib/python3.7/dist-packages/aiohttp/web_app.py", line 458, in _handle
    resp = await handler(request)
  File "keybase_alerts.py", line 82, in handle
    await alert_bot.chat.send(channel, msg)
  File "/usr/local/lib/python3.7/dist-packages/pykeybasebot/chat_client.py", line 18, in send
    "message": {"body": message},
  File "/usr/local/lib/python3.7/dist-packages/pykeybasebot/chat_client.py", line 98, in execute
    resp = await self.bot.submit("chat api", json.dumps(command).encode("utf-8"))
  File "/usr/local/lib/python3.7/dist-packages/pykeybasebot/bot.py", line 95, in submit
    self.keybase_cli, command, input_data, loop=self.loop, **opts
  File "/usr/local/lib/python3.7/dist-packages/pykeybasebot/cli.py", line 78, in kbsubmit
    raise Exception(parsed_response["error"])
Exception: {'code': 0, 'message': 'Login required'}

Judging from the traceback, I suppose it's possible that "Login required" is my aiohttp server's reply to the client (in this case Alertmanager with a POST request), except I didn't specify basic auth anywhere so I've no clue why that would pop up. It's my first time using aiohttp incidentally. Let me know if that makes more sense; if the other library is to blame... I don't think it is though since after the first few webhooks, they continue to flow in yet aren't sent onward to the Keybase channel.

Not compatible with python 3.9

If i try to install pykeybasebot on python3.9, even pip doesn't argue against and installs it succesfully it looks like part of the code is not yet compatible:


kbot    | Traceback (most recent call last):
kbot    |   File "/home/keybase/project/kbot.py", line 474, in <module>
kbot    |     pingbot.run()
kbot    |   File "/home/keybase/project/kbot.py", line 78, in run
kbot    |     asyncio.run(self._bot.start(listen_options))
kbot    |   File "/usr/local/lib/python3.9/asyncio/runners.py", line 44, in run
kbot    |     return loop.run_until_complete(main)
kbot    |   File "/usr/local/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
kbot    |     return future.result()
kbot    |   File "/home/keybase/virtualenv/lib/python3.9/site-packages/pykeybasebot/bot.py", line 25, in wrapped_f
kbot    |     await keybase_bot_start_function(self, *args, **kwargs)
kbot    |   File "/home/keybase/virtualenv/lib/python3.9/site-packages/pykeybasebot/bot.py", line 93, in start
kbot    |     async for event in events:
kbot    |   File "/home/keybase/virtualenv/lib/python3.9/site-packages/pykeybasebot/cli.py", line 53, in kblisten
kbot    |     yield KbEvent.from_json(decoded_line)
kbot    |   File "/home/keybase/virtualenv/lib/python3.9/site-packages/dataclasses_json/api.py", line 135, in from_json
kbot    |     kvs = json.loads(s,
kbot    |   File "/usr/local/lib/python3.9/json/__init__.py", line 359, in loads
kbot    |     return cls(**kw).decode(s)
kbot    | TypeError: __init__() got an unexpected keyword argument 'encoding'

That appears to be, because encoding keyword has been removed from python3.9:
https://docs.python.org/3/library/json.html#json.loads

This problem is already solved on new dataclasses_json versions. So, changing the version for this in pyproject.toml and also updating the rest of dependencies should do the trick.

Version with this fixed:
dataclasses-json = "^0.5.2"

Is this still a supported library?

This library hasn't received an update in about 4 years. There's a known Issue with this library supporting modern Python 3 versions that has had an open pull request to fix it for 3 years. I'm potentially reading too much between the lines here, but I'm just wondering if this library should maybe have a disclaimer stating that it was abandoned, if it has been? If not, maybe it could use some fresh eyes?

I'm a consumer of this library, and I'm sort of already convinced that switching to the Go library is the right call here. But if I can keep using the Python library for now, that would maybe be more ideal (for me) than rewriting the bots that are already written in a different language. Convincing myself that I shouldn't rewrite them is getting harder and harder though.

Anyway, thanks for all the work that's been put into these libraries up until the point of about 4 years ago. I'm sure the Keybase team finds maintaining the Golang library a bit easier since that's the language of the main product's backend. I actually prefer writing Golang myself, but I'm sure people who want to use Keybase and have a need for bots that don't already have a 1st party solution appreciate the array of libraries in various languages to choose from.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.