Python 3 fixes
This commit is contained in:
39
py/docex.py
39
py/docex.py
@@ -38,13 +38,13 @@ differences between docex and doctest are:
|
|||||||
writing "1+1==2 ==> True" and having it work in versions of Python
|
writing "1+1==2 ==> True" and having it work in versions of Python
|
||||||
where True prints as "1" rather than as "True", and so on,
|
where True prints as "1" rather than as "True", and so on,
|
||||||
but doctest has the edge if you want to compare against something
|
but doctest has the edge if you want to compare against something
|
||||||
that doesn't have an eval-able output, or if you want to test
|
that doesn't have an eval-able output, or if you want to test
|
||||||
printed output.
|
printed output.
|
||||||
|
|
||||||
(4) Doctest has many more features, and is better supported.
|
(4) Doctest has many more features, and is better supported.
|
||||||
I wrote docex before doctest was an official part of Python, but
|
I wrote docex before doctest was an official part of Python, but
|
||||||
with the refactoring of doctest in Python 2.4, I decided to switch
|
with the refactoring of doctest in Python 2.4, I decided to switch
|
||||||
my code over to doctest, even though I prefer the brevity of docex.
|
my code over to doctest, even though I prefer the brevity of docex.
|
||||||
I still offer docex for those who want it.
|
I still offer docex for those who want it.
|
||||||
|
|
||||||
From Python, when you want to test modules m1, m2, ... do:
|
From Python, when you want to test modules m1, m2, ... do:
|
||||||
@@ -70,8 +70,9 @@ one of the following formats:
|
|||||||
First y is evaled to yield an exception type, then x is execed.
|
First y is evaled to yield an exception type, then x is execed.
|
||||||
If x doesn't raise the right exception, an error msg is printed.
|
If x doesn't raise the right exception, an error msg is printed.
|
||||||
(5) Of the form 'statement'. Statement is execed for side effect.
|
(5) Of the form 'statement'. Statement is execed for side effect.
|
||||||
(6) Of the form 'expression'. Expression is evaled for side effect.
|
(6) Of the form 'expression'. Expression is evaled for side effect.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
import re, sys, types
|
import re, sys, types
|
||||||
|
|
||||||
@@ -96,9 +97,9 @@ class Docex:
|
|||||||
if out:
|
if out:
|
||||||
sys.stdout = sys.__stdout__
|
sys.stdout = sys.__stdout__
|
||||||
out.close()
|
out.close()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
if self.failed:
|
if self.failed:
|
||||||
return ('<Test: #### failed %d, passed %d>'
|
return ('<Test: #### failed %d, passed %d>'
|
||||||
% (self.failed, self.passed))
|
% (self.failed, self.passed))
|
||||||
else:
|
else:
|
||||||
@@ -141,8 +142,8 @@ class Docex:
|
|||||||
match = search(s)
|
match = search(s)
|
||||||
if match: self.run_string(s[match.end():])
|
if match: self.run_string(s[match.end():])
|
||||||
if hasattr(object, '_docex'):
|
if hasattr(object, '_docex'):
|
||||||
self.run_string(object._docex)
|
self.run_string(object._docex)
|
||||||
|
|
||||||
def run_string(self, teststr):
|
def run_string(self, teststr):
|
||||||
"""Run a test string, printing inputs and results."""
|
"""Run a test string, printing inputs and results."""
|
||||||
if not teststr: return
|
if not teststr: return
|
||||||
@@ -163,7 +164,7 @@ class Docex:
|
|||||||
try:
|
try:
|
||||||
self.evaluate(teststr)
|
self.evaluate(teststr)
|
||||||
except SyntaxError:
|
except SyntaxError:
|
||||||
exec teststr in self.dictionary
|
exec(teststr, self.dictionary)
|
||||||
|
|
||||||
def evaluate(self, teststr, resultstr=None):
|
def evaluate(self, teststr, resultstr=None):
|
||||||
"Eval teststr and check if resultstr (if given) evals to the same."
|
"Eval teststr and check if resultstr (if given) evals to the same."
|
||||||
@@ -172,18 +173,18 @@ class Docex:
|
|||||||
self.dictionary['_'] = result
|
self.dictionary['_'] = result
|
||||||
self.writeln(repr(result))
|
self.writeln(repr(result))
|
||||||
if resultstr == None:
|
if resultstr == None:
|
||||||
return
|
return
|
||||||
elif result == eval(resultstr, self.dictionary):
|
elif result == eval(resultstr, self.dictionary):
|
||||||
self.passed += 1
|
self.passed += 1
|
||||||
else:
|
else:
|
||||||
self.fail(teststr, resultstr)
|
self.fail(teststr, resultstr)
|
||||||
|
|
||||||
def raises(self, teststr, exceptionstr):
|
def raises(self, teststr, exceptionstr):
|
||||||
teststr = teststr.strip()
|
teststr = teststr.strip()
|
||||||
self.writeln('>>> ' + teststr)
|
self.writeln('>>> ' + teststr)
|
||||||
except_class = eval(exceptionstr, self.dictionary)
|
except_class = eval(exceptionstr, self.dictionary)
|
||||||
try:
|
try:
|
||||||
exec teststr in self.dictionary
|
exec(teststr, self.dictionary)
|
||||||
except except_class:
|
except except_class:
|
||||||
self.writeln('# raises %s as expected' % exceptionstr)
|
self.writeln('# raises %s as expected' % exceptionstr)
|
||||||
self.passed += 1
|
self.passed += 1
|
||||||
@@ -191,7 +192,7 @@ class Docex:
|
|||||||
self.fail(teststr, exceptionstr)
|
self.fail(teststr, exceptionstr)
|
||||||
|
|
||||||
def fail(self, teststr, resultstr):
|
def fail(self, teststr, resultstr):
|
||||||
self.writeln('###### ERROR, TEST FAILED: expected %s for %s'
|
self.writeln('###### ERROR, TEST FAILED: expected %s for %s'
|
||||||
% (resultstr, teststr),
|
% (resultstr, teststr),
|
||||||
'<font color=red><b>', '</b></font>')
|
'<font color=red><b>', '</b></font>')
|
||||||
self.failed += 1
|
self.failed += 1
|
||||||
@@ -201,9 +202,9 @@ class Docex:
|
|||||||
s = str(s)
|
s = str(s)
|
||||||
if self.html:
|
if self.html:
|
||||||
s = s.replace('&','&').replace('<','<').replace('>','>')
|
s = s.replace('&','&').replace('<','<').replace('>','>')
|
||||||
print '%s%s%s' % (before, s, after)
|
print('%s%s%s' % (before, s, after))
|
||||||
else:
|
else:
|
||||||
print s
|
print(s)
|
||||||
|
|
||||||
def seen(self, object):
|
def seen(self, object):
|
||||||
"""Return true if this object has been seen before.
|
"""Return true if this object has been seen before.
|
||||||
@@ -213,7 +214,7 @@ class Docex:
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def main(args):
|
def main(args):
|
||||||
"""Run Docex. args should be a list of python filenames.
|
"""Run Docex. args should be a list of python filenames.
|
||||||
If the first arg is a non-python filename, it is taken as the
|
If the first arg is a non-python filename, it is taken as the
|
||||||
name of a log file to which output is written. If it ends in
|
name of a log file to which output is written. If it ends in
|
||||||
".htm" or ".html", then the output is written as html. If the
|
".htm" or ".html", then the output is written as html. If the
|
||||||
@@ -230,9 +231,7 @@ def main(args):
|
|||||||
for file in glob.glob(arg):
|
for file in glob.glob(arg):
|
||||||
if file.endswith('.py'):
|
if file.endswith('.py'):
|
||||||
modules.append(__import__(file[:-3]))
|
modules.append(__import__(file[:-3]))
|
||||||
print Docex(modules, html=html, out=out)
|
print(Docex(modules, html=html, out=out))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main(sys.argv[1:])
|
main(sys.argv[1:])
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
59
py/ibol.py
59
py/ibol.py
@@ -1,10 +1,11 @@
|
|||||||
|
from __future__ import print_function
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
def get_genomes(fname="byronbayseqs.fas.txt"):
|
def get_genomes(fname="byronbayseqs.fas.txt"):
|
||||||
"Return a list of genomes, and a list of their corresponding names."
|
"Return a list of genomes, and a list of their corresponding names."
|
||||||
import re
|
import re
|
||||||
names, species, genomes = [], [], []
|
names, species, genomes = [], [], []
|
||||||
for name, g in re.findall('>(.*?)\r([^\r]*)\r*', file(fname).read()):
|
for name, g in re.findall('>(.*?)\r([^\r]*)\r*', open(fname).read()):
|
||||||
names.append(name)
|
names.append(name)
|
||||||
species.append(name.split('|')[-1])
|
species.append(name.split('|')[-1])
|
||||||
genomes.append(g)
|
genomes.append(g)
|
||||||
@@ -14,7 +15,7 @@ def get_neighbors(fname="editdistances.txt"):
|
|||||||
"Return dict: neighbors[i][j] = neighbors[j][i] = d means i,j are d apart."
|
"Return dict: neighbors[i][j] = neighbors[j][i] = d means i,j are d apart."
|
||||||
## Read the data pre-computed from the Java program
|
## Read the data pre-computed from the Java program
|
||||||
neighbors = dict((i, {}) for i in range(n))
|
neighbors = dict((i, {}) for i in range(n))
|
||||||
for line in file(fname):
|
for line in open(fname):
|
||||||
i,j,d = map(int, line.split())
|
i,j,d = map(int, line.split())
|
||||||
neighbors[i][j] = neighbors[j][i] = d
|
neighbors[i][j] = neighbors[j][i] = d
|
||||||
return neighbors
|
return neighbors
|
||||||
@@ -75,15 +76,15 @@ def showh(d):
|
|||||||
return ' '.join('%s:%s' % i for i in sorted(d.items()))
|
return ' '.join('%s:%s' % i for i in sorted(d.items()))
|
||||||
|
|
||||||
def greport(genomes):
|
def greport(genomes):
|
||||||
print "Number of genomes: %d (%d distinct)" % (len(genomes), len(set(genomes)))
|
print("Number of genomes: %d (%d distinct)" % (len(genomes), len(set(genomes))))
|
||||||
G = dict((g, set()) for g in genomes)
|
G = dict((g, set()) for g in genomes)
|
||||||
for i in range(n):
|
for i in range(n):
|
||||||
G[genomes[i]].add(species[i])
|
G[genomes[i]].add(species[i])
|
||||||
print "Multi-named genomes:", (
|
print("Multi-named genomes:", (
|
||||||
len([s for s in G.values() if len(s) > 1]))
|
len([s for s in G.values() if len(s) > 1])))
|
||||||
lens = map(len, genomes)
|
lens = map(len, genomes)
|
||||||
print "Genome lengths: min=%d, max=%d" % (min(lens), max(lens))
|
print("Genome lengths: min=%d, max=%d" % (min(lens), max(lens)))
|
||||||
print "Character counts: ", showh(c for g in genomes for c in g)
|
print("Character counts: ", showh(c for g in genomes for c in g))
|
||||||
|
|
||||||
def nreport(neighbors):
|
def nreport(neighbors):
|
||||||
NN, NumN = defaultdict(int), defaultdict(int) ## Nearest, Number of neighbors
|
NN, NumN = defaultdict(int), defaultdict(int) ## Nearest, Number of neighbors
|
||||||
@@ -92,9 +93,9 @@ def nreport(neighbors):
|
|||||||
NN[nn] += 1
|
NN[nn] += 1
|
||||||
for d2 in neighbors[n].values():
|
for d2 in neighbors[n].values():
|
||||||
NumN[d2] += 1
|
NumN[d2] += 1
|
||||||
print
|
print()
|
||||||
print "Nearest neighbor counts:", showh(NN)
|
print("Nearest neighbor counts:", showh(NN))
|
||||||
print "Number of neighbors at each distance:", showh(NumN)
|
print("Number of neighbors at each distance:", showh(NumN))
|
||||||
|
|
||||||
def nspecies(c): return len(set(species[g] for g in c))
|
def nspecies(c): return len(set(species[g] for g in c))
|
||||||
|
|
||||||
@@ -104,34 +105,34 @@ def showc(c):
|
|||||||
|
|
||||||
def creport(drange, dcrange):
|
def creport(drange, dcrange):
|
||||||
def table(what, fn):
|
def table(what, fn):
|
||||||
print "\n" + what
|
print("\n" + what)
|
||||||
print ' '*8, ' '.join([' '+pct(dc, glen) for dc in dcrange])
|
print(' '*8, ' '.join([' '+pct(dc, glen) for dc in dcrange]))
|
||||||
for d in drange:
|
for d in drange:
|
||||||
print '%s (%2d)' % (pct(d, glen), d),
|
print('%s (%2d)' % (pct(d, glen), d), end=' ')
|
||||||
for dc in dcrange:
|
for dc in dcrange:
|
||||||
print '%5s' % fn(cluster(neighbors, d, dc)),
|
print('%5s' % fn(cluster(neighbors, d, dc)), end=' ')
|
||||||
print
|
print()
|
||||||
print '\nNearest neighbor must be closer than this percentage (places). '
|
print('\nNearest neighbor must be closer than this percentage (places). ')
|
||||||
print 'Each column: all genomes in cluster within this percentage of each other.'
|
print('Each column: all genomes in cluster within this percentage of each other.')
|
||||||
table("Number of clusters", len)
|
table("Number of clusters", len)
|
||||||
cluster1 = cluster(neighbors, 8, 15) ## splits Cleora
|
cluster1 = cluster(neighbors, 8, 15) ## splits Cleora
|
||||||
print '\nNumber of clusters of different sizes:', showh(len(c) for c in cluster1)
|
print('\nNumber of clusters of different sizes:', showh(len(c) for c in cluster1))
|
||||||
M, T = defaultdict(int), defaultdict(int)
|
M, T = defaultdict(int), defaultdict(int)
|
||||||
for c in cluster1:
|
for c in cluster1:
|
||||||
M[margin(c)] += 1; T[margin(c)] += len(c)
|
M[margin(c)] += 1; T[margin(c)] += len(c)
|
||||||
for x in M: print '%d\t%d\t%d'% (x,M[x],T[x])
|
for x in M: print('%d\t%d\t%d'% (x,M[x],T[x]))
|
||||||
print '\nMargins', showh(M)
|
print('\nMargins', showh(M))
|
||||||
for c in cluster1:
|
for c in cluster1:
|
||||||
if margin(c) <= 16:
|
if margin(c) <= 16:
|
||||||
print showc(c)
|
print(showc(c))
|
||||||
print '\nScatter plot of cluster diameter vs. margin.'
|
print('\nScatter plot of cluster diameter vs. margin.')
|
||||||
for c in cluster1:
|
for c in cluster1:
|
||||||
if diameter(c) > 0:
|
if diameter(c) > 0:
|
||||||
pass
|
pass
|
||||||
#print '%d\t%d' % (diameter(c), margin(c))
|
#print '%d\t%d' % (diameter(c), margin(c))
|
||||||
print '\nDifference from cluster(neighbors, 11, 14):'
|
print('\nDifference from cluster(neighbors, 11, 14):')
|
||||||
#table(lambda cl: pct(len(cluster1)-compare(cluster1, cl),max(len(cluster1),len(cl))))
|
#table(lambda cl: pct(len(cluster1)-compare(cluster1, cl),max(len(cluster1),len(cl))))
|
||||||
print '\nNumber of clusters witth more than one species name:'
|
print('\nNumber of clusters witth more than one species name:')
|
||||||
#table(lambda cl: sum(nspecies(c) > 1 for c in cl))
|
#table(lambda cl: sum(nspecies(c) > 1 for c in cl))
|
||||||
def pct_near_another(clusters, P=1.25):
|
def pct_near_another(clusters, P=1.25):
|
||||||
total = 0
|
total = 0
|
||||||
@@ -143,21 +144,21 @@ def creport(drange, dcrange):
|
|||||||
total += 1
|
total += 1
|
||||||
return pct(total, n)
|
return pct(total, n)
|
||||||
def f(P):
|
def f(P):
|
||||||
print '\nPercent of individuals within %.2f*diameter of another cluster.'%P
|
print('\nPercent of individuals within %.2f*diameter of another cluster.'%P)
|
||||||
table(lambda cl: pct_near_another(cl, P))
|
table(lambda cl: pct_near_another(cl, P))
|
||||||
#map(f, [1.2, 1.33, 1.5])
|
#map(f, [1.2, 1.33, 1.5])
|
||||||
|
|
||||||
def sreport(species):
|
def sreport(species):
|
||||||
SS = defaultdict(int)
|
SS = defaultdict(int)
|
||||||
print
|
print()
|
||||||
for s in set(species):
|
for s in set(species):
|
||||||
c = [g for g in range(n) if species[g] == s]
|
c = [g for g in range(n) if species[g] == s]
|
||||||
d = diameter(c)
|
d = diameter(c)
|
||||||
if d > 14:
|
if d > 14:
|
||||||
if d==glen: d = '>25'
|
if d==glen: d = '>25'
|
||||||
print 'diameter %s for %s (%d elements)' % (d, s, len(c))
|
print('diameter %s for %s (%d elements)' % (d, s, len(c)))
|
||||||
SS[d] += 1
|
SS[d] += 1
|
||||||
print 'Diameters of %d labeled clusters: %s' % (len(set(species)), showh(SS))
|
print('Diameters of %d labeled clusters: %s' % (len(set(species)), showh(SS)))
|
||||||
|
|
||||||
def compare(cl1, cl2):
|
def compare(cl1, cl2):
|
||||||
"Compare two lists of clusters"
|
"Compare two lists of clusters"
|
||||||
@@ -174,7 +175,7 @@ def unit_tests():
|
|||||||
assert diameter(set()) == 0
|
assert diameter(set()) == 0
|
||||||
assert diameter([17, 42]) == dist(17, 42)
|
assert diameter([17, 42]) == dist(17, 42)
|
||||||
assert pct(1, 2) == '50.0%'
|
assert pct(1, 2) == '50.0%'
|
||||||
print '\nAll tests pass.\n'
|
print('\nAll tests pass.\n')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ an external file format that looks like this:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
from collections import Counter, defaultdict
|
from collections import Counter, defaultdict
|
||||||
|
|
||||||
#### Read files in Books-Ngram format; convert to a dict
|
#### Read files in Books-Ngram format; convert to a dict
|
||||||
@@ -31,7 +32,7 @@ def read_year_file(filename, dic=None):
|
|||||||
"""Read a file of 'word year word_count book_count' lines and convert to a dict
|
"""Read a file of 'word year word_count book_count' lines and convert to a dict
|
||||||
{WORD: totalcount}. Uppercase all words, and only include all-alphabetic words."""
|
{WORD: totalcount}. Uppercase all words, and only include all-alphabetic words."""
|
||||||
if dic is None: dic = {}
|
if dic is None: dic = {}
|
||||||
for line in file(filename):
|
for line in open(filename):
|
||||||
word, year, c1, c2 = line.split('\t')
|
word, year, c1, c2 = line.split('\t')
|
||||||
if '_' in word:
|
if '_' in word:
|
||||||
word = word[:word.index('_')]
|
word = word[:word.index('_')]
|
||||||
@@ -44,14 +45,14 @@ def read_year_file(filename, dic=None):
|
|||||||
|
|
||||||
def write_dict(dic, filename):
|
def write_dict(dic, filename):
|
||||||
"Write a {word:count} dict as 'word \t count' lines in filename."
|
"Write a {word:count} dict as 'word \t count' lines in filename."
|
||||||
out = file(filename, 'w')
|
out = open(filename, 'w')
|
||||||
for key in sorted(dic):
|
for key in sorted(dic):
|
||||||
out.write('%s\t%s\n' % (key, dic[key]))
|
out.write('%s\t%s\n' % (key, dic[key]))
|
||||||
return out.close()
|
return out.close()
|
||||||
|
|
||||||
def read_dict(filename, sep='\t'):
|
def read_dict(filename, sep='\t'):
|
||||||
"Read 'word \t count' lines from file and make them into a dict of {word:count}."
|
"Read 'word \t count' lines from file and make them into a dict of {word:count}."
|
||||||
pairs = (line.split(sep) for line in file(filename))
|
pairs = (line.split(sep) for line in open(filename))
|
||||||
return {word: int(count) for (word, count) in pairs}
|
return {word: int(count) for (word, count) in pairs}
|
||||||
|
|
||||||
#### Convert a bunch of year files into dict file format.
|
#### Convert a bunch of year files into dict file format.
|
||||||
@@ -61,9 +62,9 @@ def convert_files(filenames, mincount=1e5):
|
|||||||
import time
|
import time
|
||||||
N = len(D)
|
N = len(D)
|
||||||
W = sum(v for v in D.itervalues())
|
W = sum(v for v in D.itervalues())
|
||||||
print '%s: %s %s words (%s tokens) at %s' % (
|
print('%s: %s %s words (%s tokens) at %s' % (
|
||||||
filename, adj, format(W, ',d'), format(N, ',d'),
|
filename, adj, format(W, ',d'), format(N, ',d'),
|
||||||
time.strftime("%H:%M:%S", time.gmtime()))
|
time.strftime("%H:%M:%S", time.gmtime())))
|
||||||
for f in filenames:
|
for f in filenames:
|
||||||
report(f, {}, 'starting')
|
report(f, {}, 'starting')
|
||||||
D = read_year_file(f)
|
D = read_year_file(f)
|
||||||
@@ -155,10 +156,10 @@ def getcount(counts, s, pos, length):
|
|||||||
return counts[s, pos, length]
|
return counts[s, pos, length]
|
||||||
|
|
||||||
|
|
||||||
print 'start'
|
print('start')
|
||||||
#wc = word_counts('count_100K.txt')
|
#wc = word_counts('count_100K.txt')
|
||||||
#counts = letter_counts(wc)
|
#counts = letter_counts(wc)
|
||||||
print 'end'
|
print('end')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -172,18 +173,18 @@ def num(ch):
|
|||||||
|
|
||||||
def stats(D, NS = (1, 2, 3, 4, 5, 6)):
|
def stats(D, NS = (1, 2, 3, 4, 5, 6)):
|
||||||
counts = {n: Counter() for n in NS}
|
counts = {n: Counter() for n in NS}
|
||||||
print 'words ' + ' '.join(' %d-grams ' % n for n in NS)
|
print('words ' + ' '.join(' %d-grams ' % n for n in NS))
|
||||||
for (i, word) in enumerate(sortedby(D), 1):
|
for (i, word) in enumerate(sortedby(D), 1):
|
||||||
for n in NS:
|
for n in NS:
|
||||||
for ng in ngrams(word, n):
|
for ng in ngrams(word, n):
|
||||||
counts[n][ng] += 1
|
counts[n][ng] += 1
|
||||||
if i % 5000 == 0 or i == len(D):
|
if i % 5000 == 0 or i == len(D):
|
||||||
print "%4dK" % (i/1000),
|
print("%4dK" % (i/1000), end=' ')
|
||||||
for n in NS:
|
for n in NS:
|
||||||
c = len(counts[n])
|
c = len(counts[n])
|
||||||
field = "%5d (%d%%)" % (c, int(round(c*100/(26**n))))
|
field = "%5d (%d%%)" % (c, int(round(c*100/(26**n))))
|
||||||
print '%12s' % field,
|
print('%12s' % field, end=' ')
|
||||||
print
|
print()
|
||||||
|
|
||||||
letters = 'ETAOINSRHLDCUMFPGWYBVKXJQZ'
|
letters = 'ETAOINSRHLDCUMFPGWYBVKXJQZ'
|
||||||
alphabet = ''.join(sorted(letters))
|
alphabet = ''.join(sorted(letters))
|
||||||
@@ -224,7 +225,7 @@ def substr(word, pos, length):
|
|||||||
def lettercount(D, pos):
|
def lettercount(D, pos):
|
||||||
LC = histogram((substr(w, pos, 1), D[w]) for w in D)
|
LC = histogram((substr(w, pos, 1), D[w]) for w in D)
|
||||||
del LC[None]
|
del LC[None]
|
||||||
print LC
|
print(LC)
|
||||||
pos_name = (str(pos)+'+' if isinstance(pos, tuple) else
|
pos_name = (str(pos)+'+' if isinstance(pos, tuple) else
|
||||||
pos if pos < 0 else
|
pos if pos < 0 else
|
||||||
pos+1)
|
pos+1)
|
||||||
@@ -293,7 +294,7 @@ def csvline(first, rest):
|
|||||||
return '\t'.join([first] + map(str, rest))
|
return '\t'.join([first] + map(str, rest))
|
||||||
|
|
||||||
def makecsv(n, D=D):
|
def makecsv(n, D=D):
|
||||||
out = file('ngrams%d.csv' % n, 'w')
|
out = open('ngrams%d.csv' % n, 'w')
|
||||||
cols = columns(n)
|
cols = columns(n)
|
||||||
Dng = defaultdict(lambda: defaultdict(int))
|
Dng = defaultdict(lambda: defaultdict(int))
|
||||||
for w in D:
|
for w in D:
|
||||||
@@ -310,9 +311,9 @@ def makecsv(n, D=D):
|
|||||||
if from_end <= 9:
|
if from_end <= 9:
|
||||||
entry[ANY, -from_end, -from_end+n-1] += N
|
entry[ANY, -from_end, -from_end+n-1] += N
|
||||||
# enumerate ngrams from word and increment counts for each one
|
# enumerate ngrams from word and increment counts for each one
|
||||||
print >> out, csvline('%d-gram' % n, map(colname, cols))
|
print(csvline('%d-gram' % n, map(colname, cols)), file=out)
|
||||||
for ng in sorted(Dng, key=lambda ng: -Dng[ng][(ANY, ANY)]):
|
for ng in sorted(Dng, key=lambda ng: -Dng[ng][(ANY, ANY)]):
|
||||||
print >> out, csvline(ng, [Dng[ng].get(col, 0) for col in cols])
|
print(csvline(ng, [Dng[ng].get(col, 0) for col in cols]), file=out)
|
||||||
out.close()
|
out.close()
|
||||||
return Dng
|
return Dng
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ from __future__ import division
|
|||||||
import math
|
import math
|
||||||
import operator as op
|
import operator as op
|
||||||
|
|
||||||
|
try:
|
||||||
|
raw_input # Python 2
|
||||||
|
except NameError:
|
||||||
|
raw_input = input # Python 3
|
||||||
|
|
||||||
################ Types
|
################ Types
|
||||||
|
|
||||||
Symbol = str # A Lisp Symbol is implemented as a Python str
|
Symbol = str # A Lisp Symbol is implemented as a Python str
|
||||||
@@ -96,7 +101,7 @@ def repl(prompt='lis.py> '):
|
|||||||
"A prompt-read-eval-print loop."
|
"A prompt-read-eval-print loop."
|
||||||
while True:
|
while True:
|
||||||
val = eval(parse(raw_input(prompt)))
|
val = eval(parse(raw_input(prompt)))
|
||||||
if val is not None:
|
if val is not None:
|
||||||
print(lispstr(val))
|
print(lispstr(val))
|
||||||
|
|
||||||
def lispstr(exp):
|
def lispstr(exp):
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
################ Symbol, Procedure, classes
|
################ Symbol, Procedure, classes
|
||||||
|
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
import re, sys, StringIO
|
import re, sys, StringIO
|
||||||
|
|
||||||
class Symbol(str): pass
|
class Symbol(str): pass
|
||||||
@@ -114,9 +115,9 @@ def repl(prompt='lispy> ', inport=InPort(sys.stdin), out=sys.stdout):
|
|||||||
x = parse(inport)
|
x = parse(inport)
|
||||||
if x is eof_object: return
|
if x is eof_object: return
|
||||||
val = eval(x)
|
val = eval(x)
|
||||||
if val is not None and out: print >> out, to_string(val)
|
if val is not None and out: print(to_string(val), file=out)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print '%s: %s' % (type(e).__name__, e)
|
print('%s: %s' % (type(e).__name__, e))
|
||||||
|
|
||||||
################ Environment class
|
################ Environment class
|
||||||
|
|
||||||
@@ -315,4 +316,3 @@ eval(parse("""(begin
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
repl()
|
repl()
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
################ Tests for lis.py and lispy.py
|
################ Tests for lis.py and lispy.py
|
||||||
|
|
||||||
@@ -103,15 +104,15 @@ def test(tests, name=''):
|
|||||||
for (x, expected) in tests:
|
for (x, expected) in tests:
|
||||||
try:
|
try:
|
||||||
result = eval(parse(x))
|
result = eval(parse(x))
|
||||||
print x, '=>', to_string(result)
|
print(x, '=>', to_string(result))
|
||||||
ok = (result == expected)
|
ok = (result == expected)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print x, '=raises=>', type(e).__name__, e
|
print(x, '=raises=>', type(e).__name__, e)
|
||||||
ok = issubclass(expected, Exception) and isinstance(e, expected)
|
ok = issubclass(expected, Exception) and isinstance(e, expected)
|
||||||
if not ok:
|
if not ok:
|
||||||
fails += 1
|
fails += 1
|
||||||
print 'FAIL!!! Expected', expected
|
print('FAIL!!! Expected', expected)
|
||||||
print '%s %s: %d out of %d tests fail.' % ('*'*45, name, fails, len(tests))
|
print('%s %s: %d out of %d tests fail.' % ('*'*45, name, fails, len(tests)))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
from lis import *
|
from lis import *
|
||||||
|
|||||||
12
py/ngrams.py
12
py/ngrams.py
@@ -8,6 +8,7 @@ Code copyright (c) 2008-2009 by Peter Norvig
|
|||||||
You are free to use this code under the MIT licencse:
|
You are free to use this code under the MIT licencse:
|
||||||
http://www.opensource.org/licenses/mit-license.php
|
http://www.opensource.org/licenses/mit-license.php
|
||||||
"""
|
"""
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
import re, string, random, glob, operator, heapq
|
import re, string, random, glob, operator, heapq
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
@@ -27,7 +28,7 @@ def test(verbose=None):
|
|||||||
"""Run some tests, taken from the chapter.
|
"""Run some tests, taken from the chapter.
|
||||||
Since the hillclimbing algorithm is randomized, some tests may fail."""
|
Since the hillclimbing algorithm is randomized, some tests may fail."""
|
||||||
import doctest
|
import doctest
|
||||||
print 'Running tests...'
|
print('Running tests...')
|
||||||
doctest.testfile('ngrams-test.txt', verbose=verbose)
|
doctest.testfile('ngrams-test.txt', verbose=verbose)
|
||||||
|
|
||||||
################ Word Segmentation (p. 223)
|
################ Word Segmentation (p. 223)
|
||||||
@@ -97,9 +98,10 @@ def segment2(text, prev='<S>'):
|
|||||||
for first,rem in splits(text)]
|
for first,rem in splits(text)]
|
||||||
return max(candidates)
|
return max(candidates)
|
||||||
|
|
||||||
def combine(Pfirst, first, (Prem, rem)):
|
def combine(Pfirst, first, Prem__rem):
|
||||||
"Combine first and rem results into one (probability, words) pair."
|
"Combine first and rem results into one (probability, words) pair."
|
||||||
return Pfirst+Prem, [first]+rem
|
(Prem, rem) = Prem__rem
|
||||||
|
return Pfirst+Prem, [first]+rem
|
||||||
|
|
||||||
################ Secret Codes (p. 228-230)
|
################ Secret Codes (p. 228-230)
|
||||||
|
|
||||||
@@ -166,7 +168,7 @@ def hillclimb(x, f, neighbors, steps=10000):
|
|||||||
if fx2 > fx:
|
if fx2 > fx:
|
||||||
x, fx = x2, fx2
|
x, fx = x2, fx2
|
||||||
neighborhood = iter(neighbors(x))
|
neighborhood = iter(neighbors(x))
|
||||||
if debugging: print 'hillclimb:', x, int(fx)
|
if debugging: print('hillclimb:', x, int(fx))
|
||||||
return x
|
return x
|
||||||
|
|
||||||
debugging = False
|
debugging = False
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from __future__ import print_function
|
||||||
import string, random, os, re, bisect
|
import string, random, os, re, bisect
|
||||||
|
|
||||||
"""Produce Panama-ish Palindromes. Copyright (C) 2002, Peter Norvig.
|
"""Produce Panama-ish Palindromes. Copyright (C) 2002, Peter Norvig.
|
||||||
@@ -127,7 +128,7 @@ class Panama:
|
|||||||
"Write current state to log file."
|
"Write current state to log file."
|
||||||
if len(self) > self.best + 200:
|
if len(self) > self.best + 200:
|
||||||
self.best = len(self)
|
self.best = len(self)
|
||||||
print self.best
|
print(self.best)
|
||||||
self.bestphrase = str(self)
|
self.bestphrase = str(self)
|
||||||
assert is_panama(self.bestphrase)
|
assert is_panama(self.bestphrase)
|
||||||
f = open('pallog%d.txt' % os.getpid(), 'w')
|
f = open('pallog%d.txt' % os.getpid(), 'w')
|
||||||
|
|||||||
20
py/pal2.py
20
py/pal2.py
@@ -1,5 +1,11 @@
|
|||||||
|
from __future__ import print_function
|
||||||
import random, re, bisect, time
|
import random, re, bisect, time
|
||||||
|
|
||||||
|
try:
|
||||||
|
xrange # Python 2
|
||||||
|
except NameError:
|
||||||
|
xrange = range # Python 3
|
||||||
|
|
||||||
"""Produce Panama-ish Palindromes. Copyright (C) 2002-2008, Peter Norvig."""
|
"""Produce Panama-ish Palindromes. Copyright (C) 2002-2008, Peter Norvig."""
|
||||||
|
|
||||||
################ Checking for Palindromes
|
################ Checking for Palindromes
|
||||||
@@ -107,10 +113,10 @@ def anpdictshort():
|
|||||||
"Find the words that are valid when every phrase must start with 'a'"
|
"Find the words that are valid when every phrase must start with 'a'"
|
||||||
def segment(word): return [s for s in word.split('a') if s]
|
def segment(word): return [s for s in word.split('a') if s]
|
||||||
def valid(word): return all(reversestr(s) in segments for s in segment(word))
|
def valid(word): return all(reversestr(s) in segments for s in segment(word))
|
||||||
words = map(canonical, file('anpdict.txt'))
|
words = map(canonical, open('anpdict.txt'))
|
||||||
segments = set(s for w in words for s in segment(canonical(w)))
|
segments = set(s for w in words for s in segment(canonical(w)))
|
||||||
valid_words = [paldict.truename[w] for w in words if valid(w)]
|
valid_words = [paldict.truename[w] for w in words if valid(w)]
|
||||||
file('anpdict-short.txt', 'w').write('\n'.join(valid_words))
|
open('anpdict-short.txt', 'w').write('\n'.join(valid_words))
|
||||||
|
|
||||||
################ Search for a palindrome
|
################ Search for a palindrome
|
||||||
|
|
||||||
@@ -185,14 +191,14 @@ class Panama:
|
|||||||
|
|
||||||
def add_reversibles(self):
|
def add_reversibles(self):
|
||||||
"Add in reversible words."
|
"Add in reversible words."
|
||||||
print 'using reversibles ...'
|
print('using reversibles ...')
|
||||||
for (word, rword) in self.dict.reversible_words().items():
|
for (word, rword) in self.dict.reversible_words().items():
|
||||||
if word not in self.seen and rword not in self.seen:
|
if word not in self.seen and rword not in self.seen:
|
||||||
self.add('left', word)
|
self.add('left', word)
|
||||||
self.add('right', rword)
|
self.add('right', rword)
|
||||||
self.used_reversibles = True
|
self.used_reversibles = True
|
||||||
self.stack = []
|
self.stack = []
|
||||||
print '...done'
|
print('...done')
|
||||||
|
|
||||||
def report(self):
|
def report(self):
|
||||||
"Report a new palindrome to log file (if it is sufficiently big)."
|
"Report a new palindrome to log file (if it is sufficiently big)."
|
||||||
@@ -202,8 +208,8 @@ class Panama:
|
|||||||
if N > self.best and (N > 12500 or N > self.best+500):
|
if N > self.best and (N > 12500 or N > self.best+500):
|
||||||
self.best = len(self)
|
self.best = len(self)
|
||||||
self.bestphrase = str(self)
|
self.bestphrase = str(self)
|
||||||
print '%5d phrases (%5d words) in %3d seconds' % (
|
print('%5d phrases (%5d words) in %3d seconds' % (
|
||||||
self.best, self.bestphrase.count(' ')+1, time.clock() - self.starttime)
|
self.best, self.bestphrase.count(' ')+1, time.clock() - self.starttime))
|
||||||
assert is_panama(self.bestphrase)
|
assert is_panama(self.bestphrase)
|
||||||
f = open('pallog%d.txt' % (id(self) % 10000), 'w')
|
f = open('pallog%d.txt' % (id(self) % 10000), 'w')
|
||||||
f.write(self.bestphrase + '\n')
|
f.write(self.bestphrase + '\n')
|
||||||
@@ -254,7 +260,7 @@ def tests(p=Panama()):
|
|||||||
d.tryharder = False
|
d.tryharder = False
|
||||||
assert d.startswith('oklahoma') == ['oklahoma']
|
assert d.startswith('oklahoma') == ['oklahoma']
|
||||||
assert d.startswith('fsfdsfdsfds') == []
|
assert d.startswith('fsfdsfdsfds') == []
|
||||||
print 'all tests pass'
|
print('all tests pass')
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
p = Panama();
|
p = Panama();
|
||||||
|
|||||||
29
py/parse.py
29
py/parse.py
@@ -1,3 +1,4 @@
|
|||||||
|
from __future__ import print_function
|
||||||
grammar = {
|
grammar = {
|
||||||
'Noun': ['stench', 'wumpus'],
|
'Noun': ['stench', 'wumpus'],
|
||||||
'Verb': ['is', 'smell'],
|
'Verb': ['is', 'smell'],
|
||||||
@@ -9,16 +10,16 @@ grammar = {
|
|||||||
'Preposition': ['to', 'in'],
|
'Preposition': ['to', 'in'],
|
||||||
'Conjunction': ['and', 'or'],
|
'Conjunction': ['and', 'or'],
|
||||||
'Digit': ['0', '1'],
|
'Digit': ['0', '1'],
|
||||||
|
|
||||||
'S': [['NP', 'VP'], ['S', 'Comjunction', 'S']],
|
'S': [['NP', 'VP'], ['S', 'Comjunction', 'S']],
|
||||||
'NP': ['Pronoun', 'Noun', ['Article', 'Noun'], ['Digit', 'Digit'],
|
'NP': ['Pronoun', 'Noun', ['Article', 'Noun'], ['Digit', 'Digit'],
|
||||||
['NP', 'PP'], ['NP', 'RelClause']],
|
['NP', 'PP'], ['NP', 'RelClause']],
|
||||||
'VP': ['Verb', ['VP', 'NP'], ['VP', 'Adjective'], ['VP', 'PP'],
|
'VP': ['Verb', ['VP', 'NP'], ['VP', 'Adjective'], ['VP', 'PP'],
|
||||||
['VP', 'Adverb']],
|
['VP', 'Adverb']],
|
||||||
'PP': [['Preposition', 'NP']],
|
'PP': [['Preposition', 'NP']],
|
||||||
'RelClause': [['that', 'VP']]
|
'RelClause': [['that', 'VP']]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def parse(forest, grammar):
|
def parse(forest, grammar):
|
||||||
if len(forest) == 1 and category(forest[0]) == 'S':
|
if len(forest) == 1 and category(forest[0]) == 'S':
|
||||||
@@ -26,16 +27,16 @@ def parse(forest, grammar):
|
|||||||
for i in range(len(forest)):
|
for i in range(len(forest)):
|
||||||
for lhs in grammar.keys():
|
for lhs in grammar.keys():
|
||||||
for rhs in grammar[lhs]:
|
for rhs in grammar[lhs]:
|
||||||
rhs = mklist(rhs)
|
rhs = mklist(rhs)
|
||||||
n = len(rhs)
|
n = len(rhs)
|
||||||
subsequence = forest[i:i+n]
|
subsequence = forest[i:i+n]
|
||||||
if match(subsequence, rhs):
|
if match(subsequence, rhs):
|
||||||
print subsequence, lhs, '=>', rhs
|
print(subsequence, lhs, '=>', rhs)
|
||||||
forest2 = forest[:]
|
forest2 = forest[:]
|
||||||
forest2[i:i+n] = [(lhs, subsequence)]
|
forest2[i:i+n] = [(lhs, subsequence)]
|
||||||
result = parse(forest2, grammar)
|
result = parse(forest2, grammar)
|
||||||
if result != None:
|
if result != None:
|
||||||
return result
|
return result
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def mklist(x):
|
def mklist(x):
|
||||||
|
|||||||
@@ -7,6 +7,11 @@ From the shell, do:
|
|||||||
|
|
||||||
import re, string, time, os
|
import re, string, time, os
|
||||||
|
|
||||||
|
try:
|
||||||
|
cmp # Python 2
|
||||||
|
except NameError:
|
||||||
|
def cmp(x, y): # Python 3
|
||||||
|
return (x > y) - (x < y)
|
||||||
|
|
||||||
id = r'[a-zA-Z_][a-zA-Z_0-9]*' ## RE for a Python identifier
|
id = r'[a-zA-Z_][a-zA-Z_0-9]*' ## RE for a Python identifier
|
||||||
g1, g2, g3, g4 = r'\1 \2 \3 \4'.split() ## groups for re.matches
|
g1, g2, g3, g4 = r'\1 \2 \3 \4'.split() ## groups for re.matches
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from __future__ import division
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
import re
|
import re
|
||||||
from accum import *
|
from accum import *
|
||||||
|
|
||||||
@@ -18,10 +19,10 @@ def expand_accumulations(program_text):
|
|||||||
|
|
||||||
def test1(acc_display, expected):
|
def test1(acc_display, expected):
|
||||||
"Eval an accumulation display and see if it gets the expected answer."
|
"Eval an accumulation display and see if it gets the expected answer."
|
||||||
print acc_display
|
print(acc_display)
|
||||||
result = eval(expand_accumulations(acc_display))
|
result = eval(expand_accumulations(acc_display))
|
||||||
assert result == expected, ('Got %s; expected %s' % (result, expected))
|
assert result == expected, ('Got %s; expected %s' % (result, expected))
|
||||||
print ' ==> %s' % result
|
print(' ==> %s' % result)
|
||||||
|
|
||||||
#### Initialize some data
|
#### Initialize some data
|
||||||
temp = [70, 70, 71, 74, 76, 76, 72, 76, 77, 77, 77, 78,
|
temp = [70, 70, 71, 74, 76, 76, 72, 76, 77, 77, 77, 78,
|
||||||
@@ -33,11 +34,11 @@ candidates = votes.keys()
|
|||||||
|
|
||||||
def test():
|
def test():
|
||||||
|
|
||||||
print 'temp = ', temp
|
print('temp = ', temp)
|
||||||
print 'data = temp'
|
print('data = temp')
|
||||||
print 'votes = ', votes
|
print('votes = ', votes)
|
||||||
print 'candidates = ', candidates
|
print('candidates = ', candidates)
|
||||||
print
|
print()
|
||||||
|
|
||||||
#### Test some accumulation displays
|
#### Test some accumulation displays
|
||||||
test1("[Max: temp[hour] for hour in range(24)]",
|
test1("[Max: temp[hour] for hour in range(24)]",
|
||||||
|
|||||||
21
py/yaptu.py
21
py/yaptu.py
@@ -61,6 +61,7 @@ lines
|
|||||||
Time for work.
|
Time for work.
|
||||||
#]
|
#]
|
||||||
"""
|
"""
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
import sys, re, os, os.path
|
import sys, re, os, os.path
|
||||||
|
|
||||||
@@ -73,14 +74,14 @@ class Copier:
|
|||||||
def repl(match, self=self):
|
def repl(match, self=self):
|
||||||
"Replace the match with its value as a Python expression."
|
"Replace the match with its value as a Python expression."
|
||||||
expr = self.preproc(match.group(1), 'eval')
|
expr = self.preproc(match.group(1), 'eval')
|
||||||
if self.verbose: print '=== eval{%s}' % expr,
|
if self.verbose: print('=== eval{%s}' % expr, end=' ')
|
||||||
try:
|
try:
|
||||||
val = eval(expr, self.globals)
|
val = eval(expr, self.globals)
|
||||||
except:
|
except:
|
||||||
self.oops('eval', expr)
|
self.oops('eval', expr)
|
||||||
if callable(val): val = val()
|
if callable(val): val = val()
|
||||||
if val == None: val = ''
|
if val == None: val = ''
|
||||||
if self.verbose: print '========>', val
|
if self.verbose: print('========>', val)
|
||||||
return str(val)
|
return str(val)
|
||||||
|
|
||||||
block = self.globals['_bl']
|
block = self.globals['_bl']
|
||||||
@@ -127,16 +128,16 @@ class Copier:
|
|||||||
def execute(self, stmt):
|
def execute(self, stmt):
|
||||||
stmt = self.preproc(stmt, 'exec') + '\n'
|
stmt = self.preproc(stmt, 'exec') + '\n'
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
print "******* executing {%s} in %s" % (stmt, self.globals.keys())
|
print("******* executing {%s} in %s" % (stmt, self.globals.keys()))
|
||||||
try:
|
try:
|
||||||
exec stmt in self.globals
|
exec(stmt, self.globals)
|
||||||
except:
|
except:
|
||||||
self.oops('exec', stmt)
|
self.oops('exec', stmt)
|
||||||
|
|
||||||
def oops(self, why, what):
|
def oops(self, why, what):
|
||||||
print 'Something went wrong in %sing {%s}' % (why, what)
|
print('Something went wrong in %sing {%s}' % (why, what))
|
||||||
print 'Globals:', self.globals.keys(), \
|
print('Globals:', self.globals.keys(), \
|
||||||
self.globals.get('SECTIONS', '???')
|
self.globals.get('SECTIONS', '???'))
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def preproc(self, string, why, reg=re.compile(r"\s([<>&])\s"),
|
def preproc(self, string, why, reg=re.compile(r"\s([<>&])\s"),
|
||||||
@@ -155,10 +156,10 @@ class Copier:
|
|||||||
"Convert filename.* to filename.ext, where ext defaults to html."
|
"Convert filename.* to filename.ext, where ext defaults to html."
|
||||||
global yaptu_filename
|
global yaptu_filename
|
||||||
outname = re.sub('[.][a-zA-Z0-9]+?$', '', filename) + '.'+ext
|
outname = re.sub('[.][a-zA-Z0-9]+?$', '', filename) + '.'+ext
|
||||||
print 'Transforming', filename, 'to', outname
|
print('Transforming', filename, 'to', outname)
|
||||||
self.globals['_bl'] = file(filename).readlines()
|
self.globals['_bl'] = open(filename).readlines()
|
||||||
yaptu_filename = filename
|
yaptu_filename = filename
|
||||||
self.outf = file(outname, 'w')
|
self.outf = open(outname, 'w')
|
||||||
self.copyblock()
|
self.copyblock()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
Reference in New Issue
Block a user