Skip to content

Instantly share code, notes, and snippets.

@cdunklau
Forked from habnabit/chatserver.py
Last active January 3, 2016 10:09
Show Gist options
  • Save cdunklau/8447316 to your computer and use it in GitHub Desktop.
Save cdunklau/8447316 to your computer and use it in GitHub Desktop.
Chatserver Nightmare! Now with flake8 compliance!
main = lambda port: (lambda dt: (lambda mm: (lambda n: (map(lambda r: (lambda
rr: setattr(n, *rr) if (type(rr) is tuple and len(rr) == 2) else None)(r()),
[lambda: map(setattr, *zip(*[(n, m, __import__(m)) for m in mm.m.decode('ba'
'se64').split()])), lambda: map(n.s['signal.signal'], (n.s['signal.SIGINT'],
n.s['signal.SIGTERM']), [lambda s, f: (n.s['sys.exit']() if n.f else [n.sa(
mm.l[0], n.o)] and n.u('f', True) or n.fc(n.l))] * 2), lambda: setattr(mm,
'l', mm.l.decode('base64').split('~~~')), lambda: ('sw', n.s['types.Functio'
'nType'] (compile("try:\n\tv = n.select.select(n.so, n.w(), [])\nexcept n.s"
"elect.error, e:\n\tif e[0] != n.errno.EINTR: raise\nelse:\n\tn.u('sr', v)",
'', 'exec'), dict(n=n, OSError=OSError))),lambda: ('l', n.s['socket.socket']
(n.s['socket.AF_INET'], n.s['socket.SOCK_STREAM'])), lambda: n.s['l.bind']((
'', port)), lambda: n.s['l.listen'](5), lambda: ('ro', lambda: filter(lambda
s: s in n.nn, n.so)), lambda: n.update(si=(lambda o: o.__setitem__), di=(
lambda o: o.__delitem__), cr=n.s['re.compile'](mm.l[11]), nn={}, dp=lambda
s, d, c, l: n.dd.get(c, d)(s, l, c), dd=dict(me=lambda s, l, c: n.sa(mm.l[14
] % (n.nn[s], l)), quit=lambda s, l, c: n.c(s), who=lambda s, l, c: n.ws(s,
mm.l[1] + ', '.join(n.s['nn.values']())), help=lambda s, l, c: n.ws(s, mm.l[
2]), nick=lambda s, l, c: ((([n.sa(mm.l[3] % (n.nn[s], l))] and n.si(n.nn)(
s, l)) if n.nr.match(l) else n.ws(s, mm.l[4])) if l not in n.nn.values()
else n.ws(s, mm.l[7]))), so=(n.u('f', False) or [n.l]), ib=n.s['collections'
'.defaultdict'](list), ob=n.s['collections.defaultdict'](list), o=(lambda:
filter(lambda s: s is not n.l, n.so)), w=(lambda: filter(n.ob.__getitem__,
n.o())), ws=(lambda s, l: n.ob[s].append(l + '\r\n')), nr=n.s['re.compile'](
mm.l[12]), sa=(lambda d, f=n.ro: map(lambda s: n.ws(s, d), f())), fs=set(),
c=(lambda s: [n.sa(mm.l[13] % n.nn[s]) if s in n.nn and s not in n.fs else
None] and n.s['fs.add'](s)), fc=(lambda s: [s.close()] and (n.so.remove(s)
if s in n.so else None) or (n.fs.remove(s) if s in n.fs else None) or (n.di(
n.ib)(s) if s in n.ib else None) or (n.di(n.ob)(s) if s in n.ob else None)
or (n.di(n.nn)(s) if s in n.nn else None))), lambda: map(lambda f: map(
apply, [lambda: n.u('sr', ([], [], [])), lambda: n.sw(), lambda: map(apply,
[lambda *ss: map(lambda s: map(apply, [lambda: n.sa(mm.l[8]), lambda: n.so.
append(s.accept()[0]), lambda: n.ws(n.so[-1], mm.l[6])]) if s is n.l else
map(apply, [lambda: n.ib[s].append(s.recv(4096)) or (n.c(s) if n.ib[s][-1]
== '' else None)]), ss), lambda *ss: map(lambda s: (lambda d: (n.si(n.ob)(s,
[d[s.send(d):]]) or (n.si(n.ob)(s, []) if n.ob[s] == [''] else None)))(''.
join(n.ob[s])), ss), lambda *ss: None], n.sr), lambda: [n.di(v)(slice(None,
None)) for k, v in n.ob.items() if v and not filter(None, v)], lambda: n.u(
'sl', {}), lambda: map((lambda (k, v): n.si(n.sl)(k, ''.join(v).split('\r\n'
)) or n.si(n.ib)(k, [n.sl[k].pop()])), n.ib.items()), lambda: n.sl and map(
lambda (s, l): ((n.sa(mm.l[15] % (n.nn[s], l[1:] if l.startswith('//') else
l)) if not l.startswith('/') or l.startswith('//') else (n.dp(s, lambda s,
l, c: n.ws(s, mm.l[9] % c), *n.s['cr.match'](l).groups()))) if s in n.nn
else (((n.si(n.nn)(s, l) or [n.ws(s, mm.l[5])] and n.sa(mm.l[10] % l)) if n.
nr.match(l) else n.ws(s, mm.l[4])) if l not in n.nn.values() else n.ws(s,
mm.l[7]))), [(s, l.rstrip()) for s, ll in n.sl.items() for l in ll]),
lambda: n.f and map(lambda (s, b): n.fc(s) if not filter(None, b) else None,
n.ob.items()), lambda: map(lambda s: n.fc(s) if not filter(None, n.ob[s])
else None, list(n.fs))]), iter(lambda: bool(n.so), False)), lambda: n.s['l.'
'close']()])))(dt()))(dt(m='c3lzIHNpZ25hbCBzb2NrZXQgc2VsZWN0IGNvbGxlY3Rpb25'
'zIGVycm5vIHR5cGVzIGl0ZXJ0b29scyByZQ==', l='KioqIFNlcnZlciBnb2luZyBkb3duIX5'
'+fioqKiBDdXJyZW50bHkgY29ubmVjdGVkOiB+fn4qKiogQXZhaWxhYmxlIGNvbW1hbmRzOg0KK'
'ioqICAvaGVscCAtLSBnZXQgaGVscA0KKioqICAvcXVpdCAtLSBkaXNjb25uZWN0DQoqKiogIC9'
'tZSAtLSBwZXJmb3JtIGFuIGFjdGlvbg0KKioqICAvd2hvIC0tIGxpc3QgY29ubmVjdGVkIHVzZ'
'XJzDQoqKiogIC9uaWNrIC0tIGNoYW5nZSB5b3VyIG5pY2tuYW1lIHRvIHNvbWV0aGluZyBiZXR'
'0ZXJ+fn4qKiogJXMgaXMgbm93IGtub3duIGFzICVzLn5+fioqKiBUaGF0IG5pY2tuYW1lIGlzI'
'GludmFsaWQufn5+KioqIFR5cGUgIi9oZWxwIiBmb3IgaGVscC5+fn4qKiogSGVsbG8hIFdoYXQ'
'gaXMgeW91ciBuaWNrbmFtZT9+fn4qKiogVGhhdCBuaWNrbmFtZSBpcyBhbHJlYWR5IGluIHVzZ'
'S5+fn4qKiogSW5jb21pbmcgY29ubmVjdGlvbiF+fn4qKiogTm8gc3VjaCBjb21tYW5kOiAvJXN'
'+fn4qKiogJXMgaGFzIGpvaW5lZC5+fn5eLyhbQS16XSopXHMqKC4qKSR+fn5eW0EtejAtOV9dK'
'yR+fn4qKiogJXMgaGFzIGxlZnQufn5+KiAlcyAlc35+fjwlcz4gJXM=')))(type('', (dict,
), dict(__getattr__=lambda s, k: s[k], u=lambda s, *a: s.__setitem__(*a),
__setattr__=lambda s, k, v: s.__setitem__(k, v), s=property(lambda s: type(
'', (object,), dict(__getitem__=lambda ss, k: reduce(getattr, k.split('.'),
s)))()))))
main = lambda port: (
lambda dt: (
lambda mm: (
lambda n: (
map(
lambda r: (
lambda rr: (
setattr(n, *rr)
if (type(rr) is tuple and len(rr) == 2)
else None
)
)(r()),
[
lambda: map(
setattr,
*zip(
*[
(n, m, __import__(m))
for m
in mm.m.decode('ba' 'se64').split()
]
)
),
lambda: map(
n.s['signal.signal'],
(n.s['signal.SIGINT'], n.s['signal.SIGTERM']),
[
lambda s, f: (
n.s['sys.exit']()
if n.f
else (
[n.sa(mm.l[0], n.o)] and
n.u('f', True) or
n.fc(n.l)
)
)
] * 2
),
lambda: setattr(
mm, 'l', mm.l.decode('base64').split('~~~')
),
lambda: (
'sw',
n.s['types.Functio' 'nType'](
compile(
"try:\n"
"\tv = n.select.select(n.so, n.w(), [])\n"
"except n.select.error, e:\n"
"\tif e[0] != n.errno.EINTR: raise\n"
"else:\n"
"\tn.u('sr', v)",
'',
'exec'
),
dict(n=n, OSError=OSError)
)
),
lambda: (
'l',
n.s['socket.socket'](
n.s['socket.AF_INET'],
n.s['socket.SOCK_STREAM']
)
),
lambda: n.s['l.bind'](('', port)),
lambda: n.s['l.listen'](5),
lambda: (
'ro', lambda: filter(lambda s: s in n.nn, n.so)
),
lambda: n.update(
si=(lambda o: o.__setitem__),
di=(lambda o: o.__delitem__),
cr=n.s['re.compile'](mm.l[11]),
nn={},
dp=lambda s, d, c, l: n.dd.get(c, d)(s, l, c),
dd=dict(
me=lambda s, l, c: (
n.sa(mm.l[14] % (n.nn[s], l))
),
quit=lambda s, l, c: n.c(s),
who=lambda s, l, c: n.ws(
s, mm.l[1] + ', '.join(n.s['nn.values']())
),
help=lambda s, l, c: n.ws(s, mm.l[2]),
nick=lambda s, l, c: (
(
(
[n.sa(mm.l[3] % (n.nn[s], l))] and
n.si(n.nn)(s, l)
)
if n.nr.match(l)
else n.ws(s, mm.l[4])
)
if l not in n.nn.values()
else n.ws(s, mm.l[7])
)
),
so=(n.u('f', False) or [n.l]),
ib=n.s['collections' '.defaultdict'](list),
ob=n.s['collections.defaultdict'](list),
o=(lambda: filter(lambda s: s is not n.l, n.so)),
w=(lambda: filter(n.ob.__getitem__, n.o())),
ws=(lambda s, l: n.ob[s].append(l + '\r\n')),
nr=n.s['re.compile'](mm.l[12]),
sa=(
lambda d, f=n.ro: map(
lambda s: n.ws(s, d),
f()
)
),
fs=set(),
c=(
lambda s: [
n.sa(mm.l[13] % n.nn[s])
if s in n.nn and s not in n.fs
else None
] and n.s['fs.add'](s)
),
fc=(
lambda s: (
[s.close()] and
(n.so.remove(s) if s in n.so else None) or
(n.fs.remove(s) if s in n.fs else None) or
(n.di(n.ib)(s) if s in n.ib else None) or
(n.di(n.ob)(s) if s in n.ob else None) or
(n.di(n.nn)(s) if s in n.nn else None)
)
)
),
lambda: map(
lambda f: map(
apply,
[
lambda: n.u('sr', ([], [], [])),
lambda: n.sw(),
lambda: map(
apply,
[
lambda *ss: map(
lambda s: map(
apply,
[
lambda: (
n.sa(mm.l[8])
),
lambda: (
n.so.append(
s.accept()[0]
)
),
lambda: n.ws(
n.so[-1],
mm.l[6]
)
]
) if s is n.l else map(
apply,
[
lambda: (
n.ib[s].append(
s.recv(4096)
) or
(
n.c(s)
if (
n.ib[s][-1]
== ''
)
else None
)
)
]
),
ss
),
lambda *ss: map(
lambda s: (
lambda d: (
n.si(n.ob)(
s,
[d[s.send(d):]]
) or
(
n.si(n.ob)(s, [])
if n.ob[s] == ['']
else None
)
)
)(''. join(n.ob[s])), ss),
lambda *ss: None
],
n.sr
),
lambda: [
n.di(v)(slice(None, None))
for k, v
in n.ob.items()
if v and not filter(None, v)
],
lambda: n.u('sl', {}),
lambda: map(
(
lambda (k, v): (
n.si(n.sl)(
k,
''.join(v).split('\r\n')
) or n.si(n.ib)(
k,
[n.sl[k].pop()]
)
)
),
n.ib.items()
),
lambda: n.sl and map(
lambda (s, l): (
(
n.sa(
mm.l[15] % (
n.nn[s],
l[1:]
if l.startswith('//')
else l
)
)
if (
not l.startswith('/') or
l.startswith('//')
)
else (
n.dp(
s,
lambda s, l, c: (
n.ws(
s,
mm.l[9] % c
)
),
*n.s['cr.match'](
l
).groups()
)
)
)
if s in n.nn
else (
(
(
n.si(n.nn)(s, l) or
[n.ws(s, mm.l[5])] and
n.sa(mm.l[10] % l)
)
if n.nr.match(l)
else n.ws(s, mm.l[4])
)
if l not in n.nn.values()
else n.ws(s, mm.l[7])
)
),
[
(s, l.rstrip())
for s, ll
in n.sl.items()
for l
in ll
]
),
lambda: (
n.f and
map(
lambda (s, b): (
n.fc(s)
if not filter(None, b)
else None
),
n.ob.items()
)
),
lambda: map(
lambda s: (
n.fc(s)
if not filter(None, n.ob[s])
else None
),
list(n.fs)
)
]
),
iter(lambda: bool(n.so), False)
),
lambda: n.s['l.' 'close']()
]
)
)
)(dt())
)(
dt(
m='c3lzIHNpZ25hbCBzb2NrZXQgc2VsZWN0IGNvbGxlY3Rpb25zIGVycm5vIHR5cGV'
'zIGl0ZXJ0b29scyByZQ==',
l='KioqIFNlcnZlciBnb2luZyBkb3duIX5+fioqKiBDdXJyZW50bHkgY29ubmVjdGV'
'kOiB+fn4qKiogQXZhaWxhYmxlIGNvbW1hbmRzOg0KKioqICAvaGVscCAtLSBnZXQg'
'aGVscA0KKioqICAvcXVpdCAtLSBkaXNjb25uZWN0DQoqKiogIC9tZSAtLSBwZXJmb'
'3JtIGFuIGFjdGlvbg0KKioqICAvd2hvIC0tIGxpc3QgY29ubmVjdGVkIHVzZXJzDQ'
'oqKiogIC9uaWNrIC0tIGNoYW5nZSB5b3VyIG5pY2tuYW1lIHRvIHNvbWV0aGluZyB'
'iZXR0ZXJ+fn4qKiogJXMgaXMgbm93IGtub3duIGFzICVzLn5+fioqKiBUaGF0IG5p'
'Y2tuYW1lIGlzIGludmFsaWQufn5+KioqIFR5cGUgIi9oZWxwIiBmb3IgaGVscC5+f'
'n4qKiogSGVsbG8hIFdoYXQgaXMgeW91ciBuaWNrbmFtZT9+fn4qKiogVGhhdCBuaW'
'NrbmFtZSBpcyBhbHJlYWR5IGluIHVzZS5+fn4qKiogSW5jb21pbmcgY29ubmVjdGl'
'vbiF+fn4qKiogTm8gc3VjaCBjb21tYW5kOiAvJXN+fn4qKiogJXMgaGFzIGpvaW5l'
'ZC5+fn5eLyhbQS16XSopXHMqKC4qKSR+fn5eW0EtejAtOV9dKyR+fn4qKiogJXMga'
'GFzIGxlZnQufn5+KiAlcyAlc35+fjwlcz4gJXM='
)
)
)(
type(
'',
(dict,),
dict(
__getattr__=lambda s, k: s[k],
u=lambda s, *a: s.__setitem__(*a),
__setattr__=lambda s, k, v: s.__setitem__(k, v),
s=property(
lambda s: type(
'',
(object,),
dict(
__getitem__=lambda ss, k: reduce(
getattr,
k.split('.'),
s
)
)
)()
)
)
)
)
### The first thing that jumped out at me was the big blocks of strings
### starting at line 49 of the original code. There are two arguments to the
### ``dt`` function, named ``m`` and ``l``, and they both sure look like
### base-64 encoding. Here are the originals, the only change is the
### indentation and naming.
ORIGINAL_M_BASE64 = (
'c3lzIHNpZ25hbCBzb2NrZXQgc2VsZWN0IGNvbGxlY3Rpb25'
'zIGVycm5vIHR5cGVzIGl0ZXJ0b29scyByZQ=='
)
ORIGINAL_L_BASE64 = (
'KioqIFNlcnZlciBnb2luZyBkb3duIX5'
'+fioqKiBDdXJyZW50bHkgY29ubmVjdGVkOiB+fn4qKiogQXZhaWxhYmxlIGNvbW1hbmRzOg0KK'
'ioqICAvaGVscCAtLSBnZXQgaGVscA0KKioqICAvcXVpdCAtLSBkaXNjb25uZWN0DQoqKiogIC9'
'tZSAtLSBwZXJmb3JtIGFuIGFjdGlvbg0KKioqICAvd2hvIC0tIGxpc3QgY29ubmVjdGVkIHVzZ'
'XJzDQoqKiogIC9uaWNrIC0tIGNoYW5nZSB5b3VyIG5pY2tuYW1lIHRvIHNvbWV0aGluZyBiZXR'
'0ZXJ+fn4qKiogJXMgaXMgbm93IGtub3duIGFzICVzLn5+fioqKiBUaGF0IG5pY2tuYW1lIGlzI'
'GludmFsaWQufn5+KioqIFR5cGUgIi9oZWxwIiBmb3IgaGVscC5+fn4qKiogSGVsbG8hIFdoYXQ'
'gaXMgeW91ciBuaWNrbmFtZT9+fn4qKiogVGhhdCBuaWNrbmFtZSBpcyBhbHJlYWR5IGluIHVzZ'
'S5+fn4qKiogSW5jb21pbmcgY29ubmVjdGlvbiF+fn4qKiogTm8gc3VjaCBjb21tYW5kOiAvJXN'
'+fn4qKiogJXMgaGFzIGpvaW5lZC5+fn5eLyhbQS16XSopXHMqKC4qKSR+fn5eW0EtejAtOV9dK'
'yR+fn4qKiogJXMgaGFzIGxlZnQufn5+KiAlcyAlc35+fjwlcz4gJXM='
)
### And here are the same strings, as presented in the redented version.
REDENT_M_BASE64 = (
'c3lzIHNpZ25hbCBzb2NrZXQgc2VsZWN0IGNvbGxlY3Rpb25zIGVycm5vIHR5cGV'
'zIGl0ZXJ0b29scyByZQ=='
)
REDENT_L_BASE64 = (
'KioqIFNlcnZlciBnb2luZyBkb3duIX5+fioqKiBDdXJyZW50bHkgY29ubmVjdGV'
'kOiB+fn4qKiogQXZhaWxhYmxlIGNvbW1hbmRzOg0KKioqICAvaGVscCAtLSBnZXQg'
'aGVscA0KKioqICAvcXVpdCAtLSBkaXNjb25uZWN0DQoqKiogIC9tZSAtLSBwZXJmb'
'3JtIGFuIGFjdGlvbg0KKioqICAvd2hvIC0tIGxpc3QgY29ubmVjdGVkIHVzZXJzDQ'
'oqKiogIC9uaWNrIC0tIGNoYW5nZSB5b3VyIG5pY2tuYW1lIHRvIHNvbWV0aGluZyB'
'iZXR0ZXJ+fn4qKiogJXMgaXMgbm93IGtub3duIGFzICVzLn5+fioqKiBUaGF0IG5p'
'Y2tuYW1lIGlzIGludmFsaWQufn5+KioqIFR5cGUgIi9oZWxwIiBmb3IgaGVscC5+f'
'n4qKiogSGVsbG8hIFdoYXQgaXMgeW91ciBuaWNrbmFtZT9+fn4qKiogVGhhdCBuaW'
'NrbmFtZSBpcyBhbHJlYWR5IGluIHVzZS5+fn4qKiogSW5jb21pbmcgY29ubmVjdGl'
'vbiF+fn4qKiogTm8gc3VjaCBjb21tYW5kOiAvJXN+fn4qKiogJXMgaGFzIGpvaW5l'
'ZC5+fn5eLyhbQS16XSopXHMqKC4qKSR+fn5eW0EtejAtOV9dKyR+fn4qKiogJXMga'
'GFzIGxlZnQufn5+KiAlcyAlc35+fjwlcz4gJXM='
)
### A simple test to make sure I didn't screw up with my reformatting:
assert ORIGINAL_M_BASE64 == REDENT_M_BASE64
assert ORIGINAL_L_BASE64 == REDENT_L_BASE64
### Those didn't blow up. Let's make it a bit nicer-looking with triple-quoted
### strings and strip the newlines. The asserts make sure they're equal.
M_BASE64 = """
c3lzIHNpZ25hbCBzb2NrZXQgc2VsZWN0IGNvbGxlY3Rpb25zIGVycm5vIHR5cGVzIGl0ZXJ0b29scy
ByZQ==
""".replace('\n', '')
L_BASE64 = """
KioqIFNlcnZlciBnb2luZyBkb3duIX5+fioqKiBDdXJyZW50bHkgY29ubmVjdGVkOiB+fn4qKiogQX
ZhaWxhYmxlIGNvbW1hbmRzOg0KKioqICAvaGVscCAtLSBnZXQgaGVscA0KKioqICAvcXVpdCAtLSBk
aXNjb25uZWN0DQoqKiogIC9tZSAtLSBwZXJmb3JtIGFuIGFjdGlvbg0KKioqICAvd2hvIC0tIGxpc3
QgY29ubmVjdGVkIHVzZXJzDQoqKiogIC9uaWNrIC0tIGNoYW5nZSB5b3VyIG5pY2tuYW1lIHRvIHNv
bWV0aGluZyBiZXR0ZXJ+fn4qKiogJXMgaXMgbm93IGtub3duIGFzICVzLn5+fioqKiBUaGF0IG5pY2
tuYW1lIGlzIGludmFsaWQufn5+KioqIFR5cGUgIi9oZWxwIiBmb3IgaGVscC5+fn4qKiogSGVsbG8h
IFdoYXQgaXMgeW91ciBuaWNrbmFtZT9+fn4qKiogVGhhdCBuaWNrbmFtZSBpcyBhbHJlYWR5IGluIH
VzZS5+fn4qKiogSW5jb21pbmcgY29ubmVjdGlvbiF+fn4qKiogTm8gc3VjaCBjb21tYW5kOiAvJXN+
fn4qKiogJXMgaGFzIGpvaW5lZC5+fn5eLyhbQS16XSopXHMqKC4qKSR+fn5eW0EtejAtOV9dKyR+fn
4qKiogJXMgaGFzIGxlZnQufn5+KiAlcyAlc35+fjwlcz4gJXM=
""".replace('\n', '')
assert M_BASE64 == ORIGINAL_M_BASE64
assert L_BASE64 == ORIGINAL_L_BASE64
### Now let's see what we actually have.
import base64
M_BASE64_DECODED = base64.b64decode(M_BASE64)
L_BASE64_DECODED = base64.b64decode(L_BASE64)
print repr(M_BASE64_DECODED)
### Result:
# 'sys signal socket select collections errno types itertools re'
### It's pretty obvious these are (at least some of) the modules used, so
### let's just make a list out of it. So far, so good.
modules_list = M_BASE64.split()
### How about the other one?
print repr(L_BASE64_DECODED)
### Result:
# '*** Server going down!~~~*** Currently connected: ~~~*** Available commands:\r\n*** /help -- get help\r\n*** /quit -- disconnect\r\n*** /me -- perform an action\r\n*** /who -- list connected users\r\n*** /nick -- change your nickname to something better~~~*** %s is now known as %s.~~~*** That nickname is invalid.~~~*** Type "/help" for help.~~~*** Hello! What is your nickname?~~~*** That nickname is already in use.~~~*** Incoming connection!~~~*** No such command: /%s~~~*** %s has joined.~~~^/([A-z]*)\\s*(.*)$~~~^[A-z0-9_]+$~~~*** %s has left.~~~* %s %s~~~<%s> %s'
### Those look really familar! We saw most of that stuff when we ran the thing
### earlier. I didn't see any tildes in my interaction, and I vaguely remember
### a split involving tildes... so let's try that, and grab the indicies for
### good measure.
for i, msg in enumerate(L_BASE64_DECODED.split('~~~')):
print '{0}: {1}'.format(i, repr(msg))
# 0: '*** Server going down!'
# 1: '*** Currently connected: '
# 2: '*** Available commands:\r\n*** /help -- get help\r\n*** /quit -- disconnect\r\n*** /me -- perform an action\r\n*** /who -- list connected users\r\n*** /nick -- change your nickname to something better'
# 3: '*** %s is now known as %s.'
# 4: '*** That nickname is invalid.'
# 5: '*** Type "/help" for help.'
# 6: '*** Hello! What is your nickname?'
# 7: '*** That nickname is already in use.'
# 8: '*** Incoming connection!'
# 9: '*** No such command: /%s'
# 10: '*** %s has joined.'
# 11: '^/([A-z]*)\\s*(.*)$'
# 12: '^[A-z0-9_]+$'
# 13: '*** %s has left.'
# 14: '* %s %s'
# 15: '<%s> %s'
### Progress! Most of these things are obvious. The regex patterns and the
### very simple format strings stick out, but it's not immediately obvious
### what they're for. Let's structure this a bit better so we can get an idea
### about the semantics of these strings, the non-obvious ones are marked
### with the reasoning I used to name them.
outputs_list = L_BASE64_DECODED.split('~~~')
outputs_keys = [
'server_exit', # 0: '*** Server going down!'
'who_response_prefix', # 1: '*** Currently connected: '
'help_response', # 2: '*** Available commands:\r\n*** <trunc>
'nick_response_format', # 3: '*** %s is now known as %s.'
'nick_response_error', # 4: '*** That nickname is invalid.'
'help_message', # 5: '*** Type "/help" for help.'
'greeting_prompt', # 6: '*** Hello! What is your nickname?'
'nonunique_nick_error', # 7: '*** That nickname is already in use.'
'incoming_message', # 8: '*** Incoming connection!'
'command_error_format', # 9: '*** No such command: /%s'
'join_message_format', # 10: '*** %s has joined.'
### This has to be the command pattern, since the anchor is followed
### immediately by a forward slash
'command_pattern', # 11: '^/([A-z]*)\\s*(.*)$'
### Not too sure what this is for yet, but it definitely matches a single
### word. Perhaps it's used for nick validation?
'word_pattern', # 12: '^[A-z0-9_]+$'
'part_message_format', # 13: '*** %s has left.'
### The only thing in the initial testing session that started with a
### single asterix was the result of the action command /me
'action_message_format', # 14: '* %s %s'
### Angle brackets around the nick, then the message.
'chat_message_format', # 15: '<%s> %s'
]
### Let's combine the keys and strings into a dict. The ``pprint`` module
### gives us a nice display that we can dump back into our source file.
outputs_from_keys = dict(zip(outputs_keys, outputs_list))
import pprint
pprint.pprint(outputs_from_keys)
### We can then take the output of that and define the message store as a dict
### literal. I've redone the order of the keys in the literal so they match
### the keys list.
outputs_from_literal = {
'server_exit': '*** Server going down!',
'who_response_prefix': '*** Currently connected: ',
'help_response': (
'*** Available commands:\r\n'
'*** /help -- get help\r\n'
'*** /quit -- disconnect\r\n'
'*** /me -- perform an action\r\n'
'*** /who -- list connected users\r\n'
'*** /nick -- change your nickname to something better'
),
'nick_response_format': '*** %s is now known as %s.',
'nick_response_error': '*** That nickname is invalid.',
'help_message': '*** Type "/help" for help.',
'greeting_prompt': '*** Hello! What is your nickname?',
'nonunique_nick_error': '*** That nickname is already in use.',
'incoming_message': '*** Incoming connection!',
'command_error_format': '*** No such command: /%s',
'join_message_format': '*** %s has joined.',
'command_pattern': '^/([A-z]*)\\s*(.*)$',
'word_pattern': '^[A-z0-9_]+$',
'part_message_format': '*** %s has left.',
'action_message_format': '* %s %s',
'chat_message_format': '<%s> %s',
}
### And a simple test to ensure I didn't screw up my copy-paste
assert outputs_from_keys == outputs_from_literal
"""
Functional tests for chatserver refactor.
Set the environment variable CHATSERVER_TEST_MODULE to the suffix
of the chatserver_*.py script you want to test, and use the unittest
module's __main__ interface to run this test module::
CHATSERVER_TEST_MODULE=original python -m unittest test_chatserver
"""
import os
import os.path
import sys
import unittest
import subprocess
from glob import glob
from importlib import import_module
thisdir = os.path.abspath(os.path.dirname(__file__))
available = {}
for module_path in glob(os.path.join(thisdir, 'chatserver_*.py')):
module_name, ext = os.path.splitext(os.path.basename(module_path))
_, sep, key = module_name.partition('_')
if not sep:
continue
available[key] = module_name
#print available
chosen_suffix = os.environ.get('CHATSERVER_TEST_MODULE')
if not chosen_suffix:
print (
'CHATSERVER_TEST_MODULE not set, set to one of '
', '.join(available)
)
sys.exit(1)
if chosen_suffix not in available:
print 'Invalid suffix, choices are: ' + ', '.join(available)
sys.exit(1)
chatserver = import_module(available[chosen_suffix])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment