Skip to content

Commit 896392d

Browse files
authored
Merge branch 'master' into fix-docs
2 parents 61c5d6f + 0fb00c4 commit 896392d

33 files changed

+1722
-119
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@ install:
1818
script:
1919
- nosetests -v --with-flaky --no-flaky-report --with-coverage --cover-package=telegram/ tests
2020
- if [[ $TRAVIS_PYTHON_VERSION == 3.5 ]]; then pre-commit run --all-files; fi
21+
- python ./setup.py bdist_dumb
2122
after_success:
2223
coveralls

AUTHORS.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ The following wonderful people contributed directly or indirectly to this projec
2424
- `Eli Gao <https://github.com/eligao>`_
2525
- `ErgoZ Riftbit Vaper <https://github.com/ergoz>`_
2626
- `Eugene Lisitsky <https://github.com/lisitsky>`_
27+
- `Eugenio Panadero <https://github.com/azogue>`_
2728
- `evgfilim1 <https://github.com/evgfilim1>`_
2829
- `franciscod <https://github.com/franciscod>`_
2930
- `Hugo Damer <https://github.com/HakimusGIT>`_

examples/paymentbot.py

Whitespace-only changes.

telegram/__init__.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@
5050
from .messageentity import MessageEntity
5151
from .animation import Animation
5252
from .game import Game
53+
from .shippingaddress import ShippingAddress
54+
from .orderinfo import OrderInfo
55+
from .successfulpayment import SuccessfulPayment
56+
from .invoice import Invoice
5357
from .message import Message
5458
from .inputmessagecontent import InputMessageContent
5559
from .callbackquery import CallbackQuery
@@ -82,6 +86,10 @@
8286
from .inputlocationmessagecontent import InputLocationMessageContent
8387
from .inputvenuemessagecontent import InputVenueMessageContent
8488
from .inputcontactmessagecontent import InputContactMessageContent
89+
from .labeledprice import LabeledPrice
90+
from .shippingoption import ShippingOption
91+
from .precheckoutquery import PreCheckoutQuery
92+
from .shippingquery import ShippingQuery
8593
from .webhookinfo import WebhookInfo
8694
from .gamehighscore import GameHighScore
8795
from .videonote import VideoNote
@@ -114,5 +122,6 @@
114122
'Video', 'Voice', 'MAX_MESSAGE_LENGTH', 'MAX_CAPTION_LENGTH', 'SUPPORTED_WEBHOOK_PORTS',
115123
'MAX_FILESIZE_DOWNLOAD', 'MAX_FILESIZE_UPLOAD', 'MAX_MESSAGES_PER_SECOND_PER_CHAT',
116124
'MAX_MESSAGES_PER_SECOND', 'MAX_MESSAGES_PER_MINUTE_PER_GROUP', 'WebhookInfo', 'Animation',
117-
'Game', 'GameHighScore', 'VideoNote'
125+
'Game', 'GameHighScore', 'VideoNote', 'LabeledPrice', 'SuccessfulPayment', 'ShippingOption',
126+
'ShippingAddress', 'PreCheckoutQuery', 'OrderInfo', 'Invoice', 'ShippingQuery'
118127
]

telegram/bot.py

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1818,6 +1818,182 @@ def get_game_high_scores(self,
18181818

18191819
return [GameHighScore.de_json(hs, self) for hs in result]
18201820

1821+
@log
1822+
@message
1823+
def send_invoice(self,
1824+
chat_id,
1825+
title,
1826+
description,
1827+
payload,
1828+
provider_token,
1829+
start_parameter,
1830+
currency,
1831+
prices,
1832+
photo_url=None,
1833+
photo_size=None,
1834+
photo_width=None,
1835+
photo_height=None,
1836+
need_name=None,
1837+
need_phone_number=None,
1838+
need_shipping_address=None,
1839+
is_flexible=None,
1840+
disable_notification=False,
1841+
reply_to_message_id=None,
1842+
reply_markup=None,
1843+
timeout=None,
1844+
**kwargs):
1845+
"""
1846+
Use this method to send invoices.
1847+
1848+
Args:
1849+
chat_id (int|str): Unique identifier for the target private chat
1850+
title (str): Product name
1851+
description (str): Product description
1852+
payload (str): Bot-defined invoice payload, 1-128 bytes. This will not be displayed
1853+
to the user, use for your internal processes.
1854+
provider_token (str): Payments provider token, obtained via Botfather
1855+
start_parameter (str): Unique deep-linking parameter that can be used to generate
1856+
this invoice when used as a start parameter
1857+
currency (str): Three-letter ISO 4217 currency code
1858+
prices (List[:class:`telegram.LabeledPrice`]): Price breakdown, a list of components
1859+
(e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.)
1860+
photo_url (Optional[str]): URL of the product photo for the invoice. Can be a photo of
1861+
the goods or a marketing image for a service. People like it better when they
1862+
see what they are paying for.
1863+
photo_size (Optional[str]): Photo size
1864+
photo_width (Optional[int]): Photo width
1865+
photo_height (Optional[int]): Photo height
1866+
need_name (Optional[bool]): Pass True, if you require the user's full name to complete
1867+
the order
1868+
need_phone_number (Optional[bool]): Pass True, if you require the user's phone number
1869+
to complete the order
1870+
need_shipping_address (Optional[bool]): Pass True, if you require the user's shipping
1871+
address to complete the order
1872+
is_flexible (Optional[bool]): Pass True, if the final price depends on the shipping
1873+
method
1874+
disable_notification (Optional[bool]): Sends the message silently. iOS users will not
1875+
receive a notification, Android users will receive a notification with no sound.
1876+
reply_to_message_id (Optional[int]): If the message is a reply, ID of the original
1877+
message.
1878+
reply_markup (Optional[:class:`telegram.ReplyMarkup`]): Additional interface options.
1879+
An inlinekeyboard. If empty, one 'Pay total price' button will be shown. If not
1880+
empty, the first button must be a Pay button.
1881+
timeout (Optional[int|float]): If this value is specified, use it as the read timeout
1882+
from the server (instead of the one specified during creation of the connection
1883+
pool).
1884+
**kwargs (dict): Arbitrary keyword arguments.
1885+
1886+
Returns:
1887+
:class:`telegram.Message`: On success, instance representing the message posted.
1888+
1889+
Raises:
1890+
:class:`telegram.TelegramError`
1891+
1892+
"""
1893+
url = '{0}/sendInvoice'.format(self.base_url)
1894+
1895+
data = {
1896+
'chat_id': chat_id,
1897+
'title': title,
1898+
'description': description,
1899+
'payload': payload,
1900+
'provider_token': provider_token,
1901+
'start_parameter': start_parameter,
1902+
'currency': currency,
1903+
'prices': [p.to_dict() for p in prices]
1904+
}
1905+
1906+
if photo_url is not None:
1907+
data['photo_url'] = photo_url
1908+
if photo_size is not None:
1909+
data['photo_size'] = photo_size
1910+
if photo_width is not None:
1911+
data['photo_width'] = photo_width
1912+
if photo_height is not None:
1913+
data['photo_height'] = photo_height
1914+
if need_name is not None:
1915+
data['need_name'] = need_name
1916+
if need_phone_number is not None:
1917+
data['need_phone_number'] = need_phone_number
1918+
if need_shipping_address is not None:
1919+
data['need_shipping_address'] = need_shipping_address
1920+
if is_flexible is not None:
1921+
data['is_flexible'] = is_flexible
1922+
1923+
return url, data
1924+
1925+
def answer_shipping_query(self,
1926+
shipping_query_id,
1927+
ok,
1928+
shipping_options=None,
1929+
error_message=None):
1930+
"""
1931+
If you sent an invoice requesting a shipping address and the parameter is_flexible was
1932+
specified, the Bot API will send an Update with a shipping_query field to the bot. Use
1933+
this method to reply to shipping queries.
1934+
1935+
Args:
1936+
shipping_query_id (str): Unique identifier for the query to be answered
1937+
ok (bool): Specify True if delivery to the specified address is possible and False if
1938+
there are any problems (for example, if delivery to the specified address
1939+
is not possible)
1940+
shipping_options (Optional[List[:class:`telegram.ShippingOption`]]): Required if ok is
1941+
True. A list of available shipping options.
1942+
error_message (Optional[str]): Required if ok is False. Error message in human readable
1943+
form that explains why it is impossible to complete the order (e.g. "Sorry,
1944+
delivery to your desired address is unavailable'). Telegram will display this
1945+
message to the user.
1946+
1947+
Returns:
1948+
bool: On success, `True` is returned.
1949+
1950+
Raises:
1951+
:class:`telegram.TelegramError`
1952+
1953+
"""
1954+
url = '{0]/answerShippingQuery'.format(self.base_url)
1955+
1956+
data = {'shipping_query_id': shipping_query_id, 'ok': ok}
1957+
1958+
if shipping_options is not None:
1959+
data['shipping_options'] = shipping_options
1960+
if error_message is not None:
1961+
data['error_message'] = error_message
1962+
1963+
return url, data
1964+
1965+
def answer_pre_checkout_query(self, pre_checkout_query_id, ok, error_message=None):
1966+
"""
1967+
If you sent an invoice requesting a shipping address and the parameter is_flexible was
1968+
specified, the Bot API will send an Update with a shipping_query field to the bot.
1969+
Use this method to reply to shipping queries.
1970+
1971+
Args:
1972+
pre_checkout_query_id (str): Unique identifier for the query to be answered
1973+
ok (bool): Specify True if everything is alright (goods are available, etc.) and the
1974+
bot is ready to proceed with the order. Use False if there are any problems.
1975+
error_message (Optional[str]): Required if ok is False. Error message in human readable
1976+
form that explains the reason for failure to proceed with the checkout (e.g.
1977+
"Sorry, somebody just bought the last of our amazing black T-shirts while you were
1978+
busy filling out your payment details. Please choose a different color or
1979+
garment!"). Telegram will display this message to the user.
1980+
1981+
Returns:
1982+
bool: On success, `True` is returned.
1983+
1984+
Raises:
1985+
:class:`telegram.TelegramError`
1986+
1987+
"""
1988+
url = '{0]/answerPreCheckoutQuery'.format(self.base_url)
1989+
1990+
data = {'pre_checkout_query_id': pre_checkout_query_id, 'ok': ok}
1991+
1992+
if error_message is not None:
1993+
data['error_message'] = error_message
1994+
1995+
return url, data
1996+
18211997
@staticmethod
18221998
def de_json(data, bot):
18231999
data = super(Bot, Bot).de_json(data, bot)
@@ -1873,3 +2049,6 @@ def __reduce__(self):
18732049
getWebhookInfo = get_webhook_info
18742050
setGameScore = set_game_score
18752051
getGameHighScores = get_game_high_scores
2052+
sendInvoice = send_invoice
2053+
answerShippingQuery = answer_shipping_query
2054+
answerPreCheckoutQuery = answer_pre_checkout_query

telegram/ext/filters.py

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -214,13 +214,68 @@ def filter(self, message):
214214

215215
class _StatusUpdate(BaseFilter):
216216

217+
class _NewChatMembers(BaseFilter):
218+
219+
def filter(self, message):
220+
return bool(message.new_chat_members)
221+
222+
new_chat_members = _NewChatMembers()
223+
224+
class _LeftChatMember(BaseFilter):
225+
226+
def filter(self, message):
227+
return bool(message.left_chat_member)
228+
229+
left_chat_member = _LeftChatMember()
230+
231+
class _NewChatTitle(BaseFilter):
232+
233+
def filter(self, message):
234+
return bool(message.new_chat_title)
235+
236+
new_chat_title = _NewChatTitle()
237+
238+
class _NewChatPhoto(BaseFilter):
239+
240+
def filter(self, message):
241+
return bool(message.new_chat_photo)
242+
243+
new_chat_photo = _NewChatPhoto()
244+
245+
class _DeleteChatPhoto(BaseFilter):
246+
247+
def filter(self, message):
248+
return bool(message.delete_chat_photo)
249+
250+
delete_chat_photo = _DeleteChatPhoto()
251+
252+
class _ChatCreated(BaseFilter):
253+
254+
def filter(self, message):
255+
return bool(message.group_chat_created or message.supergroup_chat_created or
256+
message.channel_chat_created)
257+
258+
chat_created = _ChatCreated()
259+
260+
class _Migrate(BaseFilter):
261+
262+
def filter(self, message):
263+
return bool(message.migrate_from_chat_id or message.migrate_to_chat_id)
264+
265+
migrate = _Migrate()
266+
267+
class _PinnedMessage(BaseFilter):
268+
269+
def filter(self, message):
270+
return bool(message.pinned_message)
271+
272+
pinned_message = _PinnedMessage()
273+
217274
def filter(self, message):
218-
return bool(message.new_chat_members or message.left_chat_member
219-
or message.new_chat_title or message.new_chat_photo
220-
or message.delete_chat_photo or message.group_chat_created
221-
or message.supergroup_chat_created or message.channel_chat_created
222-
or message.migrate_to_chat_id or message.migrate_from_chat_id
223-
or message.pinned_message)
275+
return bool(self.new_chat_members(message) or self.left_chat_member(message) or
276+
self.new_chat_title(message) or self.new_chat_photo(message) or
277+
self.delete_chat_photo(message) or self.chat_created(message) or
278+
self.migrate(message) or self.pinned_message(message))
224279

225280
status_update = _StatusUpdate()
226281

@@ -269,6 +324,20 @@ def filter(self, message):
269324

270325
group = _Group()
271326

327+
class _Invoice(BaseFilter):
328+
329+
def filter(self, message):
330+
return bool(message.invoice)
331+
332+
invoice = _Invoice()
333+
334+
class _SuccessfulPayment(BaseFilter):
335+
336+
def filter(self, message):
337+
return bool(message.successful_payment)
338+
339+
successful_payment = _SuccessfulPayment()
340+
272341
class language(BaseFilter):
273342
"""
274343
Filters messages to only allow those which are from users with a certain language code.

telegram/inlinekeyboardbutton.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@ class InlineKeyboardButton(TelegramObject):
4646
the bot's username and the specified inline query in the current chat's input field.
4747
Can be empty, in which case only the bot's username will be inserted.
4848
callback_game (Optional[:class:`telegram.CallbackGame`]): Description of the game that will
49-
be launched when the user presses the button.
49+
be launched when the user presses the button. NOTE: This type of button must always be
50+
the first button in the first row.
51+
pay (Optional[bool]): Specify True, to send a Pay button. NOTE: This type of button must
52+
always be the first button in the first row.
5053
**kwargs (dict): Arbitrary keyword arguments.
5154
5255
"""
@@ -58,6 +61,7 @@ def __init__(self,
5861
switch_inline_query=None,
5962
switch_inline_query_current_chat=None,
6063
callback_game=None,
64+
pay=None,
6165
**kwargs):
6266
# Required
6367
self.text = text
@@ -68,6 +72,7 @@ def __init__(self,
6872
self.switch_inline_query = switch_inline_query
6973
self.switch_inline_query_current_chat = switch_inline_query_current_chat
7074
self.callback_game = callback_game
75+
self.pay = pay
7176

7277
@staticmethod
7378
def de_json(data, bot):

telegram/inputfile.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,11 @@ def __init__(self, data):
6969
if not self.filename or '.' not in self.filename:
7070
self.filename = self.mimetype.replace('/', '.')
7171
except TelegramError:
72-
self.mimetype = mimetypes.guess_type(self.filename)[0] or DEFAULT_MIME_TYPE
72+
if self.filename:
73+
self.mimetype = mimetypes.guess_type(
74+
self.filename)[0] or DEFAULT_MIME_TYPE
75+
else:
76+
self.mimetype = DEFAULT_MIME_TYPE
7377

7478
@property
7579
def headers(self):

0 commit comments

Comments
 (0)