Skip to content
This repository was archived by the owner on Aug 18, 2021. It is now read-only.

Commit 4459e5b

Browse files
committed
🎉 Initial commit.
0 parents  commit 4459e5b

13 files changed

+988
-0
lines changed

.gitignore

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
.Python
11+
build/
12+
develop-eggs/
13+
dist/
14+
downloads/
15+
eggs/
16+
.eggs/
17+
lib/
18+
lib64/
19+
parts/
20+
sdist/
21+
var/
22+
wheels/
23+
pip-wheel-metadata/
24+
share/python-wheels/
25+
*.egg-info/
26+
.installed.cfg
27+
*.egg
28+
MANIFEST
29+
30+
# PyInstaller
31+
# Usually these files are written by a python script from a template
32+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
33+
*.manifest
34+
*.spec
35+
36+
# Installer logs
37+
pip-log.txt
38+
pip-delete-this-directory.txt
39+
40+
# Unit test / coverage reports
41+
htmlcov/
42+
.tox/
43+
.nox/
44+
.coverage
45+
.coverage.*
46+
.cache
47+
nosetests.xml
48+
coverage.xml
49+
*.cover
50+
.hypothesis/
51+
.pytest_cache/
52+
53+
# Translations
54+
*.mo
55+
*.pot
56+
57+
# Django stuff:
58+
*.log
59+
local_settings.py
60+
db.sqlite3
61+
62+
# Flask stuff:
63+
instance/
64+
.webassets-cache
65+
66+
# Scrapy stuff:
67+
.scrapy
68+
69+
# Sphinx documentation
70+
docs/_build/
71+
72+
# PyBuilder
73+
target/
74+
75+
# Jupyter Notebook
76+
.ipynb_checkpoints
77+
78+
# IPython
79+
profile_default/
80+
ipython_config.py
81+
82+
# pyenv
83+
.python-version
84+
85+
# pipenv
86+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
87+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
88+
# having no cross-platform support, pipenv may install dependencies that don’t work, or not
89+
# install all needed dependencies.
90+
#Pipfile.lock
91+
92+
# celery beat schedule file
93+
celerybeat-schedule
94+
95+
# SageMath parsed files
96+
*.sage.py
97+
98+
# Environments
99+
.env
100+
.venv
101+
env/
102+
venv/
103+
ENV/
104+
env.bak/
105+
venv.bak/
106+
107+
# Spyder project settings
108+
.spyderproject
109+
.spyproject
110+
111+
# Rope project settings
112+
.ropeproject
113+
114+
# mkdocs documentation
115+
/site
116+
117+
# mypy
118+
.mypy_cache/
119+
.dmypy.json
120+
dmypy.json
121+
122+
# Pyre type checker
123+
.pyre/

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2019 Shivelight
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include README.rst LICENSE

README.rst

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
🤖 line-bot-sdk-python-extra
2+
============================
3+
4+
.. image:: https://img.shields.io/pypi/v/line-bot-sdk-extra.svg
5+
:target: https://pypi.python.org/pypi/line-bot-sdk-extra
6+
:alt: PyPI - Version
7+
8+
.. image:: https://img.shields.io/pypi/status/line-bot-sdk-extra.svg
9+
:target: https://pypi.python.org/pypi/line-bot-sdk-extra
10+
:alt: PyPI - Status
11+
12+
.. image:: https://img.shields.io/pypi/pyversions/line-bot-sdk-extra.svg
13+
:target: https://pypi.python.org/pypi/line-bot-sdk-extra
14+
:alt: PyPI - Python Version
15+
16+
.. image:: https://img.shields.io/pypi/l/line-bot-sdk-extra.svg
17+
:target: https://pypi.python.org/pypi/line-bot-sdk-extra
18+
  :alt: PyPI - License
19+
20+
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
21+
:target: https://github.com/ambv/black
22+
:alt: Code Style - Black
23+
24+
.. image:: https://img.shields.io/badge/Ko--fi-donate-blue.svg
25+
:target: https://ko-fi.com/shivelight
26+
:alt: Ko-fi - Donate
27+
28+
Extra feature for `LINE Messaging API SDK for Python <line-bot-sdk-python_>`_.
29+
30+
31+
Installation
32+
------------
33+
34+
::
35+
36+
pip install line-bot-sdk-extra
37+
38+
or::
39+
40+
python setup.py install
41+
42+
To use the package::
43+
44+
>>> import linebotx
45+
46+
47+
Features
48+
--------
49+
50+
Asynchronous API
51+
^^^^^^^^^^^^^^^^
52+
53+
Allows you to write non-blocking code which makes your bot respond much faster with little changes.
54+
55+
Synchronous:
56+
57+
.. code-block:: python
58+
59+
from linebot import LineBotApi, WebhookHandler
60+
line_bot_api = LineBotApi('YOUR_CHANNEL_ACCESS_TOKEN')
61+
handler = WebhookHandler('YOUR_CHANNEL_SECRET')
62+
63+
64+
Asynchronous:
65+
66+
.. code-block:: python
67+
68+
from linebotx import LineBotApiAsync, WebhookHandlerAsync
69+
line_bot_api = LineBotApiAsync('YOUR_CHANNEL_ACCESS_TOKEN')
70+
handler = WebhookHandlerAsync('YOUR_CHANNEL_SECRET')
71+
72+
73+
Equivalent Counterpart
74+
""""""""""""""""""""""
75+
76+
+---------------------+----------------+
77+
| linebotx | linebot |
78+
+=====================+================+
79+
| LineBotApiAsync | LineBotApi |
80+
+---------------------+----------------+
81+
| AioHttpClient | HttpClient |
82+
+---------------------+----------------+
83+
| AioHttpResponse | HttpResponse |
84+
+---------------------+----------------+
85+
| WebhookHandlerAsync | WebhookHandler |
86+
+---------------------+----------------+
87+
88+
**NOTE:** Every public method is coroutine and should be awaited. For example:
89+
90+
.. code-block:: python
91+
92+
@app.route("/callback", methods=['POST'])
93+
async def callback():
94+
...
95+
await handler.handle(body, signature)
96+
...
97+
98+
99+
@handler.add(MessageEvent, message=TextMessage)
100+
async def handle_message(event):
101+
await line_bot_api.reply_message(
102+
event.reply_token,
103+
TextSendMessage(text=event.message.text))
104+
105+
106+
Additional Methods
107+
""""""""""""""""""
108+
109+
coroutine :code:`LineBotApiAsync.close()`
110+
Close underlying http client.
111+
112+
coroutine :code:`AioHttpClient.close()`
113+
See `aiohttp.ClientSession.close() <https://aiohttp.readthedocs.io/en/stable/client_reference.html#aiohttp.ClientSession.close>`_.
114+
115+
116+
Timeout
117+
"""""""
118+
119+
To set a timeout you can pass `aiohttp.ClientTimeout <https://aiohttp.readthedocs.io/en/stable/client_reference.html#aiohttp.ClientTimeout>`_ object instead of numeric value.
120+
121+
122+
Examples
123+
""""""""
124+
125+
- `sanic-echo <https://github.com/Shivelight/line-bot-sdk-python-extra/tree/master/examples/sanic-echo>`_ - Sample echo-bot using sanic_.
126+
127+
128+
Contributing
129+
------------
130+
131+
If you would like to contribute, please check for open issues or open a new issue if you have ideas, changes, or bugs to report.
132+
133+
134+
References
135+
----------
136+
137+
This project is just a small addition to the original SDK, please refer to `line-bot-sdk-python <line-bot-sdk-python_>`_ or the `docs <https://line-bot-sdk-python.readthedocs.io/en/latest/>`_.
138+
139+
.. _sanic: https://github.com/huge-success/sanic
140+
.. _line-bot-sdk-python: https://github.com/line/line-bot-sdk-python

examples/sanic-echo/README.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
Sanic Echo
2+
==========
3+
4+
Sample echo-bot using `Sanic <https://github.com/huge-success/sanic>`_
5+
6+
Getting started
7+
~~~~~~~~~~~~~~~
8+
9+
::
10+
11+
$ export LINE_CHANNEL_SECRET=YOUR_LINE_CHANNEL_SECRET
12+
$ export LINE_CHANNEL_ACCESS_TOKEN=YOUR_LINE_CHANNEL_ACCESS_TOKEN
13+
$ pip install -r requirements.txt
14+
15+
Run WebhookParser sample::
16+
17+
$ python app.py
18+
19+
Run WebhookHandler sample::
20+
21+
$ python app_with_handler.py

examples/sanic-echo/app.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import os
2+
import sys
3+
from argparse import ArgumentParser
4+
5+
from sanic import Sanic, response
6+
from sanic.log import logger
7+
from sanic.exceptions import abort
8+
from linebot import WebhookParser
9+
from linebot.exceptions import InvalidSignatureError
10+
from linebot.models import MessageEvent, TextMessage, TextSendMessage
11+
12+
from linebotx import AioHttpClient, LineBotApiAsync
13+
14+
app = Sanic(__name__)
15+
16+
# get channel_secret and channel_access_token from your environment variable
17+
channel_secret = os.getenv("LINE_CHANNEL_SECRET", None)
18+
channel_access_token = os.getenv("LINE_CHANNEL_ACCESS_TOKEN", None)
19+
if channel_secret is None:
20+
print("Specify LINE_CHANNEL_SECRET as environment variable.")
21+
sys.exit(1)
22+
if channel_access_token is None:
23+
print("Specify LINE_CHANNEL_ACCESS_TOKEN as environment variable.")
24+
sys.exit(1)
25+
26+
parser = WebhookParser(channel_secret)
27+
28+
29+
@app.listener("before_server_start")
30+
async def setup_bot(app, loop):
31+
transport = AioHttpClient(loop=loop)
32+
app.bot = LineBotApiAsync(channel_access_token, http_client=transport)
33+
34+
35+
@app.listener('after_server_stop')
36+
async def close_bot(app, loop):
37+
await app.bot.close()
38+
39+
40+
@app.route("/callback", methods=["POST"])
41+
async def callback(request):
42+
signature = request.headers["X-Line-Signature"]
43+
44+
# get request body as text
45+
body = request.body.decode()
46+
logger.info("Request body: " + body)
47+
48+
# parse webhook body
49+
try:
50+
events = parser.parse(body, signature)
51+
except InvalidSignatureError:
52+
abort(400)
53+
54+
# if event is MessageEvent and message is TextMessage, then echo text
55+
for event in events:
56+
if not isinstance(event, MessageEvent):
57+
continue
58+
if not isinstance(event.message, TextMessage):
59+
continue
60+
61+
await app.bot.reply_message(
62+
event.reply_token, TextSendMessage(text=event.message.text)
63+
)
64+
65+
return response.text("OK")
66+
67+
68+
if __name__ == "__main__":
69+
arg_parser = ArgumentParser(
70+
usage="Usage: python " + __file__ + " [--port <port>] [--help]"
71+
)
72+
arg_parser.add_argument("-p", "--port", type=int, default=8000, help="port")
73+
arg_parser.add_argument("-d", "--debug", default=False, help="debug")
74+
options = arg_parser.parse_args()
75+
76+
app.run(debug=options.debug, port=options.port)

0 commit comments

Comments
 (0)