Merge pull request #518 from carpedm20/fix-documentation
Improve documentation
This commit is contained in:
@@ -3,36 +3,40 @@ Contributing to ``fbchat``
|
||||
|
||||
Thanks for reading this, all contributions are very much welcome!
|
||||
|
||||
Please be aware that ``fbchat`` uses `Scemantic Versioning <https://semver.org/>`__
|
||||
Please be aware that ``fbchat`` uses `Scemantic Versioning <https://semver.org/>`__ quite rigorously!
|
||||
That means that if you're submitting a breaking change, it will probably take a while before it gets considered.
|
||||
|
||||
In that case, you can point your PR to the ``2.0.0-dev`` branch, where the API is being properly developed.
|
||||
Otherwise, just point it to ``master``.
|
||||
|
||||
Development Environment
|
||||
-----------------------
|
||||
|
||||
You can use `flit` to install the package as a symlink:
|
||||
This project uses ``flit`` to configure development environments. You can install it using:
|
||||
|
||||
.. code-block::
|
||||
.. code-block:: sh
|
||||
|
||||
$ pip install flit
|
||||
|
||||
And now you can install ``fbchat`` as a symlink:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ git clone https://github.com/carpedm20/fbchat.git
|
||||
$ cd fbchat
|
||||
$ # *nix:
|
||||
$ flit install --symlink
|
||||
$ # Windows:
|
||||
$ flit install --pth-file
|
||||
|
||||
This will also install required development tools like ``black``, ``pytest`` and ``sphinx``.
|
||||
|
||||
After that, you can ``import`` the module as normal.
|
||||
|
||||
Before committing, you should run ``black .`` in the main directory, to format your code.
|
||||
Checklist
|
||||
---------
|
||||
|
||||
Testing Environment
|
||||
-------------------
|
||||
Once you're done with your work, please follow the steps below:
|
||||
|
||||
The tests use `pytest <https://docs.pytest.org/>`__, and to work they need two Facebook accounts, and a group thread between these.
|
||||
To set these up, you should export the following environment variables:
|
||||
|
||||
``client1_email``, ``client1_password``, ``client2_email``, ``client2_password`` and ``group_id``
|
||||
|
||||
If you're not able to do this, consider simply running ``pytest -m offline``.
|
||||
|
||||
And if you're adding new functionality, if possible, make sure to create a new test for it.
|
||||
- Run ``black .`` to format your code.
|
||||
- Run ``pytest`` to test your code.
|
||||
- Run ``make -C docs html``, and view the generated docs, to verify that the docs still work.
|
||||
- Run ``make -C docs spelling`` to check your spelling in docstrings.
|
||||
- Create a pull request, and point it to ``master`` `here <https://github.com/carpedm20/fbchat/pulls/new>`__.
|
||||
|
99
README.rst
99
README.rst
@@ -1,17 +1,17 @@
|
||||
``fbchat``: Facebook Chat (Messenger) for Python
|
||||
================================================
|
||||
``fbchat`` - Facebook Messenger for Python
|
||||
==========================================
|
||||
|
||||
.. image:: https://badgen.net/pypi/license/fbchat
|
||||
:target: https://github.com/carpedm20/fbchat/tree/master/LICENSE
|
||||
:alt: License: BSD 3-Clause
|
||||
.. image:: https://badgen.net/pypi/v/fbchat
|
||||
:target: https://pypi.python.org/pypi/fbchat
|
||||
:alt: Project version
|
||||
|
||||
.. image:: https://badgen.net/badge/python/3.5,3.6,3.7,3.8,pypy?list=|
|
||||
:target: https://pypi.python.org/pypi/fbchat
|
||||
:alt: Supported python versions: 3.5, 3.6, 3.7, 3.8 and pypy
|
||||
|
||||
.. image:: https://badgen.net/pypi/v/fbchat
|
||||
:target: https://pypi.python.org/pypi/fbchat
|
||||
:alt: Project version
|
||||
.. image:: https://badgen.net/pypi/license/fbchat
|
||||
:target: https://github.com/carpedm20/fbchat/tree/master/LICENSE
|
||||
:alt: License: BSD 3-Clause
|
||||
|
||||
.. image:: https://readthedocs.org/projects/fbchat/badge/?version=stable
|
||||
:target: https://fbchat.readthedocs.io
|
||||
@@ -25,37 +25,88 @@
|
||||
:target: https://github.com/ambv/black
|
||||
:alt: Code style
|
||||
|
||||
Facebook Chat (`Messenger <https://www.facebook.com/messages/>`__) for Python.
|
||||
This project was inspired by `facebook-chat-api <https://github.com/Schmavery/facebook-chat-api>`__.
|
||||
A powerful and efficient library to interact with
|
||||
`Facebook's Messenger <https://www.facebook.com/messages/>`__, using just your email and password.
|
||||
|
||||
**No XMPP or API key is needed**. Just use your email and password.
|
||||
This is *not* an official API, Facebook has that `over here <https://developers.facebook.com/docs/messenger-platform>`__ for chat bots. This library differs by using a normal Facebook account instead.
|
||||
|
||||
Go to `Read the Docs <https://fbchat.readthedocs.io>`__ to see the full documentation,
|
||||
or jump right into the code by viewing the `examples <https://github.com/carpedm20/fbchat/tree/master/examples>`__
|
||||
``fbchat`` currently support:
|
||||
|
||||
Version warning:
|
||||
----------------
|
||||
- Sending many types of messages, with files, stickers, mentions, etc.
|
||||
- Fetching all messages, threads and images in threads.
|
||||
- Searching for messages and threads.
|
||||
- Creating groups, setting the group emoji, changing nicknames, creating polls, etc.
|
||||
- Listening for, an reacting to messages and other events in real-time.
|
||||
- Type hints, and it has a modern codebase (e.g. only Python 3.5 and upwards).
|
||||
- ``async``/``await`` (COMING).
|
||||
|
||||
Essentially, everything you need to make an amazing Facebook bot!
|
||||
|
||||
|
||||
Version Warning
|
||||
---------------
|
||||
``v2`` is currently being developed at the ``master`` branch and it's highly unstable. If you want to view the old ``v1``, go `here <https://github.com/carpedm20/fbchat/tree/v1>`__.
|
||||
|
||||
Additionally, you can view the project's progress `here <https://github.com/carpedm20/fbchat/projects/2>`__.
|
||||
|
||||
Installation:
|
||||
|
||||
Caveats
|
||||
-------
|
||||
|
||||
``fbchat`` works by imitating what the browser does, and thereby tricking Facebook into thinking it's accessing the website normally.
|
||||
|
||||
However, there's a catch! **Using this library may not comply with Facebook's Terms Of Service!**, so be responsible Facebook citizens! We are not responsible if your account gets banned!
|
||||
|
||||
Additionally, **the APIs the library is calling is undocumented!** In theory, this means that your code could break tomorrow, without the slightest warning!
|
||||
If this happens to you, please report it, so that we can fix it as soon as possible!
|
||||
|
||||
.. inclusion-marker-intro-end
|
||||
.. This message doesn't make sense in the docs at Read The Docs, so we exclude it
|
||||
|
||||
With that out of the way, you may go to `Read The Docs <https://fbchat.readthedocs.io/>`__ to see the full documentation!
|
||||
|
||||
.. inclusion-marker-installation-start
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
.. code-block::
|
||||
|
||||
$ pip install fbchat
|
||||
|
||||
If you don't have `pip <https://pip.pypa.io/>`_, `this guide <http://docs.python-guide.org/en/latest/starting/installation/>`_ can guide you through the process.
|
||||
|
||||
You can also install directly from source, provided you have ``pip>=19.0``:
|
||||
|
||||
.. code-block::
|
||||
|
||||
$ pip install git+https://github.com/carpedm20/fbchat.git
|
||||
|
||||
.. inclusion-marker-installation-end
|
||||
|
||||
|
||||
Example Usage
|
||||
-------------
|
||||
|
||||
.. code-block::
|
||||
|
||||
$ pip install fbchat
|
||||
import getpass
|
||||
import fbchat
|
||||
session = fbchat.Session.login("<email/phone number>", getpass.getpass())
|
||||
user = fbchat.User(session=session, id=session.user_id)
|
||||
user.send_text("Test message!")
|
||||
|
||||
You can also install from source if you have ``pip>=19.0``:
|
||||
|
||||
.. code-block::
|
||||
|
||||
$ git clone https://github.com/carpedm20/fbchat.git
|
||||
$ pip install fbchat
|
||||
More examples are available `here <https://github.com/carpedm20/fbchat/tree/master/examples>`__.
|
||||
|
||||
|
||||
Maintainer
|
||||
----------
|
||||
|
||||
- Mads Marquart / `@madsmtm <https://github.com/madsmtm>`__
|
||||
- Taehoon Kim / `@carpedm20 <http://carpedm20.github.io/about/>`__
|
||||
|
||||
|
||||
Acknowledgements
|
||||
----------------
|
||||
|
||||
This project was originally inspired by `facebook-chat-api <https://github.com/Schmavery/facebook-chat-api>`__.
|
||||
|
BIN
docs/_static/find-group-id.png
vendored
BIN
docs/_static/find-group-id.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 59 KiB |
70
docs/api.rst
70
docs/api.rst
@@ -1,70 +0,0 @@
|
||||
.. module:: fbchat
|
||||
.. _api:
|
||||
|
||||
.. Note: we're using () to hide the __init__ method where relevant
|
||||
|
||||
Full API
|
||||
========
|
||||
|
||||
If you are looking for information on a specific function, class, or method, this part of the documentation is for you.
|
||||
|
||||
Client
|
||||
------
|
||||
|
||||
.. autoclass:: Client
|
||||
|
||||
Threads
|
||||
-------
|
||||
|
||||
.. autoclass:: Thread()
|
||||
.. autoclass:: Page()
|
||||
.. autoclass:: User()
|
||||
.. autoclass:: Group()
|
||||
|
||||
Messages
|
||||
--------
|
||||
|
||||
.. autoclass:: Message
|
||||
.. autoclass:: Mention
|
||||
.. autoclass:: EmojiSize(Enum)
|
||||
:undoc-members:
|
||||
|
||||
Exceptions
|
||||
----------
|
||||
|
||||
.. autoexception:: FBchatException()
|
||||
.. autoexception:: FBchatFacebookError()
|
||||
|
||||
Attachments
|
||||
-----------
|
||||
|
||||
.. autoclass:: Attachment()
|
||||
.. autoclass:: ShareAttachment()
|
||||
.. autoclass:: Sticker()
|
||||
.. autoclass:: LocationAttachment()
|
||||
.. autoclass:: LiveLocationAttachment()
|
||||
.. autoclass:: FileAttachment()
|
||||
.. autoclass:: AudioAttachment()
|
||||
.. autoclass:: ImageAttachment()
|
||||
.. autoclass:: VideoAttachment()
|
||||
.. autoclass:: ImageAttachment()
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
|
||||
.. autoclass:: ThreadLocation(Enum)
|
||||
:undoc-members:
|
||||
.. autoclass:: ActiveStatus()
|
||||
|
||||
.. autoclass:: QuickReply
|
||||
.. autoclass:: QuickReplyText
|
||||
.. autoclass:: QuickReplyLocation
|
||||
.. autoclass:: QuickReplyPhoneNumber
|
||||
.. autoclass:: QuickReplyEmail
|
||||
|
||||
.. autoclass:: Poll
|
||||
.. autoclass:: PollOption
|
||||
|
||||
.. autoclass:: Plan
|
||||
.. autoclass:: GuestStatus(Enum)
|
||||
:undoc-members:
|
13
docs/api/attachments.rst
Normal file
13
docs/api/attachments.rst
Normal file
@@ -0,0 +1,13 @@
|
||||
Attachments
|
||||
===========
|
||||
|
||||
.. autoclass:: Attachment()
|
||||
.. autoclass:: ShareAttachment()
|
||||
.. autoclass:: Sticker()
|
||||
.. autoclass:: LocationAttachment()
|
||||
.. autoclass:: LiveLocationAttachment()
|
||||
.. autoclass:: FileAttachment()
|
||||
.. autoclass:: AudioAttachment()
|
||||
.. autoclass:: ImageAttachment()
|
||||
.. autoclass:: VideoAttachment()
|
||||
.. autoclass:: ImageAttachment()
|
4
docs/api/client.rst
Normal file
4
docs/api/client.rst
Normal file
@@ -0,0 +1,4 @@
|
||||
Client
|
||||
======
|
||||
|
||||
.. autoclass:: Client
|
4
docs/api/events.rst
Normal file
4
docs/api/events.rst
Normal file
@@ -0,0 +1,4 @@
|
||||
Events
|
||||
======
|
||||
|
||||
.. autoclass:: Listener
|
8
docs/api/exceptions.rst
Normal file
8
docs/api/exceptions.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
Exceptions
|
||||
==========
|
||||
|
||||
.. autoexception:: FacebookError()
|
||||
.. autoexception:: HTTPError()
|
||||
.. autoexception:: ParseError()
|
||||
.. autoexception:: ExternalError()
|
||||
.. autoexception:: GraphQLError()
|
21
docs/api/index.rst
Normal file
21
docs/api/index.rst
Normal file
@@ -0,0 +1,21 @@
|
||||
.. module:: fbchat
|
||||
|
||||
.. Note: we're using () to hide the __init__ method where relevant
|
||||
|
||||
Full API
|
||||
========
|
||||
|
||||
If you are looking for information on a specific function, class, or method, this part of the documentation is for you.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
session
|
||||
client
|
||||
threads
|
||||
thread_data
|
||||
messages
|
||||
exceptions
|
||||
attachments
|
||||
events
|
||||
misc
|
8
docs/api/messages.rst
Normal file
8
docs/api/messages.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
Messages
|
||||
========
|
||||
|
||||
.. autoclass:: Message
|
||||
.. autoclass:: Mention
|
||||
.. autoclass:: EmojiSize(Enum)
|
||||
:undoc-members:
|
||||
.. autoclass:: MessageData()
|
20
docs/api/misc.rst
Normal file
20
docs/api/misc.rst
Normal file
@@ -0,0 +1,20 @@
|
||||
Miscellaneous
|
||||
=============
|
||||
|
||||
.. autoclass:: ThreadLocation(Enum)
|
||||
:undoc-members:
|
||||
.. autoclass:: ActiveStatus()
|
||||
|
||||
.. autoclass:: QuickReply
|
||||
.. autoclass:: QuickReplyText
|
||||
.. autoclass:: QuickReplyLocation
|
||||
.. autoclass:: QuickReplyPhoneNumber
|
||||
.. autoclass:: QuickReplyEmail
|
||||
|
||||
.. autoclass:: Poll
|
||||
.. autoclass:: PollOption
|
||||
|
||||
.. autoclass:: Plan
|
||||
.. autoclass:: PlanData()
|
||||
.. autoclass:: GuestStatus(Enum)
|
||||
:undoc-members:
|
4
docs/api/session.rst
Normal file
4
docs/api/session.rst
Normal file
@@ -0,0 +1,4 @@
|
||||
Session
|
||||
=======
|
||||
|
||||
.. autoclass:: Session()
|
6
docs/api/thread_data.rst
Normal file
6
docs/api/thread_data.rst
Normal file
@@ -0,0 +1,6 @@
|
||||
Thread Data
|
||||
===========
|
||||
|
||||
.. autoclass:: PageData()
|
||||
.. autoclass:: UserData()
|
||||
.. autoclass:: GroupData()
|
8
docs/api/threads.rst
Normal file
8
docs/api/threads.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
Threads
|
||||
=======
|
||||
|
||||
.. autoclass:: ThreadABC()
|
||||
.. autoclass:: Thread
|
||||
.. autoclass:: Page
|
||||
.. autoclass:: User
|
||||
.. autoclass:: Group
|
38
docs/conf.py
38
docs/conf.py
@@ -11,13 +11,18 @@ import sys
|
||||
|
||||
sys.path.insert(0, os.path.abspath(".."))
|
||||
|
||||
os.environ["_FBCHAT_DISABLE_FIX_MODULE_METADATA"] = "1"
|
||||
|
||||
import fbchat
|
||||
|
||||
del os.environ["_FBCHAT_DISABLE_FIX_MODULE_METADATA"]
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = fbchat.__name__
|
||||
copyright = fbchat.__copyright__
|
||||
author = fbchat.__author__
|
||||
copyright = "Copyright 2015 - 2018 by Taehoon Kim and 2018 - 2020 by Mads Marquart"
|
||||
author = "Taehoon Kim; Moreels Pieter-Jan; Mads Marquart"
|
||||
description = fbchat.__doc__.split("\n")[0]
|
||||
|
||||
# The short X.Y version
|
||||
version = fbchat.__version__
|
||||
@@ -37,10 +42,10 @@ needs_sphinx = "2.0"
|
||||
extensions = [
|
||||
"sphinx.ext.autodoc",
|
||||
"sphinx.ext.intersphinx",
|
||||
"sphinx.ext.todo",
|
||||
"sphinx.ext.viewcode",
|
||||
"sphinx.ext.napoleon",
|
||||
"sphinxcontrib.spelling",
|
||||
"sphinx_autodoc_typehints",
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
@@ -113,7 +118,7 @@ html_show_sourcelink = False
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#
|
||||
html_short_title = fbchat.__description__
|
||||
html_short_title = description
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ---------------------------------------------
|
||||
@@ -127,16 +132,14 @@ htmlhelp_basename = project + "doc"
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [(master_doc, project + ".tex", fbchat.__title__, author, "manual")]
|
||||
latex_documents = [(master_doc, project + ".tex", project, author, "manual")]
|
||||
|
||||
|
||||
# -- Options for manual page output ------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, project, fbchat.__title__, [x.strip() for x in author.split(";")], 1)
|
||||
]
|
||||
man_pages = [(master_doc, project, project, [x.strip() for x in author.split(";")], 1)]
|
||||
|
||||
|
||||
# -- Options for Texinfo output ----------------------------------------------
|
||||
@@ -145,15 +148,7 @@ man_pages = [
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(
|
||||
master_doc,
|
||||
project,
|
||||
fbchat.__title__,
|
||||
author,
|
||||
project,
|
||||
fbchat.__description__,
|
||||
"Miscellaneous",
|
||||
)
|
||||
(master_doc, project, project, author, project, description, "Miscellaneous",)
|
||||
]
|
||||
|
||||
|
||||
@@ -167,7 +162,7 @@ epub_exclude_files = ["search.html"]
|
||||
|
||||
# -- Options for autodoc extension ---------------------------------------
|
||||
|
||||
autoclass_content = "both"
|
||||
autoclass_content = "class"
|
||||
autodoc_member_order = "bysource"
|
||||
autodoc_default_options = {"members": True}
|
||||
|
||||
@@ -176,13 +171,6 @@ autodoc_default_options = {"members": True}
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {"https://docs.python.org/": None}
|
||||
|
||||
# -- Options for todo extension ----------------------------------------------
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = True
|
||||
|
||||
todo_link_only = True
|
||||
|
||||
# -- Options for napoleon extension ----------------------------------------------
|
||||
|
||||
# Use Google style docstrings
|
||||
|
41
docs/faq.rst
41
docs/faq.rst
@@ -1,42 +1,23 @@
|
||||
.. _faq:
|
||||
Frequently Asked Questions
|
||||
==========================
|
||||
|
||||
FAQ
|
||||
===
|
||||
The new version broke my application
|
||||
------------------------------------
|
||||
|
||||
Version X broke my installation
|
||||
-------------------------------
|
||||
``fbchat`` follows `Scemantic Versioning <https://semver.org/>`__ quite rigorously!
|
||||
|
||||
We try to provide backwards compatibility where possible, but since we're not part of Facebook,
|
||||
most of the things may be broken at any point in time
|
||||
That means that breaking changes can *only* occur in major versions (e.g. ``v1.9.6`` -> ``v2.0.0``).
|
||||
|
||||
Downgrade to an earlier version of ``fbchat``, run this command
|
||||
If you find that something breaks, and you didn't update to a new major version, then it is a bug, and we would be grateful if you reported it!
|
||||
|
||||
In case you're stuck with an old codebase, you can downgrade to a previous version of ``fbchat``, e.g. version ``1.9.6``:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ pip install fbchat==<X>
|
||||
|
||||
Where you replace ``<X>`` with the version you want to use
|
||||
$ pip install fbchat==1.9.6
|
||||
|
||||
|
||||
Will you be supporting creating posts/events/pages and so on?
|
||||
-------------------------------------------------------------
|
||||
|
||||
We won't be focusing on anything else than chat-related things. This API is called ``fbCHAT``, after all ;)
|
||||
|
||||
|
||||
Submitting Issues
|
||||
-----------------
|
||||
|
||||
If you're having trouble with some of the snippets, or you think some of the functionality is broken,
|
||||
please feel free to submit an issue on `GitHub <https://github.com/carpedm20/fbchat>`_.
|
||||
You should first login with ``logging_level`` set to ``logging.DEBUG``::
|
||||
|
||||
from fbchat import Client
|
||||
import logging
|
||||
client = Client('<email>', '<password>', logging_level=logging.DEBUG)
|
||||
|
||||
Then you can submit the relevant parts of this log, and detailed steps on how to reproduce
|
||||
|
||||
.. warning::
|
||||
Always remove your credentials from any debug information you may provide us.
|
||||
Preferably, use a test account, in case you miss anything
|
||||
We won't be focusing on anything else than chat-related things. This library is called ``fbCHAT``, after all!
|
||||
|
@@ -1,52 +1,22 @@
|
||||
.. fbchat documentation master file, created by
|
||||
sphinx-quickstart on Thu May 25 15:43:01 2017.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
.. See README.rst for explanation of these markers
|
||||
|
||||
.. This documentation's layout is heavily inspired by requests' layout: https://requests.readthedocs.io
|
||||
Some documentation is also partially copied from facebook-chat-api: https://github.com/Schmavery/facebook-chat-api
|
||||
.. include:: ../README.rst
|
||||
:end-before: inclusion-marker-intro-end
|
||||
|
||||
``fbchat``: Facebook Chat (Messenger) for Python
|
||||
================================================
|
||||
With that said, let's get started!
|
||||
|
||||
Release v\ |version|. (:ref:`install`)
|
||||
|
||||
Facebook Chat (`Messenger <https://www.facebook.com/messages/>`_) for Python.
|
||||
This project was inspired by `facebook-chat-api <https://github.com/Schmavery/facebook-chat-api>`_.
|
||||
|
||||
**No XMPP or API key is needed**. Just use your email and password.
|
||||
|
||||
Currently ``fbchat`` support Python 3.5, 3.6, 3.7 and 3.8:
|
||||
|
||||
``fbchat`` works by emulating the browser.
|
||||
This means doing the exact same GET/POST requests and tricking Facebook into thinking it's accessing the website normally.
|
||||
Therefore, this API requires the credentials of a Facebook account.
|
||||
|
||||
.. note::
|
||||
If you're having problems, please check the :ref:`faq`, before asking questions on GitHub
|
||||
|
||||
.. warning::
|
||||
We are not responsible if your account gets banned for spammy activities,
|
||||
such as sending lots of messages to people you don't know, sending messages very quickly,
|
||||
sending spammy looking URLs, logging in and out very quickly... Be responsible Facebook citizens.
|
||||
|
||||
.. note::
|
||||
Facebook now has an `official API <https://developers.facebook.com/docs/messenger-platform>`_ for chat bots,
|
||||
so if you're familiar with ``Node.js``, this might be what you're looking for.
|
||||
|
||||
If you're already familiar with the basics of how Facebook works internally, go to :ref:`examples` to see example usage of ``fbchat``
|
||||
.. include:: ../README.rst
|
||||
:start-after: inclusion-marker-installation-start
|
||||
:end-before: inclusion-marker-installation-end
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
Documentation Overview
|
||||
----------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
install
|
||||
intro
|
||||
examples
|
||||
testing
|
||||
api
|
||||
todo
|
||||
faq
|
||||
api/index
|
||||
|
@@ -1,43 +0,0 @@
|
||||
.. _install:
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
Install using pip
|
||||
-----------------
|
||||
|
||||
To install ``fbchat``, run this command:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ pip install fbchat
|
||||
|
||||
If you don't have `pip <https://pip.pypa.io>`_ installed,
|
||||
`this Python installation guide <http://docs.python-guide.org/en/latest/starting/installation/>`_
|
||||
can guide you through the process.
|
||||
|
||||
Get the Source Code
|
||||
-------------------
|
||||
|
||||
``fbchat`` is developed on GitHub, where the code is
|
||||
`always available <https://github.com/carpedm20/fbchat>`_.
|
||||
|
||||
You can either clone the public repository:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ git clone git://github.com/carpedm20/fbchat.git
|
||||
|
||||
Or, download a `tarball <https://github.com/carpedm20/fbchat/tarball/master>`_:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ curl -OL https://github.com/carpedm20/fbchat/tarball/master
|
||||
# optionally, zipball is also available (for Windows users).
|
||||
|
||||
Once you have a copy of the source, you can embed it in your own Python
|
||||
package, or install it into your site-packages easily:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ python setup.py install
|
218
docs/intro.rst
218
docs/intro.rst
@@ -1,194 +1,150 @@
|
||||
.. _intro:
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
``fbchat`` uses your email and password to communicate with the Facebook server.
|
||||
That means that you should always store your password in a separate file, in case e.g. someone looks over your shoulder while you're writing code.
|
||||
You should also make sure that the file's access control is appropriately restrictive
|
||||
Welcome, this page will guide you through the basic concepts of using ``fbchat``.
|
||||
|
||||
The hardest, and most error prone part is logging in, and managing your login session, so that is what we will look at first.
|
||||
|
||||
.. _intro_logging_in:
|
||||
|
||||
Logging In
|
||||
----------
|
||||
|
||||
Simply create an instance of `Client`. If you have two factor authentication enabled, type the code in the terminal prompt
|
||||
(If you want to supply the code in another fashion, overwrite `Client.on_2fa_code`)::
|
||||
Everything in ``fbchat`` starts with getting an instance of `Session`. Currently there are two ways of doing that, `Session.login` and `Session.from_cookies`.
|
||||
|
||||
from fbchat import Client
|
||||
from fbchat.models import *
|
||||
client = Client('<email>', '<password>')
|
||||
The follow example will prompt you for you password, and use it to login::
|
||||
|
||||
Replace ``<email>`` and ``<password>`` with your email and password respectively
|
||||
import getpass
|
||||
import fbchat
|
||||
session = fbchat.Session.login("<email/phone number>", getpass.getpass())
|
||||
# If your account requires a two factor authentication code:
|
||||
session = fbchat.Session.login(
|
||||
"<your email/phone number>",
|
||||
getpass.getpass(),
|
||||
lambda: getpass.getpass("2FA code"),
|
||||
)
|
||||
|
||||
.. note::
|
||||
For ease of use then most of the code snippets in this document will assume you've already completed the login process
|
||||
Though the second line, ``from fbchat.models import *``, is not strictly necessary here, later code snippets will assume you've done this
|
||||
However, **this is not something you should do often!** Logging in/out all the time *will* get your Facebook account locked!
|
||||
|
||||
If you want to change how verbose ``fbchat`` is, change the logging level (in `Client`)
|
||||
Instead, you should start by using `Session.login`, and then store the cookies with `Session.get_cookies`, so that they can be used instead the next time your application starts.
|
||||
|
||||
Throughout your code, if you want to check whether you are still logged in, use `Client.is_logged_in`.
|
||||
An example would be to login again if you've been logged out, using `Client.login`::
|
||||
Usability-wise, this is also better, since you won't have to re-type your password every time you want to login.
|
||||
|
||||
if not client.is_logged_in():
|
||||
client.login('<email>', '<password>')
|
||||
The following, quite lengthy, yet very import example, illustrates a way to do this:
|
||||
|
||||
When you're done using the client, and want to securely logout, use `Client.logout`::
|
||||
.. literalinclude:: ../examples/session_handling.py
|
||||
|
||||
client.logout()
|
||||
Assuming you have successfully completed the above, congratulations! Using ``fbchat`` should be mostly trouble free from now on!
|
||||
|
||||
|
||||
.. _intro_threads:
|
||||
Understanding Thread Ids
|
||||
------------------------
|
||||
|
||||
Threads
|
||||
-------
|
||||
At the core of any thread is its unique identifier, its ID.
|
||||
|
||||
A thread can refer to two things: A Messenger group chat (`Group`) or a single Facebook user (`User`).
|
||||
A thread basically just means "something I can chat with", but more precisely, it can refer to a few things:
|
||||
- A Messenger group thread (`Group`)
|
||||
- The conversation between you and a single Facebook user (`User`)
|
||||
- The conversation between you and a Facebook Page (`Page`)
|
||||
|
||||
Searching for group chats and finding their ID can be done via. `Client.search_for_groups`,
|
||||
and searching for users is possible via. `Client.search_for_users`. See :ref:`intro_fetching`
|
||||
You can get your own user ID with `Session.user_id`.
|
||||
|
||||
You can get your own user ID by using `Session.user_id`
|
||||
Getting the ID of a specific group thread is fairly trivial, you only need to login to `<https://www.messenger.com/>`_, click on the group you want to find the ID of, and then read the id from the address bar.
|
||||
The URL will look something like this: ``https://www.messenger.com/t/1234567890``, where ``1234567890`` would be the ID of the group.
|
||||
|
||||
Getting the ID of a group chat is fairly trivial otherwise, since you only need to navigate to `<https://www.facebook.com/messages/>`_,
|
||||
click on the group you want to find the ID of, and then read the id from the address bar.
|
||||
The URL will look something like this: ``https://www.facebook.com/messages/t/1234567890``, where ``1234567890`` would be the ID of the group.
|
||||
An image to illustrate this is shown below:
|
||||
The same method can be applied to some user accounts, though if they have set a custom URL, then you will have to use a different method.
|
||||
|
||||
An image to illustrate the process is shown below:
|
||||
|
||||
.. image:: /_static/find-group-id.png
|
||||
:alt: An image illustrating how to find the ID of a group
|
||||
|
||||
The same method can be applied to some user accounts, though if they've set a custom URL, then you'll just see that URL instead
|
||||
Once you have an ID, you can use it to create a `Group` or a `User` instance, which will allow you to do all sorts of things. To do this, you need a valid, logged in session::
|
||||
|
||||
Here's an snippet showing the usage of thread IDs and thread types, where ``<user id>`` and ``<group id>``
|
||||
corresponds to the ID of a single user, and the ID of a group respectively::
|
||||
group = fbchat.Group(session=session, id="<The id you found>")
|
||||
# Or for user threads
|
||||
user = fbchat.User(session=session, id="<The id you found>")
|
||||
|
||||
user.send(Message(text='<message>'))
|
||||
group.send(Message(text='<message>'))
|
||||
Just like threads, every message, poll, plan, attachment, action etc. you send or do on Facebook has a unique ID.
|
||||
|
||||
Some functions don't require a thread type, so in these cases you just provide the thread ID::
|
||||
Below is an example of using such a message ID to get a `Message` instance::
|
||||
|
||||
thread = fbchat.Thread(session=session, id="<user-or-group-id>")
|
||||
thread.set_color("#a695c7")
|
||||
thread.set_color("#67b868")
|
||||
# Provide the thread the message was created in, and it's ID
|
||||
message = fbchat.Message(thread=user, id="<The message id>")
|
||||
|
||||
|
||||
.. _intro_message_ids:
|
||||
|
||||
Message IDs
|
||||
-----------
|
||||
|
||||
Every message you send on Facebook has a unique ID, and every action you do in a thread,
|
||||
like changing a nickname or adding a person, has a unique ID too.
|
||||
|
||||
This snippet shows how to send a message, and then use the returned ID to react to that message with a 😍 emoji::
|
||||
|
||||
message = thread.send_text("A message!")
|
||||
message.react("😍")
|
||||
|
||||
|
||||
.. _intro_interacting:
|
||||
|
||||
Interacting with Threads
|
||||
------------------------
|
||||
|
||||
``fbchat`` provides multiple functions for interacting with threads
|
||||
|
||||
Most functionality works on all threads, though some things,
|
||||
like adding users to and removing users from a group chat, logically only works on group chats
|
||||
|
||||
The simplest way of using ``fbchat`` is to send a message.
|
||||
The following snippet will, as you've probably already figured out, send the message ``test message`` to your account::
|
||||
|
||||
user = User(session=session, id=session.user_id)
|
||||
message_id = user.send(Message(text='test message'))
|
||||
|
||||
You can see a full example showing all the possible thread interactions with ``fbchat`` by going to :ref:`examples`
|
||||
|
||||
|
||||
.. _intro_fetching:
|
||||
|
||||
Fetching Information
|
||||
--------------------
|
||||
|
||||
You can use ``fbchat`` to fetch basic information like user names, profile pictures, thread names and user IDs
|
||||
Managing these ids yourself quickly becomes very cumbersome! Luckily, there are other, easier ways of getting `Group`/`User` instances.
|
||||
|
||||
You can retrieve a user's ID with `Client.search_for_users`.
|
||||
The following snippet will search for users by their name, take the first (and most likely) user, and then get their user ID from the result::
|
||||
You would start by creating a `Client` instance, which is basically just a helper on top of `Session`, that will allow you to do various things::
|
||||
|
||||
users = client.search_for_users('<name of user>')
|
||||
user = users[0]
|
||||
print("User's ID: {}".format(user.id))
|
||||
print("User's name: {}".format(user.name))
|
||||
print("User's profile picture URL: {}".format(user.photo))
|
||||
print("User's main URL: {}".format(user.url))
|
||||
client = fbchat.Client(session=session)
|
||||
|
||||
Since this uses Facebook's search functions, you don't have to specify the whole name, first names will usually be enough
|
||||
Now, you could search for threads using `Client.search_for_threads`, or fetch a list of them using `Client.fetch_threads`::
|
||||
|
||||
You can see a full example showing all the possible ways to fetch information with ``fbchat`` by going to :ref:`examples`
|
||||
# Fetch the 5 most likely search results
|
||||
# Uses Facebook's search functions, you don't have to specify the whole name, first names will usually be enough
|
||||
threads = list(client.search_for_threads("<name of the thread to search for>", limit=5))
|
||||
# Fetch the 5 most recent threads in your account
|
||||
threads = list(client.fetch_threads(limit=5))
|
||||
|
||||
Note the `list` statements; this is because the methods actually return `generators <https://wiki.python.org/moin/Generators>`__. If you don't know what that means, don't worry, it is just something you can use to make your code faster later.
|
||||
|
||||
The examples above will actually fetch `UserData`/`GroupData`, which are subclasses of `User`/`Group`. These model have extra properties, so you could for example print the names and ids of the fetched threads like this::
|
||||
|
||||
for thread in threads:
|
||||
print(f"{thread.id}: {thread.name}")
|
||||
|
||||
Once you have a thread, you can use that to fetch the messages therein::
|
||||
|
||||
for message in thread.fetch_messages(limit=20):
|
||||
print(message.text)
|
||||
|
||||
|
||||
.. _intro_sessions:
|
||||
Interacting with Threads
|
||||
------------------------
|
||||
|
||||
Sessions
|
||||
--------
|
||||
Once you have a `User`/`Group` instance, you can do things on them as described in `ThreadABC`, since they are subclasses of that.
|
||||
|
||||
``fbchat`` provides functions to retrieve and set the session cookies.
|
||||
This will enable you to store the session cookies in a separate file, so that you don't have to login each time you start your script.
|
||||
Use `Client.get_gession` to retrieve the cookies::
|
||||
Some functionality, like adding users to a `Group`, or blocking a `User`, logically only works the relevant threads, so see the full API documentation for that.
|
||||
|
||||
session_cookies = client.get_gession()
|
||||
With that out of the way, let's see some examples!
|
||||
|
||||
Then you can use `Client.set_gession`::
|
||||
The simplest way of interracting with a thread is by sending a message::
|
||||
|
||||
client.set_gession(session_cookies)
|
||||
# Send a message to the user
|
||||
message = user.send_text("test message")
|
||||
|
||||
Or you can set the ``session_cookies`` on your initial login.
|
||||
(If the session cookies are invalid, your email and password will be used to login instead)::
|
||||
There are many types of messages you can send, see the full API documentation for more.
|
||||
|
||||
client = Client('<email>', '<password>', session_cookies=session_cookies)
|
||||
Notice how we held on to the sent message? The return type i a `Message` instance, so you can interract with it afterwards::
|
||||
|
||||
.. warning::
|
||||
You session cookies can be just as valuable as you password, so store them with equal care
|
||||
# React to the message with the 😍 emoji
|
||||
message.react("😍")
|
||||
|
||||
Besides sending messages, you can also interract with threads in other ways. An example is to change the thread color::
|
||||
|
||||
# Will change the thread color to the default blue
|
||||
thread.set_color("#0084ff")
|
||||
|
||||
.. _intro_events:
|
||||
|
||||
Listening & Events
|
||||
------------------
|
||||
|
||||
To use the listening functions ``fbchat`` offers (like `Client.listen`),
|
||||
you have to define what should be executed when certain events happen.
|
||||
By default, (most) events will just be a `logging.info` statement,
|
||||
meaning it will simply print information to the console when an event happens
|
||||
Now, we are finally at the point we have all been waiting for: Creating an automatic Facebook bot!
|
||||
|
||||
.. note::
|
||||
You can identify the event methods by their ``on`` prefix, e.g. ``on_message``
|
||||
To get started, you create your methods that will handle your events::
|
||||
|
||||
The event actions can be changed by subclassing the `Client`, and then overwriting the event methods::
|
||||
def on_message(event):
|
||||
print(f"Message from {event.author.id}: {event.message.text}")
|
||||
|
||||
class CustomClient(Client):
|
||||
def on_message(self, mid, author_id, message_object, thread, ts, metadata, msg, **kwargs):
|
||||
# Do something with message_object here
|
||||
pass
|
||||
And then you create a listener object, and start handling the incoming events::
|
||||
|
||||
client = CustomClient('<email>', '<password>')
|
||||
listener = fbchat.Listener.connect(session, False, False)
|
||||
|
||||
**Notice:** The following snippet is as equally valid as the previous one::
|
||||
for event in listener.listen():
|
||||
if isinstance(event, fbchat.MessageEvent):
|
||||
on_message(event)
|
||||
|
||||
class CustomClient(Client):
|
||||
def on_message(self, message_object, author_id, thread, **kwargs):
|
||||
# Do something with message_object here
|
||||
pass
|
||||
|
||||
client = CustomClient('<email>', '<password>')
|
||||
|
||||
The change was in the parameters that our ``on_message`` method took: ``message_object`` and ``author_id`` got swapped,
|
||||
and ``mid``, ``ts``, ``metadata`` and ``msg`` got removed, but the function still works, since we included ``**kwargs``
|
||||
|
||||
.. note::
|
||||
Therefore, for both backwards and forwards compatibility,
|
||||
the API actually requires that you include ``**kwargs`` as your final argument.
|
||||
|
||||
View the :ref:`examples` to see some more examples illustrating the event system
|
||||
View the :ref:`examples` to see some more examples illustrating the event system.
|
||||
|
@@ -1,4 +1,6 @@
|
||||
iterables
|
||||
iterable
|
||||
mimetype
|
||||
timestamp
|
||||
metadata
|
||||
spam
|
||||
@@ -12,3 +14,4 @@ spritemap
|
||||
online
|
||||
inbox
|
||||
subclassing
|
||||
codebase
|
||||
|
@@ -1,25 +0,0 @@
|
||||
.. _testing:
|
||||
|
||||
Testing
|
||||
=======
|
||||
|
||||
To use the tests, copy ``tests/data.json`` to ``tests/my_data.json`` or type the information manually in the terminal prompts.
|
||||
|
||||
- email: Your (or a test user's) email / phone number
|
||||
- password: Your (or a test user's) password
|
||||
- group_thread_id: A test group that will be used to test group functionality
|
||||
- user_thread_id: A person that will be used to test kick/add functionality (This user should be in the group)
|
||||
|
||||
Please remember to test all supported python versions.
|
||||
If you've made any changes to the 2FA functionality, test it with a 2FA enabled account.
|
||||
|
||||
If you only want to execute specific tests, pass the function names in the command line (not including the ``test_`` prefix). Example:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ python tests.py sendMessage sessions sendEmoji
|
||||
|
||||
.. warning::
|
||||
|
||||
Do not execute the full set of tests in too quick succession. This can get your account temporarily blocked for spam!
|
||||
(You should execute the script at max about 10 times a day)
|
@@ -1,22 +0,0 @@
|
||||
.. _todo:
|
||||
|
||||
Todo
|
||||
====
|
||||
|
||||
This page will be periodically updated to show missing features and documentation
|
||||
|
||||
|
||||
Missing Functionality
|
||||
---------------------
|
||||
|
||||
- Implement ``Client.search_for_message``
|
||||
- This will use the GraphQL request API
|
||||
- Implement chatting with pages properly
|
||||
- Write better FAQ
|
||||
- Explain usage of GraphQL
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
.. todolist::
|
42
examples/session_handling.py
Normal file
42
examples/session_handling.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# TODO: Consider adding Session.from_file and Session.to_file,
|
||||
# which would make this example a lot easier!
|
||||
|
||||
import atexit
|
||||
import json
|
||||
import getpass
|
||||
import fbchat
|
||||
|
||||
|
||||
def load_cookies(filename):
|
||||
try:
|
||||
# Load cookies from file
|
||||
with open(filename) as f:
|
||||
return json.load(f)
|
||||
except FileNotFoundError:
|
||||
return # No cookies yet
|
||||
|
||||
|
||||
def save_cookies(filename, cookies):
|
||||
with open(filename, "w") as f:
|
||||
json.dump(f, cookies)
|
||||
|
||||
|
||||
def load_session(cookies):
|
||||
if not cookies:
|
||||
return
|
||||
try:
|
||||
return fbchat.Session.from_cookies(cookies)
|
||||
except fbchat.FacebookError:
|
||||
return # Failed loading from cookies
|
||||
|
||||
|
||||
cookies = load_cookies("session.json")
|
||||
session = load_session(cookies)
|
||||
if not session:
|
||||
# Session could not be loaded, login instead!
|
||||
session = fbchat.Session.login("<email>", getpass.getpass())
|
||||
|
||||
# Save session cookies to file when the program exits
|
||||
atexit.register(lambda: save_cookies("session.json", session.get_cookies()))
|
||||
|
||||
# Do stuff with session here
|
@@ -1,7 +1,11 @@
|
||||
"""Facebook Chat (Messenger) for Python
|
||||
"""Facebook Messenger for Python.
|
||||
|
||||
:copyright: (c) 2015 - 2019 by Taehoon Kim
|
||||
:license: BSD 3-Clause, see LICENSE for more details.
|
||||
Copyright:
|
||||
(c) 2015 - 2018 by Taehoon Kim
|
||||
(c) 2018 - 2020 by Mads Marquart
|
||||
|
||||
License:
|
||||
BSD 3-Clause, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
import logging as _logging
|
||||
@@ -84,47 +88,12 @@ from ._mqtt import Listener
|
||||
|
||||
from ._client import Client
|
||||
|
||||
__title__ = "fbchat"
|
||||
__version__ = "1.9.6"
|
||||
__description__ = "Facebook Chat (Messenger) for Python"
|
||||
|
||||
__copyright__ = "Copyright 2015 - 2019 by Taehoon Kim"
|
||||
__license__ = "BSD 3-Clause"
|
||||
|
||||
__author__ = "Taehoon Kim; Moreels Pieter-Jan; Mads Marquart"
|
||||
__email__ = "carpedm20@gmail.com"
|
||||
|
||||
__all__ = ("Session", "Listener", "Client")
|
||||
|
||||
# Everything below is taken from the excellent trio project:
|
||||
|
||||
from . import _fix_module_metadata
|
||||
|
||||
def fixup_module_metadata(namespace):
|
||||
def fix_one(qualname, name, obj):
|
||||
mod = getattr(obj, "__module__", None)
|
||||
if mod is not None and mod.startswith("fbchat."):
|
||||
obj.__module__ = "fbchat"
|
||||
# Modules, unlike everything else in Python, put fully-qualitied
|
||||
# names into their __name__ attribute. We check for "." to avoid
|
||||
# rewriting these.
|
||||
if hasattr(obj, "__name__") and "." not in obj.__name__:
|
||||
obj.__name__ = name
|
||||
obj.__qualname__ = qualname
|
||||
if isinstance(obj, type):
|
||||
# Fix methods
|
||||
for attr_name, attr_value in obj.__dict__.items():
|
||||
fix_one(objname + "." + attr_name, attr_name, attr_value)
|
||||
|
||||
for objname, obj in namespace.items():
|
||||
if not objname.startswith("_"): # ignore private attributes
|
||||
fix_one(objname, objname, obj)
|
||||
|
||||
|
||||
# Having the public path in .__module__ attributes is important for:
|
||||
# - exception names in printed tracebacks
|
||||
# - sphinx :show-inheritance:
|
||||
# - deprecation warnings
|
||||
# - pickle
|
||||
# - probably other stuff
|
||||
fixup_module_metadata(globals())
|
||||
del fixup_module_metadata
|
||||
_fix_module_metadata.fixup_module_metadata(globals())
|
||||
del _fix_module_metadata
|
||||
|
@@ -477,15 +477,12 @@ class Client:
|
||||
|
||||
Args:
|
||||
threads: Threads to set as unread
|
||||
at: Timestam to signal the read cursor at
|
||||
at: Timestamp to signal the read cursor at
|
||||
"""
|
||||
return self._read_status(False, threads, at)
|
||||
|
||||
def mark_as_seen(self):
|
||||
"""
|
||||
Todo:
|
||||
Documenting this
|
||||
"""
|
||||
# TODO: Documenting this
|
||||
j = self.session._payload_post(
|
||||
"/ajax/mercury/mark_seen.php", {"seen_timestamp": _util.now()}
|
||||
)
|
||||
|
39
fbchat/_fix_module_metadata.py
Normal file
39
fbchat/_fix_module_metadata.py
Normal file
@@ -0,0 +1,39 @@
|
||||
"""Everything in this module is taken from the excellent trio project.
|
||||
|
||||
Having the public path in .__module__ attributes is important for:
|
||||
- exception names in printed tracebacks
|
||||
- ~sphinx :show-inheritance:~
|
||||
- deprecation warnings
|
||||
- pickle
|
||||
- probably other stuff
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
|
||||
def fixup_module_metadata(namespace):
|
||||
def fix_one(qualname, name, obj):
|
||||
mod = getattr(obj, "__module__", None)
|
||||
if mod is not None and mod.startswith("fbchat."):
|
||||
obj.__module__ = "fbchat"
|
||||
# Modules, unlike everything else in Python, put fully-qualitied
|
||||
# names into their __name__ attribute. We check for "." to avoid
|
||||
# rewriting these.
|
||||
if hasattr(obj, "__name__") and "." not in obj.__name__:
|
||||
obj.__name__ = name
|
||||
obj.__qualname__ = qualname
|
||||
if isinstance(obj, type):
|
||||
# Fix methods
|
||||
for attr_name, attr_value in obj.__dict__.items():
|
||||
fix_one(objname + "." + attr_name, attr_name, attr_value)
|
||||
|
||||
for objname, obj in namespace.items():
|
||||
if not objname.startswith("_"): # ignore private attributes
|
||||
fix_one(objname, objname, obj)
|
||||
|
||||
|
||||
# Allow disabling this when running Sphinx
|
||||
# This is done so that Sphinx autodoc can detect the file's source
|
||||
# TODO: Find a better way to detect when we're running Sphinx!
|
||||
if os.environ.get("_FBCHAT_DISABLE_FIX_MODULE_METADATA") == "1":
|
||||
fixup_module_metadata = lambda namespace: None
|
@@ -8,6 +8,8 @@ from . import _session, _plan, _thread
|
||||
class Page(_thread.ThreadABC):
|
||||
"""Represents a Facebook page. Implements `ThreadABC`."""
|
||||
|
||||
# TODO: Implement pages properly, the implementation is lacking in a lot of places!
|
||||
|
||||
#: The session to use when making requests.
|
||||
session = attr.ib(type=_session.Session)
|
||||
#: The unique identifier of the page.
|
||||
|
@@ -329,6 +329,8 @@ class Session:
|
||||
raise _exception.ParseError("Missing payload", data=j) from e
|
||||
|
||||
def _graphql_requests(self, *queries):
|
||||
# TODO: Explain usage of GraphQL, probably in the docs
|
||||
# Perhaps provide this API as public?
|
||||
data = {
|
||||
"method": "GET",
|
||||
"response_format": "json",
|
||||
|
@@ -110,7 +110,7 @@ class ThreadABC(metaclass=abc.ABCMeta):
|
||||
reply_to_id: Optional message to reply to
|
||||
|
||||
Returns:
|
||||
:ref:`Message ID <intro_message_ids>` of the sent message
|
||||
The sent message
|
||||
"""
|
||||
data = self._to_send_data()
|
||||
data["action_type"] = "ma-type:user-generated-message"
|
||||
@@ -139,7 +139,7 @@ class ThreadABC(metaclass=abc.ABCMeta):
|
||||
size: The size of the emoji
|
||||
|
||||
Returns:
|
||||
:ref:`Message ID <intro_message_ids>` of the sent message
|
||||
The sent message
|
||||
"""
|
||||
data = self._to_send_data()
|
||||
data["action_type"] = "ma-type:user-generated-message"
|
||||
@@ -154,7 +154,7 @@ class ThreadABC(metaclass=abc.ABCMeta):
|
||||
sticker_id: ID of the sticker to send
|
||||
|
||||
Returns:
|
||||
:ref:`Message ID <intro_message_ids>` of the sent message
|
||||
The sent message
|
||||
"""
|
||||
data = self._to_send_data()
|
||||
data["action_type"] = "ma-type:user-generated-message"
|
||||
@@ -420,7 +420,7 @@ class ThreadABC(metaclass=abc.ABCMeta):
|
||||
def set_color(self, color: str):
|
||||
"""Change thread color.
|
||||
|
||||
The new color must be one of the following:
|
||||
The new color must be one of the following::
|
||||
|
||||
"#0084ff", "#44bec7", "#ffc300", "#fa3c4c", "#d696bb", "#6699cc", "#13cf13",
|
||||
"#ff7e29", "#e68585", "#7646ff", "#20cef5", "#67b868", "#d4a88c", "#ff5ca1",
|
||||
|
@@ -56,7 +56,8 @@ test = [
|
||||
]
|
||||
docs = [
|
||||
"sphinx~=2.0",
|
||||
"sphinxcontrib-spelling~=4.0"
|
||||
"sphinxcontrib-spelling~=4.0",
|
||||
"sphinx-autodoc-typehints~=1.10",
|
||||
]
|
||||
lint = [
|
||||
"black",
|
||||
|
Reference in New Issue
Block a user