summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormathieui <mathieui@mathieui.net>2014-03-23 00:15:01 +0100
committermathieui <mathieui@mathieui.net>2014-03-23 00:15:01 +0100
commit186803d9a97d7efb089acc470b98293b7e472db5 (patch)
tree89533dc38acddbcfbb34b162974bd29a62c07db3
parent918e15d1781fce0fbf2b7b2b047be32163bc4679 (diff)
downloadpoezio-186803d9a97d7efb089acc470b98293b7e472db5.tar.gz
poezio-186803d9a97d7efb089acc470b98293b7e472db5.tar.bz2
poezio-186803d9a97d7efb089acc470b98293b7e472db5.tar.xz
poezio-186803d9a97d7efb089acc470b98293b7e472db5.zip
Fix formatting, some typos, and unused code, and add docstrings
- No idea why subclasses of ConversationTab were working before (info_header was overriden with None in __init__) - Or why the date parsing worked (“Exeception”) - Some more reformatting with pylint indications - Document each module in the tabs module
-rw-r--r--src/args.py2
-rw-r--r--src/bookmark.py11
-rw-r--r--src/common.py2
-rw-r--r--src/core.py1
-rw-r--r--src/data_forms.py21
-rw-r--r--src/decorators.py2
-rw-r--r--src/pep.py12
-rw-r--r--src/poezio_shlex.py2
-rw-r--r--src/roster.py1
-rw-r--r--src/tabs/basetabs.py24
-rw-r--r--src/tabs/conversationtab.py25
-rw-r--r--src/tabs/muclisttab.py21
-rw-r--r--src/tabs/muctab.py31
-rw-r--r--src/tabs/privatetab.py24
-rw-r--r--src/tabs/rostertab.py9
-rw-r--r--src/tabs/xmltab.py9
-rw-r--r--src/theming.py2
-rw-r--r--src/windows.py14
-rw-r--r--src/xhtml.py6
19 files changed, 141 insertions, 78 deletions
diff --git a/src/args.py b/src/args.py
index 33d4f6e6..05281fa0 100644
--- a/src/args.py
+++ b/src/args.py
@@ -21,7 +21,7 @@ def parse_args(CONFIG_PATH=''):
help="The file where debug will be written", metavar="DEBUG_FILE")
parser.add_option("-v", "--version", dest="version",
help=SUPPRESS, metavar="VERSION", default="0.8.3-dev")
- (options, args) = parser.parse_args()
+ (options, _) = parser.parse_args()
else:
parser = ArgumentParser()
parser.add_argument("-f", "--file", dest="filename", default=path.join(CONFIG_PATH, 'poezio.cfg'),
diff --git a/src/bookmark.py b/src/bookmark.py
index 95d20734..a68cc27a 100644
--- a/src/bookmark.py
+++ b/src/bookmark.py
@@ -1,3 +1,13 @@
+"""
+Bookmarks module
+
+Therein the bookmark class is defined, representing one conference room.
+This object is used to generate elements for both local and remote
+bookmark storage. It can also parse xml Elements.
+
+This module also defines several functions for retrieving and updating
+bookmarks, both local and remote.
+"""
import os
import logging
from sys import version_info
@@ -70,6 +80,7 @@ class Bookmark(object):
config.set_and_save('password', self.password, section=self.jid)
return local
+ @staticmethod
def parse_from_element(el, method=None):
"""
Generate a Bookmark object from a <conference/> element
diff --git a/src/common.py b/src/common.py
index e7568bb7..8fbf34fb 100644
--- a/src/common.py
+++ b/src/common.py
@@ -198,7 +198,7 @@ def datetime_tuple(timestamp):
tz_msg = timestamp[15:]
try:
ret = datetime.strptime(date, '%Y%m%dT%H%M%S')
- except Exeception as e:
+ except Exception as e:
ret = datetime.now()
# add the message timezone if any
try:
diff --git a/src/core.py b/src/core.py
index 7a635d48..3d90513e 100644
--- a/src/core.py
+++ b/src/core.py
@@ -3817,7 +3817,6 @@ class Core(object):
-
class KeyDict(dict):
"""
A dict, with a wrapper for get() that will return a custom value
diff --git a/src/data_forms.py b/src/data_forms.py
index e1c96500..89781377 100644
--- a/src/data_forms.py
+++ b/src/data_forms.py
@@ -156,27 +156,6 @@ class DummyInput(FieldInput, windows.Win):
def is_dummy(self):
return True
-class ColoredLabel(windows.Win):
- def __init__(self, text):
- self.text = text
- self.color = get_theme().COLOR_NORMAL_TEXT
- windows.Win.__init__(self)
-
- def resize(self, height, width, y, x):
- self._resize(height, width, y, x)
-
- def set_color(self, color):
- self.color = color
- self.refresh()
-
- def refresh(self):
- with g_lock:
- self._win.erase()
- self._win.attron(to_curses_attr(self.color))
- self.addstr(0, 0, self.text)
- self._win.attroff(to_curses_attr(self.color))
- self._refresh()
-
class BooleanWin(FieldInput, windows.Win):
def __init__(self, field):
FieldInput.__init__(self, field)
diff --git a/src/decorators.py b/src/decorators.py
index 56fb3184..251d8749 100644
--- a/src/decorators.py
+++ b/src/decorators.py
@@ -29,7 +29,7 @@ class RefreshWrapper(object):
return ret
return wrap
- def update(self, funct):
+ def update(self, func):
"""
Decorator that only updates the screen
"""
diff --git a/src/pep.py b/src/pep.py
index a505329a..0478b5fd 100644
--- a/src/pep.py
+++ b/src/pep.py
@@ -1,3 +1,8 @@
+"""
+Collection of mappings for PEP moods/activities
+extracted directly from the XEP
+"""
+
from gettext import gettext as _
MOODS = {
@@ -216,10 +221,3 @@ ACTIVITIES = {
}
}
-
-
-
-
-
-
-
diff --git a/src/poezio_shlex.py b/src/poezio_shlex.py
index 5b3c556c..d2025c2e 100644
--- a/src/poezio_shlex.py
+++ b/src/poezio_shlex.py
@@ -20,7 +20,7 @@ from io import StringIO
__all__ = ["shlex", "split", "quote"]
-class shlex:
+class shlex(object):
"""
A custom version of the shlex in the stdlib to yield more information
"""
diff --git a/src/roster.py b/src/roster.py
index fc68278f..51468aad 100644
--- a/src/roster.py
+++ b/src/roster.py
@@ -19,7 +19,6 @@ from roster_sorting import SORTING_METHODS, GROUP_SORTING_METHODS
from os import path as p
from datetime import datetime
from common import safeJID
-from sleekxmpp import JID
from sleekxmpp.exceptions import IqError, IqTimeout
diff --git a/src/tabs/basetabs.py b/src/tabs/basetabs.py
index 86ba9e1f..5e38775b 100644
--- a/src/tabs/basetabs.py
+++ b/src/tabs/basetabs.py
@@ -1,9 +1,16 @@
"""
-A Tab object is a way to organize various Windows (see windows.py)
-around the screen at once.
-A tab is then composed of multiple Buffers.
-Each Tab object has different refresh() and resize() methods, defining how its
-Windows are displayed, resized, etc.
+Module for the base Tabs
+
+The root class Tab defines the generic interface and attributes of a
+tab. A tab organizes various Windows around the screen depending
+of the tab specificity. If the tab shows messages, it will also
+reference a buffer containing the messages.
+
+Each subclass should redefine its own refresh() and resize() method
+according to its windows.
+
+This module also defines ChatTabs, the parent class for all tabs
+revolving around chats.
"""
from gettext import gettext as _
@@ -33,6 +40,7 @@ from theming import get_theme
MIN_WIDTH = 42
MIN_HEIGHT = 6
+# getters for tab colors (lambdas, so that they are dynamic)
STATE_COLORS = {
'disconnected': lambda: get_theme().COLOR_TAB_DISCONNECTED,
'scrolled': lambda: get_theme().COLOR_TAB_SCROLLED,
@@ -44,7 +52,6 @@ STATE_COLORS = {
'current': lambda: get_theme().COLOR_TAB_CURRENT,
'attention': lambda: get_theme().COLOR_TAB_ATTENTION,
}
-
VERTICAL_STATE_COLORS = {
'disconnected': lambda: get_theme().COLOR_VERTICAL_TAB_DISCONNECTED,
'scrolled': lambda: get_theme().COLOR_VERTICAL_TAB_SCROLLED,
@@ -58,6 +65,8 @@ VERTICAL_STATE_COLORS = {
}
+# priority of the different tab states when using Alt+e
+# higher means more priority, < 0 means not selectable
STATE_PRIORITY = {
'normal': -1,
'current': -1,
@@ -465,7 +474,7 @@ class ChatTab(Tab):
identifier=identifier,
jid=jid)
- def modify_message(self, txt, old_id, new_id, user=None,jid=None, nickname=None):
+ def modify_message(self, txt, old_id, new_id, user=None, jid=None, nickname=None):
self.log_message(txt, nickname, typ=1)
message = self._text_buffer.modify_message(txt, old_id, new_id, time=time, user=user, jid=jid)
if message:
@@ -663,4 +672,3 @@ class ChatTab(Tab):
def scroll_separator(self):
self.text_win.scroll_to_separator()
-
diff --git a/src/tabs/conversationtab.py b/src/tabs/conversationtab.py
index 143c8d68..64eeb4bf 100644
--- a/src/tabs/conversationtab.py
+++ b/src/tabs/conversationtab.py
@@ -1,3 +1,16 @@
+"""
+Module for the ConversationTabs
+
+A ConversationTab is a direct chat between two JIDs, outside of a room.
+
+There are two different instances of a ConversationTab:
+- A DynamicConversationTab that implements XEP-0296 (best practices for
+ resource locking), which means it will switch the resource it is
+ focused on depending on the presences received. This is the default.
+- A StaticConversationTab that will stay focused on one resource all
+ the time.
+
+"""
from gettext import gettext as _
import logging
@@ -212,7 +225,10 @@ class ConversationTab(ChatTab):
if 'urn:xmpp:attention:0' in iq['disco_info'].get_features():
self.core.information('Attention is supported', 'Info')
self.remote_supports_attention = True
- self.commands['attention'] = (self.command_attention, _('Usage: /attention [message]\nAttention: Require the attention of the contact. Can also send a message along with the attention.'), None)
+ self.commands['attention'] = (self.command_attention,
+ _('Usage: /attention [message]\nAttention: Require'
+ ' the attention of the contact. Can also send a '
+ 'message along with the attention.'), None)
else:
self.remote_supports_attention = False
@@ -238,7 +254,8 @@ class ConversationTab(ChatTab):
if jid in roster:
resource = roster[jid].get_highest_priority_resource()
jid = resource.jid if resource else jid
- fixes.get_version(self.core.xmpp, jid, callback=callback)
+ fixes.get_version(self.core.xmpp, jid,
+ callback=callback)
def resize(self):
if self.core.information_win_size >= self.height-3 or not self.visible:
@@ -253,7 +270,7 @@ class ConversationTab(ChatTab):
def refresh(self):
if self.need_resize:
self.resize()
- log.debug(' TAB Refresh: %s',self.__class__.__name__)
+ log.debug(' TAB Refresh: %s', self.__class__.__name__)
self.text_win.refresh()
self.upper_bar.refresh(self.get_dest_jid(), roster[self.get_dest_jid()])
self.info_header.refresh(self.get_dest_jid(), roster[self.get_dest_jid()], self.text_win, self.chatstate, ConversationTab.additional_informations)
@@ -396,7 +413,7 @@ class DynamicConversationTab(ConversationTab):
"""
if self.need_resize:
self.resize()
- log.debug(' TAB Refresh: %s',self.__class__.__name__)
+ log.debug(' TAB Refresh: %s', self.__class__.__name__)
self.text_win.refresh()
self.upper_bar.refresh(self.get_name(), roster[self.get_name()])
if self.locked_resource:
diff --git a/src/tabs/muclisttab.py b/src/tabs/muclisttab.py
index 0fe27307..c5b2a205 100644
--- a/src/tabs/muclisttab.py
+++ b/src/tabs/muclisttab.py
@@ -1,3 +1,9 @@
+"""
+A MucListTab is a tab listing the rooms on a conference server.
+
+It has no functionnality except scrolling the list, and allowing the
+user to join the rooms.
+"""
from gettext import gettext as _
import logging
@@ -18,6 +24,7 @@ class MucListTab(Tab):
"""
plugin_commands = {}
plugin_keys = {}
+
def __init__(self, server):
Tab.__init__(self)
self.state = 'normal'
@@ -47,7 +54,7 @@ class MucListTab(Tab):
def refresh(self):
if self.need_resize:
self.resize()
- log.debug(' TAB Refresh: %s',self.__class__.__name__)
+ log.debug(' TAB Refresh: %s', self.__class__.__name__)
self.info_header.refresh()
self.info_win.refresh()
self.refresh_tab_win()
@@ -61,7 +68,7 @@ class MucListTab(Tab):
return
self.need_resize = False
self.info_header.resize(1, self.width, self.height-2-self.core.information_win_size - Tab.tab_win_height(), 0)
- column_size = {'node-part': int(self.width*2/8) ,
+ column_size = {'node-part': int(self.width*2/8),
'name': int(self.width*5/8),
'users': self.width-int(self.width*2/8)-int(self.width*5/8)}
self.list_header.resize_columns(column_size)
@@ -105,7 +112,7 @@ class MucListTab(Tab):
return
items = [{'node-part': safeJID(item[0]).user if safeJID(item[0]).server == self.name else safeJID(item[0]).bare,
'jid': item[0],
- 'name': item[2] or '' ,'users': ''} for item in iq['disco_items'].get_items()]
+ 'name': item[2] or '', 'users': ''} for item in iq['disco_items'].get_items()]
self.listview.add_lines(items)
self.info_header.message = _('Chatroom list on server %s') % self.name
if self.core.current_tab() is self:
@@ -118,11 +125,15 @@ class MucListTab(Tab):
def sort_by(self):
if self.list_header.get_order():
- self.listview.sort_by_column(col_name=self.list_header.get_sel_column(),asc=False)
+ self.listview.sort_by_column(
+ col_name=self.list_header.get_sel_column(),
+ asc=False)
self.list_header.set_order(False)
self.list_header.refresh()
else:
- self.listview.sort_by_column(col_name=self.list_header.get_sel_column(),asc=True)
+ self.listview.sort_by_column(
+ col_name=self.list_header.get_sel_column(),
+ asc=True)
self.list_header.set_order(True)
self.list_header.refresh()
curses.doupdate()
diff --git a/src/tabs/muctab.py b/src/tabs/muctab.py
index 9bc2f88e..0b56df35 100644
--- a/src/tabs/muctab.py
+++ b/src/tabs/muctab.py
@@ -1,3 +1,12 @@
+"""
+Module for the MucTab
+
+A MucTab is a tab for multi-user chats as defined in XEP-0045.
+
+It keeps track of many things such as part/joins, maintains an
+user list, and updates private tabs when necessary.
+"""
+
from gettext import gettext as _
import logging
@@ -250,7 +259,7 @@ class MucTab(ChatTab):
return the_input.new_completion(userlist, 1, '', quotify=True)
elif n == 2:
possible_affiliations = ['none', 'member', 'admin', 'owner', 'outcast']
- return the_input.new_completion(possible_affiliations, 2, '', quotify=True)
+ return the_input.new_completion(possible_affiliations, 2, '', quotify=True)
def command_invite(self, args):
"""/invite <jid> [reason]"""
@@ -368,7 +377,6 @@ class MucTab(ChatTab):
res.get('version') or _('unknown'),
res.get('os') or _('an unknown platform'))
self.core.information(version, 'Info')
-
if not arg:
return self.core.command_help('version')
if arg in [user.nick for user in self.users]:
@@ -376,7 +384,8 @@ class MucTab(ChatTab):
jid = safeJID(jid + '/' + arg)
else:
jid = safeJID(arg)
- fixes.get_version(self.core.xmpp, jid, callback=callback)
+ fixes.get_version(self.core.xmpp, jid,
+ callback=callback)
def command_nick(self, arg):
"""
@@ -404,13 +413,13 @@ class MucTab(ChatTab):
if arg:
msg = _("\x195}You left the chatroom (\x19o%s\x195})\x193}" % arg)
else:
- msg =_("\x195}You left the chatroom\x193}")
+ msg = _("\x195}You left the chatroom\x193}")
self.add_message(msg, typ=2)
if self == self.core.current_tab():
self.refresh()
self.core.doupdate()
else:
- msg =_("\x195}You left the chatroom\x193}")
+ msg = _("\x195}You left the chatroom\x193}")
self.core.disable_private_tabs(self.name, reason=msg)
def command_close(self, arg):
@@ -484,16 +493,16 @@ class MucTab(ChatTab):
buff = ['Users: %s \n' % len(self.users)]
for moderator in moderators:
buff.append('\x19%s}%s\x19o\x19%s}%s\x19o' % (color_moderator,
- moderator[1], dump_tuple(moderator[0].color), moderator[0].nick))
+ moderator[1], dump_tuple(moderator[0].color), moderator[0].nick))
for participant in participants:
buff.append('\x19%s}%s\x19o\x19%s}%s\x19o' % (color_participant,
- participant[1], dump_tuple(participant[0].color), participant[0].nick))
+ participant[1], dump_tuple(participant[0].color), participant[0].nick))
for visitor in visitors:
buff.append('\x19%s}%s\x19o\x19%s}%s\x19o' % (color_visitor,
- visitor[1], dump_tuple(visitor[0].color), visitor[0].nick))
+ visitor[1], dump_tuple(visitor[0].color), visitor[0].nick))
for other in others:
buff.append('\x19%s}%s\x19o\x19%s}%s\x19o' % (color_other,
- other[1], dump_tuple(other[0].color), other[0].nick))
+ other[1], dump_tuple(other[0].color), other[0].nick))
buff.append('\n')
message = ' '.join(buff)
@@ -563,7 +572,7 @@ class MucTab(ChatTab):
if len(args) < 2:
self.core.command_help('role')
return
- nick, role = args[0],args[1]
+ nick, role = args[0], args[1]
if len(args) > 2:
reason = ' '.join(args[2:])
else:
@@ -704,7 +713,7 @@ class MucTab(ChatTab):
def refresh(self):
if self.need_resize:
self.resize()
- log.debug(' TAB Refresh: %s',self.__class__.__name__)
+ log.debug(' TAB Refresh: %s', self.__class__.__name__)
self.topic_win.refresh(self.get_single_line_topic())
self.text_win.refresh()
if config.get("hide_user_list", "false") == "false":
diff --git a/src/tabs/privatetab.py b/src/tabs/privatetab.py
index 574a2218..6adbf878 100644
--- a/src/tabs/privatetab.py
+++ b/src/tabs/privatetab.py
@@ -1,3 +1,15 @@
+"""
+Module for the PrivateTab
+
+A PrivateTab is a private conversation opened with someone from a MUC
+(see muctab.py). The conversation happens with both JID being relative
+to the MUC (room@server/nick1 and room@server/nick2).
+
+This tab references his parent room, and is modified to keep track of
+both participant’s nicks. It also has slightly different features than
+the ConversationTab (such as tab-completion on nicks from the room).
+
+"""
from gettext import gettext as _
import logging
@@ -182,7 +194,12 @@ class PrivateTab(ChatTab):
if 'urn:xmpp:attention:0' in iq['disco_info'].get_features():
self.core.information('Attention is supported', 'Info')
self.remote_supports_attention = True
- self.commands['attention'] = (self.command_attention, _('Usage: /attention [message]\nAttention: Require the attention of the contact. Can also send a message along with the attention.'), None)
+ self.commands['attention'] = (
+ self.command_attention,
+ _('Usage: /attention [message]\nAttention:'
+ 'Require the attention of the contact. Can'
+ ' also send a message along with the attention.'),
+ None)
else:
self.remote_supports_attention = False
@@ -207,7 +224,8 @@ class PrivateTab(ChatTab):
if arg:
return self.core.command_version(arg)
jid = safeJID(self.name)
- fixes.get_version(self.core.xmpp, jid, callback=callback)
+ fixes.get_version(self.core.xmpp, jid,
+ callback=callback)
def command_info(self, arg):
"""
@@ -231,7 +249,7 @@ class PrivateTab(ChatTab):
def refresh(self):
if self.need_resize:
self.resize()
- log.debug(' TAB Refresh: %s',self.__class__.__name__)
+ log.debug(' TAB Refresh: %s', self.__class__.__name__)
self.text_win.refresh()
self.info_header.refresh(self.name, self.text_win, self.chatstate, PrivateTab.additional_informations)
self.info_win.refresh()
diff --git a/src/tabs/rostertab.py b/src/tabs/rostertab.py
index 2ab81dae..22cad8b9 100644
--- a/src/tabs/rostertab.py
+++ b/src/tabs/rostertab.py
@@ -1,3 +1,10 @@
+"""
+The RosterInfoTab is the tab showing roster info, the list of contacts,
+half of it is dedicated to showing the information buffer, and a small
+rectangle shows the current contact info.
+
+This module also includes functions to match users in the roster.
+"""
from gettext import gettext as _
import logging
@@ -690,7 +697,7 @@ class RosterInfoTab(Tab):
def refresh(self):
if self.need_resize:
self.resize()
- log.debug(' TAB Refresh: %s',self.__class__.__name__)
+ log.debug(' TAB Refresh: %s', self.__class__.__name__)
self.v_separator.refresh()
self.roster_win.refresh(roster)
self.contact_info_win.refresh(self.roster_win.get_selected_row())
diff --git a/src/tabs/xmltab.py b/src/tabs/xmltab.py
index ed099405..a2728586 100644
--- a/src/tabs/xmltab.py
+++ b/src/tabs/xmltab.py
@@ -1,3 +1,10 @@
+"""
+The XMLTab is here for debugging purposes, it shows the incoming and
+outgoing stanzas. It has a few useful functions that can filter stanzas
+in order to only show the relevant ones, and it can also be frozen or
+unfrozen on demand so that the relevant information is not drowned by
+the traffic.
+"""
from gettext import gettext as _
import logging
@@ -168,7 +175,7 @@ class XMLTab(Tab):
def refresh(self):
if self.need_resize:
self.resize()
- log.debug(' TAB Refresh: %s',self.__class__.__name__)
+ log.debug(' TAB Refresh: %s', self.__class__.__name__)
self.text_win.refresh()
self.info_header.refresh(self.filter_type, self.filter, self.text_win)
self.refresh_tab_win()
diff --git a/src/theming.py b/src/theming.py
index 16280bc7..0e271018 100644
--- a/src/theming.py
+++ b/src/theming.py
@@ -260,7 +260,7 @@ class Theme(object):
CHAR_KICK = '-!-'
CHAR_NEW_TEXT_SEPARATOR = '- '
CHAR_COLUMN_ASC = ' ▲'
- CHAR_COLUMN_DESC =' ▼'
+ CHAR_COLUMN_DESC = ' ▼'
CHAR_ROSTER_ERROR = '✖'
CHAR_ROSTER_TUNE = '♪'
CHAR_ROSTER_ASKED = '?'
diff --git a/src/windows.py b/src/windows.py
index 6b0523a2..7e9951a6 100644
--- a/src/windows.py
+++ b/src/windows.py
@@ -1168,13 +1168,13 @@ class Input(Win):
}
Win.__init__(self)
self.text = ''
- self.pos = 0 # The position of the “cursor” in the text
- # (not only in the view)
- self.view_pos = 0 # The position (in the text) of the
- # first character displayed on the
- # screen
- self.on_input = None # callback called on any key pressed
- self.color = None # use this color on addstr
+ self.pos = 0 # The position of the “cursor” in the text
+ # (not only in the view)
+ self.view_pos = 0 # The position (in the text) of the
+ # first character displayed on the
+ # screen
+ self.on_input = None # callback called on any key pressed
+ self.color = None # use this color on addstr
def on_delete(self):
"""
diff --git a/src/xhtml.py b/src/xhtml.py
index 85e764ba..ed45ff53 100644
--- a/src/xhtml.py
+++ b/src/xhtml.py
@@ -421,9 +421,9 @@ def convert_simple_to_full_colors(text):
# TODO, have a single list of this. This is some sort of
# dusplicate from windows.format_chars
mapping = str.maketrans({'\x0E': '\x19b', '\x0F': '\x19o', '\x10': '\x19u',
- '\x11': '\x191', '\x12': '\x192','\x13': '\x193',
- '\x14': '\x194', '\x15': '\x195','\x16': '\x196',
- '\x17': '\x197', '\x18': '\x198','\x19': '\x199'})
+ '\x11': '\x191', '\x12': '\x192', '\x13': '\x193',
+ '\x14': '\x194', '\x15': '\x195', '\x16': '\x196',
+ '\x17': '\x197', '\x18': '\x198', '\x19': '\x199'})
text = text.translate(mapping)
def add_curly_bracket(match):
return match.group(0) + '}'