using for loop to install conda package
This commit is contained in:
BIN
.CondaPkg/env/Tools/demo/__pycache__/beer.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/demo/__pycache__/beer.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/demo/__pycache__/eiffel.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/demo/__pycache__/eiffel.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/demo/__pycache__/hanoi.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/demo/__pycache__/hanoi.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/demo/__pycache__/life.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/demo/__pycache__/life.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/demo/__pycache__/markov.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/demo/__pycache__/markov.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/demo/__pycache__/mcast.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/demo/__pycache__/mcast.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/demo/__pycache__/queens.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/demo/__pycache__/queens.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/demo/__pycache__/redemo.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/demo/__pycache__/redemo.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/demo/__pycache__/rpython.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/demo/__pycache__/rpython.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/demo/__pycache__/rpythond.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/demo/__pycache__/rpythond.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/demo/__pycache__/sortvisu.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/demo/__pycache__/sortvisu.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/demo/__pycache__/spreadsheet.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/demo/__pycache__/spreadsheet.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/demo/__pycache__/vector.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/demo/__pycache__/vector.cpython-311.pyc
vendored
Normal file
Binary file not shown.
25
.CondaPkg/env/Tools/demo/beer.py
vendored
Normal file
25
.CondaPkg/env/Tools/demo/beer.py
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
A Python version of the classic "bottles of beer on the wall" programming
|
||||
example.
|
||||
|
||||
By Guido van Rossum, demystified after a version by Fredrik Lundh.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
n = 100
|
||||
if sys.argv[1:]:
|
||||
n = int(sys.argv[1])
|
||||
|
||||
def bottle(n):
|
||||
if n == 0: return "no more bottles of beer"
|
||||
if n == 1: return "one bottle of beer"
|
||||
return str(n) + " bottles of beer"
|
||||
|
||||
for i in range(n, 0, -1):
|
||||
print(bottle(i), "on the wall,")
|
||||
print(bottle(i) + ".")
|
||||
print("Take one down, pass it around,")
|
||||
print(bottle(i-1), "on the wall.")
|
||||
146
.CondaPkg/env/Tools/demo/eiffel.py
vendored
Normal file
146
.CondaPkg/env/Tools/demo/eiffel.py
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Support Eiffel-style preconditions and postconditions for functions.
|
||||
|
||||
An example for Python metaclasses.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from types import FunctionType as function
|
||||
|
||||
class EiffelBaseMetaClass(type):
|
||||
|
||||
def __new__(meta, name, bases, dict):
|
||||
meta.convert_methods(dict)
|
||||
return super(EiffelBaseMetaClass, meta).__new__(
|
||||
meta, name, bases, dict)
|
||||
|
||||
@classmethod
|
||||
def convert_methods(cls, dict):
|
||||
"""Replace functions in dict with EiffelMethod wrappers.
|
||||
|
||||
The dict is modified in place.
|
||||
|
||||
If a method ends in _pre or _post, it is removed from the dict
|
||||
regardless of whether there is a corresponding method.
|
||||
"""
|
||||
# find methods with pre or post conditions
|
||||
methods = []
|
||||
for k, v in dict.items():
|
||||
if k.endswith('_pre') or k.endswith('_post'):
|
||||
assert isinstance(v, function)
|
||||
elif isinstance(v, function):
|
||||
methods.append(k)
|
||||
for m in methods:
|
||||
pre = dict.get("%s_pre" % m)
|
||||
post = dict.get("%s_post" % m)
|
||||
if pre or post:
|
||||
dict[m] = cls.make_eiffel_method(dict[m], pre, post)
|
||||
|
||||
|
||||
class EiffelMetaClass1(EiffelBaseMetaClass):
|
||||
# an implementation of the "eiffel" meta class that uses nested functions
|
||||
|
||||
@staticmethod
|
||||
def make_eiffel_method(func, pre, post):
|
||||
def method(self, *args, **kwargs):
|
||||
if pre:
|
||||
pre(self, *args, **kwargs)
|
||||
rv = func(self, *args, **kwargs)
|
||||
if post:
|
||||
post(self, rv, *args, **kwargs)
|
||||
return rv
|
||||
|
||||
if func.__doc__:
|
||||
method.__doc__ = func.__doc__
|
||||
|
||||
return method
|
||||
|
||||
|
||||
class EiffelMethodWrapper:
|
||||
|
||||
def __init__(self, inst, descr):
|
||||
self._inst = inst
|
||||
self._descr = descr
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self._descr.callmethod(self._inst, args, kwargs)
|
||||
|
||||
|
||||
class EiffelDescriptor:
|
||||
|
||||
def __init__(self, func, pre, post):
|
||||
self._func = func
|
||||
self._pre = pre
|
||||
self._post = post
|
||||
|
||||
self.__name__ = func.__name__
|
||||
self.__doc__ = func.__doc__
|
||||
|
||||
def __get__(self, obj, cls=None):
|
||||
return EiffelMethodWrapper(obj, self)
|
||||
|
||||
def callmethod(self, inst, args, kwargs):
|
||||
if self._pre:
|
||||
self._pre(inst, *args, **kwargs)
|
||||
x = self._func(inst, *args, **kwargs)
|
||||
if self._post:
|
||||
self._post(inst, x, *args, **kwargs)
|
||||
return x
|
||||
|
||||
|
||||
class EiffelMetaClass2(EiffelBaseMetaClass):
|
||||
# an implementation of the "eiffel" meta class that uses descriptors
|
||||
|
||||
make_eiffel_method = EiffelDescriptor
|
||||
|
||||
|
||||
class Tests(unittest.TestCase):
|
||||
|
||||
def testEiffelMetaClass1(self):
|
||||
self._test(EiffelMetaClass1)
|
||||
|
||||
def testEiffelMetaClass2(self):
|
||||
self._test(EiffelMetaClass2)
|
||||
|
||||
def _test(self, metaclass):
|
||||
class Eiffel(metaclass=metaclass):
|
||||
pass
|
||||
|
||||
class Test(Eiffel):
|
||||
def m(self, arg):
|
||||
"""Make it a little larger"""
|
||||
return arg + 1
|
||||
|
||||
def m2(self, arg):
|
||||
"""Make it a little larger"""
|
||||
return arg + 1
|
||||
|
||||
def m2_pre(self, arg):
|
||||
assert arg > 0
|
||||
|
||||
def m2_post(self, result, arg):
|
||||
assert result > arg
|
||||
|
||||
class Sub(Test):
|
||||
def m2(self, arg):
|
||||
return arg**2
|
||||
|
||||
def m2_post(self, Result, arg):
|
||||
super(Sub, self).m2_post(Result, arg)
|
||||
assert Result < 100
|
||||
|
||||
t = Test()
|
||||
self.assertEqual(t.m(1), 2)
|
||||
self.assertEqual(t.m2(1), 2)
|
||||
self.assertRaises(AssertionError, t.m2, 0)
|
||||
|
||||
s = Sub()
|
||||
self.assertRaises(AssertionError, s.m2, 1)
|
||||
self.assertRaises(AssertionError, s.m2, 10)
|
||||
self.assertEqual(s.m2(5), 25)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
154
.CondaPkg/env/Tools/demo/hanoi.py
vendored
Normal file
154
.CondaPkg/env/Tools/demo/hanoi.py
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Animated Towers of Hanoi using Tk with optional bitmap file in background.
|
||||
|
||||
Usage: hanoi.py [n [bitmapfile]]
|
||||
|
||||
n is the number of pieces to animate; default is 4, maximum 15.
|
||||
|
||||
The bitmap file can be any X11 bitmap file (look in /usr/include/X11/bitmaps for
|
||||
samples); it is displayed as the background of the animation. Default is no
|
||||
bitmap.
|
||||
"""
|
||||
|
||||
from tkinter import Tk, Canvas
|
||||
|
||||
# Basic Towers-of-Hanoi algorithm: move n pieces from a to b, using c
|
||||
# as temporary. For each move, call report()
|
||||
def hanoi(n, a, b, c, report):
|
||||
if n <= 0: return
|
||||
hanoi(n-1, a, c, b, report)
|
||||
report(n, a, b)
|
||||
hanoi(n-1, c, b, a, report)
|
||||
|
||||
|
||||
# The graphical interface
|
||||
class Tkhanoi:
|
||||
|
||||
# Create our objects
|
||||
def __init__(self, n, bitmap=None):
|
||||
self.n = n
|
||||
self.tk = tk = Tk()
|
||||
self.canvas = c = Canvas(tk)
|
||||
c.pack()
|
||||
width, height = tk.getint(c['width']), tk.getint(c['height'])
|
||||
|
||||
# Add background bitmap
|
||||
if bitmap:
|
||||
self.bitmap = c.create_bitmap(width//2, height//2,
|
||||
bitmap=bitmap,
|
||||
foreground='blue')
|
||||
|
||||
# Generate pegs
|
||||
pegwidth = 10
|
||||
pegheight = height//2
|
||||
pegdist = width//3
|
||||
x1, y1 = (pegdist-pegwidth)//2, height*1//3
|
||||
x2, y2 = x1+pegwidth, y1+pegheight
|
||||
self.pegs = []
|
||||
p = c.create_rectangle(x1, y1, x2, y2, fill='black')
|
||||
self.pegs.append(p)
|
||||
x1, x2 = x1+pegdist, x2+pegdist
|
||||
p = c.create_rectangle(x1, y1, x2, y2, fill='black')
|
||||
self.pegs.append(p)
|
||||
x1, x2 = x1+pegdist, x2+pegdist
|
||||
p = c.create_rectangle(x1, y1, x2, y2, fill='black')
|
||||
self.pegs.append(p)
|
||||
self.tk.update()
|
||||
|
||||
# Generate pieces
|
||||
pieceheight = pegheight//16
|
||||
maxpiecewidth = pegdist*2//3
|
||||
minpiecewidth = 2*pegwidth
|
||||
self.pegstate = [[], [], []]
|
||||
self.pieces = {}
|
||||
x1, y1 = (pegdist-maxpiecewidth)//2, y2-pieceheight-2
|
||||
x2, y2 = x1+maxpiecewidth, y1+pieceheight
|
||||
dx = (maxpiecewidth-minpiecewidth) // (2*max(1, n-1))
|
||||
for i in range(n, 0, -1):
|
||||
p = c.create_rectangle(x1, y1, x2, y2, fill='red')
|
||||
self.pieces[i] = p
|
||||
self.pegstate[0].append(i)
|
||||
x1, x2 = x1 + dx, x2-dx
|
||||
y1, y2 = y1 - pieceheight-2, y2-pieceheight-2
|
||||
self.tk.update()
|
||||
self.tk.after(25)
|
||||
|
||||
# Run -- never returns
|
||||
def run(self):
|
||||
while True:
|
||||
hanoi(self.n, 0, 1, 2, self.report)
|
||||
hanoi(self.n, 1, 2, 0, self.report)
|
||||
hanoi(self.n, 2, 0, 1, self.report)
|
||||
hanoi(self.n, 0, 2, 1, self.report)
|
||||
hanoi(self.n, 2, 1, 0, self.report)
|
||||
hanoi(self.n, 1, 0, 2, self.report)
|
||||
|
||||
# Reporting callback for the actual hanoi function
|
||||
def report(self, i, a, b):
|
||||
if self.pegstate[a][-1] != i: raise RuntimeError # Assertion
|
||||
del self.pegstate[a][-1]
|
||||
p = self.pieces[i]
|
||||
c = self.canvas
|
||||
|
||||
# Lift the piece above peg a
|
||||
ax1, ay1, ax2, ay2 = c.bbox(self.pegs[a])
|
||||
while True:
|
||||
x1, y1, x2, y2 = c.bbox(p)
|
||||
if y2 < ay1: break
|
||||
c.move(p, 0, -1)
|
||||
self.tk.update()
|
||||
|
||||
# Move it towards peg b
|
||||
bx1, by1, bx2, by2 = c.bbox(self.pegs[b])
|
||||
newcenter = (bx1+bx2)//2
|
||||
while True:
|
||||
x1, y1, x2, y2 = c.bbox(p)
|
||||
center = (x1+x2)//2
|
||||
if center == newcenter: break
|
||||
if center > newcenter: c.move(p, -1, 0)
|
||||
else: c.move(p, 1, 0)
|
||||
self.tk.update()
|
||||
|
||||
# Move it down on top of the previous piece
|
||||
pieceheight = y2-y1
|
||||
newbottom = by2 - pieceheight*len(self.pegstate[b]) - 2
|
||||
while True:
|
||||
x1, y1, x2, y2 = c.bbox(p)
|
||||
if y2 >= newbottom: break
|
||||
c.move(p, 0, 1)
|
||||
self.tk.update()
|
||||
|
||||
# Update peg state
|
||||
self.pegstate[b].append(i)
|
||||
|
||||
|
||||
def main():
|
||||
import sys
|
||||
|
||||
# First argument is number of pegs, default 4
|
||||
if sys.argv[1:]:
|
||||
n = int(sys.argv[1])
|
||||
else:
|
||||
n = 4
|
||||
|
||||
# Second argument is bitmap file, default none
|
||||
if sys.argv[2:]:
|
||||
bitmap = sys.argv[2]
|
||||
# Reverse meaning of leading '@' compared to Tk
|
||||
if bitmap[0] == '@': bitmap = bitmap[1:]
|
||||
else: bitmap = '@' + bitmap
|
||||
else:
|
||||
bitmap = None
|
||||
|
||||
# Create the graphical objects...
|
||||
h = Tkhanoi(n, bitmap)
|
||||
|
||||
# ...and run!
|
||||
h.run()
|
||||
|
||||
|
||||
# Call main when run as script
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
262
.CondaPkg/env/Tools/demo/life.py
vendored
Normal file
262
.CondaPkg/env/Tools/demo/life.py
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
A curses-based version of Conway's Game of Life.
|
||||
|
||||
An empty board will be displayed, and the following commands are available:
|
||||
E : Erase the board
|
||||
R : Fill the board randomly
|
||||
S : Step for a single generation
|
||||
C : Update continuously until a key is struck
|
||||
Q : Quit
|
||||
Cursor keys : Move the cursor around the board
|
||||
Space or Enter : Toggle the contents of the cursor's position
|
||||
|
||||
Contributed by Andrew Kuchling, Mouse support and color by Dafydd Crosby.
|
||||
"""
|
||||
|
||||
import curses
|
||||
import random
|
||||
|
||||
|
||||
class LifeBoard:
|
||||
"""Encapsulates a Life board
|
||||
|
||||
Attributes:
|
||||
X,Y : horizontal and vertical size of the board
|
||||
state : dictionary mapping (x,y) to 0 or 1
|
||||
|
||||
Methods:
|
||||
display(update_board) -- If update_board is true, compute the
|
||||
next generation. Then display the state
|
||||
of the board and refresh the screen.
|
||||
erase() -- clear the entire board
|
||||
make_random() -- fill the board randomly
|
||||
set(y,x) -- set the given cell to Live; doesn't refresh the screen
|
||||
toggle(y,x) -- change the given cell from live to dead, or vice
|
||||
versa, and refresh the screen display
|
||||
|
||||
"""
|
||||
def __init__(self, scr, char=ord('*')):
|
||||
"""Create a new LifeBoard instance.
|
||||
|
||||
scr -- curses screen object to use for display
|
||||
char -- character used to render live cells (default: '*')
|
||||
"""
|
||||
self.state = {}
|
||||
self.scr = scr
|
||||
Y, X = self.scr.getmaxyx()
|
||||
self.X, self.Y = X - 2, Y - 2 - 1
|
||||
self.char = char
|
||||
self.scr.clear()
|
||||
|
||||
# Draw a border around the board
|
||||
border_line = '+' + (self.X * '-') + '+'
|
||||
self.scr.addstr(0, 0, border_line)
|
||||
self.scr.addstr(self.Y + 1, 0, border_line)
|
||||
for y in range(0, self.Y):
|
||||
self.scr.addstr(1 + y, 0, '|')
|
||||
self.scr.addstr(1 + y, self.X + 1, '|')
|
||||
self.scr.refresh()
|
||||
|
||||
def set(self, y, x):
|
||||
"""Set a cell to the live state"""
|
||||
if x < 0 or self.X <= x or y < 0 or self.Y <= y:
|
||||
raise ValueError("Coordinates out of range %i,%i" % (y, x))
|
||||
self.state[x, y] = 1
|
||||
|
||||
def toggle(self, y, x):
|
||||
"""Toggle a cell's state between live and dead"""
|
||||
if x < 0 or self.X <= x or y < 0 or self.Y <= y:
|
||||
raise ValueError("Coordinates out of range %i,%i" % (y, x))
|
||||
if (x, y) in self.state:
|
||||
del self.state[x, y]
|
||||
self.scr.addch(y + 1, x + 1, ' ')
|
||||
else:
|
||||
self.state[x, y] = 1
|
||||
if curses.has_colors():
|
||||
# Let's pick a random color!
|
||||
self.scr.attrset(curses.color_pair(random.randrange(1, 7)))
|
||||
self.scr.addch(y + 1, x + 1, self.char)
|
||||
self.scr.attrset(0)
|
||||
self.scr.refresh()
|
||||
|
||||
def erase(self):
|
||||
"""Clear the entire board and update the board display"""
|
||||
self.state = {}
|
||||
self.display(update_board=False)
|
||||
|
||||
def display(self, update_board=True):
|
||||
"""Display the whole board, optionally computing one generation"""
|
||||
M, N = self.X, self.Y
|
||||
if not update_board:
|
||||
for i in range(0, M):
|
||||
for j in range(0, N):
|
||||
if (i, j) in self.state:
|
||||
self.scr.addch(j + 1, i + 1, self.char)
|
||||
else:
|
||||
self.scr.addch(j + 1, i + 1, ' ')
|
||||
self.scr.refresh()
|
||||
return
|
||||
|
||||
d = {}
|
||||
self.boring = 1
|
||||
for i in range(0, M):
|
||||
L = range(max(0, i - 1), min(M, i + 2))
|
||||
for j in range(0, N):
|
||||
s = 0
|
||||
live = (i, j) in self.state
|
||||
for k in range(max(0, j - 1), min(N, j + 2)):
|
||||
for l in L:
|
||||
if (l, k) in self.state:
|
||||
s += 1
|
||||
s -= live
|
||||
if s == 3:
|
||||
# Birth
|
||||
d[i, j] = 1
|
||||
if curses.has_colors():
|
||||
# Let's pick a random color!
|
||||
self.scr.attrset(curses.color_pair(
|
||||
random.randrange(1, 7)))
|
||||
self.scr.addch(j + 1, i + 1, self.char)
|
||||
self.scr.attrset(0)
|
||||
if not live:
|
||||
self.boring = 0
|
||||
elif s == 2 and live:
|
||||
# Survival
|
||||
d[i, j] = 1
|
||||
elif live:
|
||||
# Death
|
||||
self.scr.addch(j + 1, i + 1, ' ')
|
||||
self.boring = 0
|
||||
self.state = d
|
||||
self.scr.refresh()
|
||||
|
||||
def make_random(self):
|
||||
"Fill the board with a random pattern"
|
||||
self.state = {}
|
||||
for i in range(0, self.X):
|
||||
for j in range(0, self.Y):
|
||||
if random.random() > 0.5:
|
||||
self.set(j, i)
|
||||
|
||||
|
||||
def erase_menu(stdscr, menu_y):
|
||||
"Clear the space where the menu resides"
|
||||
stdscr.move(menu_y, 0)
|
||||
stdscr.clrtoeol()
|
||||
stdscr.move(menu_y + 1, 0)
|
||||
stdscr.clrtoeol()
|
||||
|
||||
|
||||
def display_menu(stdscr, menu_y):
|
||||
"Display the menu of possible keystroke commands"
|
||||
erase_menu(stdscr, menu_y)
|
||||
|
||||
# If color, then light the menu up :-)
|
||||
if curses.has_colors():
|
||||
stdscr.attrset(curses.color_pair(1))
|
||||
stdscr.addstr(menu_y, 4,
|
||||
'Use the cursor keys to move, and space or Enter to toggle a cell.')
|
||||
stdscr.addstr(menu_y + 1, 4,
|
||||
'E)rase the board, R)andom fill, S)tep once or C)ontinuously, Q)uit')
|
||||
stdscr.attrset(0)
|
||||
|
||||
|
||||
def keyloop(stdscr):
|
||||
# Clear the screen and display the menu of keys
|
||||
stdscr.clear()
|
||||
stdscr_y, stdscr_x = stdscr.getmaxyx()
|
||||
menu_y = (stdscr_y - 3) - 1
|
||||
display_menu(stdscr, menu_y)
|
||||
|
||||
# If color, then initialize the color pairs
|
||||
if curses.has_colors():
|
||||
curses.init_pair(1, curses.COLOR_BLUE, 0)
|
||||
curses.init_pair(2, curses.COLOR_CYAN, 0)
|
||||
curses.init_pair(3, curses.COLOR_GREEN, 0)
|
||||
curses.init_pair(4, curses.COLOR_MAGENTA, 0)
|
||||
curses.init_pair(5, curses.COLOR_RED, 0)
|
||||
curses.init_pair(6, curses.COLOR_YELLOW, 0)
|
||||
curses.init_pair(7, curses.COLOR_WHITE, 0)
|
||||
|
||||
# Set up the mask to listen for mouse events
|
||||
curses.mousemask(curses.BUTTON1_CLICKED)
|
||||
|
||||
# Allocate a subwindow for the Life board and create the board object
|
||||
subwin = stdscr.subwin(stdscr_y - 3, stdscr_x, 0, 0)
|
||||
board = LifeBoard(subwin, char=ord('*'))
|
||||
board.display(update_board=False)
|
||||
|
||||
# xpos, ypos are the cursor's position
|
||||
xpos, ypos = board.X // 2, board.Y // 2
|
||||
|
||||
# Main loop:
|
||||
while True:
|
||||
stdscr.move(1 + ypos, 1 + xpos) # Move the cursor
|
||||
c = stdscr.getch() # Get a keystroke
|
||||
if 0 < c < 256:
|
||||
c = chr(c)
|
||||
if c in ' \n':
|
||||
board.toggle(ypos, xpos)
|
||||
elif c in 'Cc':
|
||||
erase_menu(stdscr, menu_y)
|
||||
stdscr.addstr(menu_y, 6, ' Hit any key to stop continuously '
|
||||
'updating the screen.')
|
||||
stdscr.refresh()
|
||||
# Activate nodelay mode; getch() will return -1
|
||||
# if no keystroke is available, instead of waiting.
|
||||
stdscr.nodelay(1)
|
||||
while True:
|
||||
c = stdscr.getch()
|
||||
if c != -1:
|
||||
break
|
||||
stdscr.addstr(0, 0, '/')
|
||||
stdscr.refresh()
|
||||
board.display()
|
||||
stdscr.addstr(0, 0, '+')
|
||||
stdscr.refresh()
|
||||
|
||||
stdscr.nodelay(0) # Disable nodelay mode
|
||||
display_menu(stdscr, menu_y)
|
||||
|
||||
elif c in 'Ee':
|
||||
board.erase()
|
||||
elif c in 'Qq':
|
||||
break
|
||||
elif c in 'Rr':
|
||||
board.make_random()
|
||||
board.display(update_board=False)
|
||||
elif c in 'Ss':
|
||||
board.display()
|
||||
else:
|
||||
# Ignore incorrect keys
|
||||
pass
|
||||
elif c == curses.KEY_UP and ypos > 0:
|
||||
ypos -= 1
|
||||
elif c == curses.KEY_DOWN and ypos + 1 < board.Y:
|
||||
ypos += 1
|
||||
elif c == curses.KEY_LEFT and xpos > 0:
|
||||
xpos -= 1
|
||||
elif c == curses.KEY_RIGHT and xpos + 1 < board.X:
|
||||
xpos += 1
|
||||
elif c == curses.KEY_MOUSE:
|
||||
mouse_id, mouse_x, mouse_y, mouse_z, button_state = curses.getmouse()
|
||||
if (mouse_x > 0 and mouse_x < board.X + 1 and
|
||||
mouse_y > 0 and mouse_y < board.Y + 1):
|
||||
xpos = mouse_x - 1
|
||||
ypos = mouse_y - 1
|
||||
board.toggle(ypos, xpos)
|
||||
else:
|
||||
# They've clicked outside the board
|
||||
curses.flash()
|
||||
else:
|
||||
# Ignore incorrect keys
|
||||
pass
|
||||
|
||||
|
||||
def main(stdscr):
|
||||
keyloop(stdscr) # Enter the main loop
|
||||
|
||||
if __name__ == '__main__':
|
||||
curses.wrapper(main)
|
||||
125
.CondaPkg/env/Tools/demo/markov.py
vendored
Normal file
125
.CondaPkg/env/Tools/demo/markov.py
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Markov chain simulation of words or characters.
|
||||
"""
|
||||
|
||||
class Markov:
|
||||
def __init__(self, histsize, choice):
|
||||
self.histsize = histsize
|
||||
self.choice = choice
|
||||
self.trans = {}
|
||||
|
||||
def add(self, state, next):
|
||||
self.trans.setdefault(state, []).append(next)
|
||||
|
||||
def put(self, seq):
|
||||
n = self.histsize
|
||||
add = self.add
|
||||
add(None, seq[:0])
|
||||
for i in range(len(seq)):
|
||||
add(seq[max(0, i-n):i], seq[i:i+1])
|
||||
add(seq[len(seq)-n:], None)
|
||||
|
||||
def get(self):
|
||||
choice = self.choice
|
||||
trans = self.trans
|
||||
n = self.histsize
|
||||
seq = choice(trans[None])
|
||||
while True:
|
||||
subseq = seq[max(0, len(seq)-n):]
|
||||
options = trans[subseq]
|
||||
next = choice(options)
|
||||
if not next:
|
||||
break
|
||||
seq += next
|
||||
return seq
|
||||
|
||||
|
||||
def test():
|
||||
import sys, random, getopt
|
||||
args = sys.argv[1:]
|
||||
try:
|
||||
opts, args = getopt.getopt(args, '0123456789cdwq')
|
||||
except getopt.error:
|
||||
print('Usage: %s [-#] [-cddqw] [file] ...' % sys.argv[0])
|
||||
print('Options:')
|
||||
print('-#: 1-digit history size (default 2)')
|
||||
print('-c: characters (default)')
|
||||
print('-w: words')
|
||||
print('-d: more debugging output')
|
||||
print('-q: no debugging output')
|
||||
print('Input files (default stdin) are split in paragraphs')
|
||||
print('separated blank lines and each paragraph is split')
|
||||
print('in words by whitespace, then reconcatenated with')
|
||||
print('exactly one space separating words.')
|
||||
print('Output consists of paragraphs separated by blank')
|
||||
print('lines, where lines are no longer than 72 characters.')
|
||||
sys.exit(2)
|
||||
histsize = 2
|
||||
do_words = False
|
||||
debug = 1
|
||||
for o, a in opts:
|
||||
if '-0' <= o <= '-9': histsize = int(o[1:])
|
||||
if o == '-c': do_words = False
|
||||
if o == '-d': debug += 1
|
||||
if o == '-q': debug = 0
|
||||
if o == '-w': do_words = True
|
||||
if not args:
|
||||
args = ['-']
|
||||
|
||||
m = Markov(histsize, random.choice)
|
||||
try:
|
||||
for filename in args:
|
||||
if filename == '-':
|
||||
f = sys.stdin
|
||||
if f.isatty():
|
||||
print('Sorry, need stdin from file')
|
||||
continue
|
||||
else:
|
||||
f = open(filename, 'r')
|
||||
with f:
|
||||
if debug: print('processing', filename, '...')
|
||||
text = f.read()
|
||||
paralist = text.split('\n\n')
|
||||
for para in paralist:
|
||||
if debug > 1: print('feeding ...')
|
||||
words = para.split()
|
||||
if words:
|
||||
if do_words:
|
||||
data = tuple(words)
|
||||
else:
|
||||
data = ' '.join(words)
|
||||
m.put(data)
|
||||
except KeyboardInterrupt:
|
||||
print('Interrupted -- continue with data read so far')
|
||||
if not m.trans:
|
||||
print('No valid input files')
|
||||
return
|
||||
if debug: print('done.')
|
||||
|
||||
if debug > 1:
|
||||
for key in m.trans.keys():
|
||||
if key is None or len(key) < histsize:
|
||||
print(repr(key), m.trans[key])
|
||||
if histsize == 0: print(repr(''), m.trans[''])
|
||||
print()
|
||||
while True:
|
||||
data = m.get()
|
||||
if do_words:
|
||||
words = data
|
||||
else:
|
||||
words = data.split()
|
||||
n = 0
|
||||
limit = 72
|
||||
for w in words:
|
||||
if n + len(w) > limit:
|
||||
print()
|
||||
n = 0
|
||||
print(w, end=' ')
|
||||
n += len(w) + 1
|
||||
print()
|
||||
print()
|
||||
|
||||
if __name__ == "__main__":
|
||||
test()
|
||||
82
.CondaPkg/env/Tools/demo/mcast.py
vendored
Normal file
82
.CondaPkg/env/Tools/demo/mcast.py
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Send/receive UDP multicast packets.
|
||||
Requires that your OS kernel supports IP multicast.
|
||||
|
||||
Usage:
|
||||
mcast -s (sender, IPv4)
|
||||
mcast -s -6 (sender, IPv6)
|
||||
mcast (receivers, IPv4)
|
||||
mcast -6 (receivers, IPv6)
|
||||
"""
|
||||
|
||||
MYPORT = 8123
|
||||
MYGROUP_4 = '225.0.0.250'
|
||||
MYGROUP_6 = 'ff15:7079:7468:6f6e:6465:6d6f:6d63:6173'
|
||||
MYTTL = 1 # Increase to reach other networks
|
||||
|
||||
import time
|
||||
import struct
|
||||
import socket
|
||||
import sys
|
||||
|
||||
def main():
|
||||
group = MYGROUP_6 if "-6" in sys.argv[1:] else MYGROUP_4
|
||||
|
||||
if "-s" in sys.argv[1:]:
|
||||
sender(group)
|
||||
else:
|
||||
receiver(group)
|
||||
|
||||
|
||||
def sender(group):
|
||||
addrinfo = socket.getaddrinfo(group, None)[0]
|
||||
|
||||
s = socket.socket(addrinfo[0], socket.SOCK_DGRAM)
|
||||
|
||||
# Set Time-to-live (optional)
|
||||
ttl_bin = struct.pack('@i', MYTTL)
|
||||
if addrinfo[0] == socket.AF_INET: # IPv4
|
||||
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl_bin)
|
||||
else:
|
||||
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, ttl_bin)
|
||||
|
||||
while True:
|
||||
data = repr(time.time()).encode('utf-8') + b'\0'
|
||||
s.sendto(data, (addrinfo[4][0], MYPORT))
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
def receiver(group):
|
||||
# Look up multicast group address in name server and find out IP version
|
||||
addrinfo = socket.getaddrinfo(group, None)[0]
|
||||
|
||||
# Create a socket
|
||||
s = socket.socket(addrinfo[0], socket.SOCK_DGRAM)
|
||||
|
||||
# Allow multiple copies of this program on one machine
|
||||
# (not strictly needed)
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
|
||||
# Bind it to the port
|
||||
s.bind(('', MYPORT))
|
||||
|
||||
group_bin = socket.inet_pton(addrinfo[0], addrinfo[4][0])
|
||||
# Join group
|
||||
if addrinfo[0] == socket.AF_INET: # IPv4
|
||||
mreq = group_bin + struct.pack('=I', socket.INADDR_ANY)
|
||||
s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
|
||||
else:
|
||||
mreq = group_bin + struct.pack('@I', 0)
|
||||
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
|
||||
|
||||
# Loop, printing any data we receive
|
||||
while True:
|
||||
data, sender = s.recvfrom(1500)
|
||||
while data[-1:] == '\0': data = data[:-1] # Strip trailing \0's
|
||||
print(str(sender) + ' ' + repr(data))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
85
.CondaPkg/env/Tools/demo/queens.py
vendored
Normal file
85
.CondaPkg/env/Tools/demo/queens.py
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
N queens problem.
|
||||
|
||||
The (well-known) problem is due to Niklaus Wirth.
|
||||
|
||||
This solution is inspired by Dijkstra (Structured Programming). It is
|
||||
a classic recursive backtracking approach.
|
||||
"""
|
||||
|
||||
N = 8 # Default; command line overrides
|
||||
|
||||
class Queens:
|
||||
|
||||
def __init__(self, n=N):
|
||||
self.n = n
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
n = self.n
|
||||
self.y = [None] * n # Where is the queen in column x
|
||||
self.row = [0] * n # Is row[y] safe?
|
||||
self.up = [0] * (2*n-1) # Is upward diagonal[x-y] safe?
|
||||
self.down = [0] * (2*n-1) # Is downward diagonal[x+y] safe?
|
||||
self.nfound = 0 # Instrumentation
|
||||
|
||||
def solve(self, x=0): # Recursive solver
|
||||
for y in range(self.n):
|
||||
if self.safe(x, y):
|
||||
self.place(x, y)
|
||||
if x+1 == self.n:
|
||||
self.display()
|
||||
else:
|
||||
self.solve(x+1)
|
||||
self.remove(x, y)
|
||||
|
||||
def safe(self, x, y):
|
||||
return not self.row[y] and not self.up[x-y] and not self.down[x+y]
|
||||
|
||||
def place(self, x, y):
|
||||
self.y[x] = y
|
||||
self.row[y] = 1
|
||||
self.up[x-y] = 1
|
||||
self.down[x+y] = 1
|
||||
|
||||
def remove(self, x, y):
|
||||
self.y[x] = None
|
||||
self.row[y] = 0
|
||||
self.up[x-y] = 0
|
||||
self.down[x+y] = 0
|
||||
|
||||
silent = 0 # If true, count solutions only
|
||||
|
||||
def display(self):
|
||||
self.nfound = self.nfound + 1
|
||||
if self.silent:
|
||||
return
|
||||
print('+-' + '--'*self.n + '+')
|
||||
for y in range(self.n-1, -1, -1):
|
||||
print('|', end=' ')
|
||||
for x in range(self.n):
|
||||
if self.y[x] == y:
|
||||
print("Q", end=' ')
|
||||
else:
|
||||
print(".", end=' ')
|
||||
print('|')
|
||||
print('+-' + '--'*self.n + '+')
|
||||
|
||||
def main():
|
||||
import sys
|
||||
silent = 0
|
||||
n = N
|
||||
if sys.argv[1:2] == ['-n']:
|
||||
silent = 1
|
||||
del sys.argv[1]
|
||||
if sys.argv[1:]:
|
||||
n = int(sys.argv[1])
|
||||
q = Queens(n)
|
||||
q.silent = silent
|
||||
q.solve()
|
||||
print("Found", q.nfound, "solutions.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
171
.CondaPkg/env/Tools/demo/redemo.py
vendored
Normal file
171
.CondaPkg/env/Tools/demo/redemo.py
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""Basic regular expression demonstration facility (Perl style syntax)."""
|
||||
|
||||
from tkinter import *
|
||||
import re
|
||||
|
||||
class ReDemo:
|
||||
|
||||
def __init__(self, master):
|
||||
self.master = master
|
||||
|
||||
self.promptdisplay = Label(self.master, anchor=W,
|
||||
text="Enter a Perl-style regular expression:")
|
||||
self.promptdisplay.pack(side=TOP, fill=X)
|
||||
|
||||
self.regexdisplay = Entry(self.master)
|
||||
self.regexdisplay.pack(fill=X)
|
||||
self.regexdisplay.focus_set()
|
||||
|
||||
self.addoptions()
|
||||
|
||||
self.statusdisplay = Label(self.master, text="", anchor=W)
|
||||
self.statusdisplay.pack(side=TOP, fill=X)
|
||||
|
||||
self.labeldisplay = Label(self.master, anchor=W,
|
||||
text="Enter a string to search:")
|
||||
self.labeldisplay.pack(fill=X)
|
||||
self.labeldisplay.pack(fill=X)
|
||||
|
||||
self.showframe = Frame(master)
|
||||
self.showframe.pack(fill=X, anchor=W)
|
||||
|
||||
self.showvar = StringVar(master)
|
||||
self.showvar.set("first")
|
||||
|
||||
self.showfirstradio = Radiobutton(self.showframe,
|
||||
text="Highlight first match",
|
||||
variable=self.showvar,
|
||||
value="first",
|
||||
command=self.recompile)
|
||||
self.showfirstradio.pack(side=LEFT)
|
||||
|
||||
self.showallradio = Radiobutton(self.showframe,
|
||||
text="Highlight all matches",
|
||||
variable=self.showvar,
|
||||
value="all",
|
||||
command=self.recompile)
|
||||
self.showallradio.pack(side=LEFT)
|
||||
|
||||
self.stringdisplay = Text(self.master, width=60, height=4)
|
||||
self.stringdisplay.pack(fill=BOTH, expand=1)
|
||||
self.stringdisplay.tag_configure("hit", background="yellow")
|
||||
|
||||
self.grouplabel = Label(self.master, text="Groups:", anchor=W)
|
||||
self.grouplabel.pack(fill=X)
|
||||
|
||||
self.grouplist = Listbox(self.master)
|
||||
self.grouplist.pack(expand=1, fill=BOTH)
|
||||
|
||||
self.regexdisplay.bind('<Key>', self.recompile)
|
||||
self.stringdisplay.bind('<Key>', self.reevaluate)
|
||||
|
||||
self.compiled = None
|
||||
self.recompile()
|
||||
|
||||
btags = self.regexdisplay.bindtags()
|
||||
self.regexdisplay.bindtags(btags[1:] + btags[:1])
|
||||
|
||||
btags = self.stringdisplay.bindtags()
|
||||
self.stringdisplay.bindtags(btags[1:] + btags[:1])
|
||||
|
||||
def addoptions(self):
|
||||
self.frames = []
|
||||
self.boxes = []
|
||||
self.vars = []
|
||||
for name in ('IGNORECASE',
|
||||
'MULTILINE',
|
||||
'DOTALL',
|
||||
'VERBOSE'):
|
||||
if len(self.boxes) % 3 == 0:
|
||||
frame = Frame(self.master)
|
||||
frame.pack(fill=X)
|
||||
self.frames.append(frame)
|
||||
val = getattr(re, name).value
|
||||
var = IntVar()
|
||||
box = Checkbutton(frame,
|
||||
variable=var, text=name,
|
||||
offvalue=0, onvalue=val,
|
||||
command=self.recompile)
|
||||
box.pack(side=LEFT)
|
||||
self.boxes.append(box)
|
||||
self.vars.append(var)
|
||||
|
||||
def getflags(self):
|
||||
flags = 0
|
||||
for var in self.vars:
|
||||
flags = flags | var.get()
|
||||
return flags
|
||||
|
||||
def recompile(self, event=None):
|
||||
try:
|
||||
self.compiled = re.compile(self.regexdisplay.get(),
|
||||
self.getflags())
|
||||
bg = self.promptdisplay['background']
|
||||
self.statusdisplay.config(text="", background=bg)
|
||||
except re.error as msg:
|
||||
self.compiled = None
|
||||
self.statusdisplay.config(
|
||||
text="re.error: %s" % str(msg),
|
||||
background="red")
|
||||
self.reevaluate()
|
||||
|
||||
def reevaluate(self, event=None):
|
||||
try:
|
||||
self.stringdisplay.tag_remove("hit", "1.0", END)
|
||||
except TclError:
|
||||
pass
|
||||
try:
|
||||
self.stringdisplay.tag_remove("hit0", "1.0", END)
|
||||
except TclError:
|
||||
pass
|
||||
self.grouplist.delete(0, END)
|
||||
if not self.compiled:
|
||||
return
|
||||
self.stringdisplay.tag_configure("hit", background="yellow")
|
||||
self.stringdisplay.tag_configure("hit0", background="orange")
|
||||
text = self.stringdisplay.get("1.0", END)
|
||||
last = 0
|
||||
nmatches = 0
|
||||
while last <= len(text):
|
||||
m = self.compiled.search(text, last)
|
||||
if m is None:
|
||||
break
|
||||
first, last = m.span()
|
||||
if last == first:
|
||||
last = first+1
|
||||
tag = "hit0"
|
||||
else:
|
||||
tag = "hit"
|
||||
pfirst = "1.0 + %d chars" % first
|
||||
plast = "1.0 + %d chars" % last
|
||||
self.stringdisplay.tag_add(tag, pfirst, plast)
|
||||
if nmatches == 0:
|
||||
self.stringdisplay.yview_pickplace(pfirst)
|
||||
groups = list(m.groups())
|
||||
groups.insert(0, m.group())
|
||||
for i in range(len(groups)):
|
||||
g = "%2d: %r" % (i, groups[i])
|
||||
self.grouplist.insert(END, g)
|
||||
nmatches = nmatches + 1
|
||||
if self.showvar.get() == "first":
|
||||
break
|
||||
|
||||
if nmatches == 0:
|
||||
self.statusdisplay.config(text="(no match)",
|
||||
background="yellow")
|
||||
else:
|
||||
self.statusdisplay.config(text="")
|
||||
|
||||
|
||||
# Main function, run when invoked as a stand-alone Python program.
|
||||
|
||||
def main():
|
||||
root = Tk()
|
||||
demo = ReDemo(root)
|
||||
root.protocol('WM_DELETE_WINDOW', root.quit)
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
37
.CondaPkg/env/Tools/demo/rpython.py
vendored
Normal file
37
.CondaPkg/env/Tools/demo/rpython.py
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Remote python client.
|
||||
Execute Python commands remotely and send output back.
|
||||
"""
|
||||
|
||||
import sys
|
||||
from socket import socket, AF_INET, SOCK_STREAM, SHUT_WR
|
||||
|
||||
PORT = 4127
|
||||
BUFSIZE = 1024
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 3:
|
||||
print("usage: rpython host command")
|
||||
sys.exit(2)
|
||||
host = sys.argv[1]
|
||||
port = PORT
|
||||
i = host.find(':')
|
||||
if i >= 0:
|
||||
port = int(host[i+1:])
|
||||
host = host[:i]
|
||||
command = ' '.join(sys.argv[2:])
|
||||
with socket(AF_INET, SOCK_STREAM) as s:
|
||||
s.connect((host, port))
|
||||
s.send(command.encode())
|
||||
s.shutdown(SHUT_WR)
|
||||
reply = b''
|
||||
while True:
|
||||
data = s.recv(BUFSIZE)
|
||||
if not data:
|
||||
break
|
||||
reply += data
|
||||
print(reply.decode(), end=' ')
|
||||
|
||||
main()
|
||||
58
.CondaPkg/env/Tools/demo/rpythond.py
vendored
Normal file
58
.CondaPkg/env/Tools/demo/rpythond.py
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Remote python server.
|
||||
Execute Python commands remotely and send output back.
|
||||
|
||||
WARNING: This version has a gaping security hole -- it accepts requests
|
||||
from any host on the internet!
|
||||
"""
|
||||
|
||||
import sys
|
||||
from socket import socket, AF_INET, SOCK_STREAM
|
||||
import io
|
||||
import traceback
|
||||
|
||||
PORT = 4127
|
||||
BUFSIZE = 1024
|
||||
|
||||
def main():
|
||||
if len(sys.argv) > 1:
|
||||
port = int(sys.argv[1])
|
||||
else:
|
||||
port = PORT
|
||||
s = socket(AF_INET, SOCK_STREAM)
|
||||
s.bind(('', port))
|
||||
s.listen(1)
|
||||
while True:
|
||||
conn, (remotehost, remoteport) = s.accept()
|
||||
with conn:
|
||||
print('connection from', remotehost, remoteport)
|
||||
request = b''
|
||||
while True:
|
||||
data = conn.recv(BUFSIZE)
|
||||
if not data:
|
||||
break
|
||||
request += data
|
||||
reply = execute(request.decode())
|
||||
conn.send(reply.encode())
|
||||
|
||||
def execute(request):
|
||||
stdout = sys.stdout
|
||||
stderr = sys.stderr
|
||||
sys.stdout = sys.stderr = fakefile = io.StringIO()
|
||||
try:
|
||||
try:
|
||||
exec(request, {}, {})
|
||||
except:
|
||||
print()
|
||||
traceback.print_exc(100)
|
||||
finally:
|
||||
sys.stderr = stderr
|
||||
sys.stdout = stdout
|
||||
return fakefile.getvalue()
|
||||
|
||||
try:
|
||||
main()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
635
.CondaPkg/env/Tools/demo/sortvisu.py
vendored
Normal file
635
.CondaPkg/env/Tools/demo/sortvisu.py
vendored
Normal file
@@ -0,0 +1,635 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Sorting algorithms visualizer using Tkinter.
|
||||
|
||||
This module is comprised of three ``components'':
|
||||
|
||||
- an array visualizer with methods that implement basic sorting
|
||||
operations (compare, swap) as well as methods for ``annotating'' the
|
||||
sorting algorithm (e.g. to show the pivot element);
|
||||
|
||||
- a number of sorting algorithms (currently quicksort, insertion sort,
|
||||
selection sort and bubble sort, as well as a randomization function),
|
||||
all using the array visualizer for its basic operations and with calls
|
||||
to its annotation methods;
|
||||
|
||||
- and a ``driver'' class which can be used as a Grail applet or as a
|
||||
stand-alone application.
|
||||
"""
|
||||
|
||||
from tkinter import *
|
||||
import random
|
||||
|
||||
XGRID = 10
|
||||
YGRID = 10
|
||||
WIDTH = 6
|
||||
|
||||
|
||||
class Array:
|
||||
|
||||
class Cancelled(BaseException):
|
||||
pass
|
||||
|
||||
def __init__(self, master, data=None):
|
||||
self.master = master
|
||||
self.frame = Frame(self.master)
|
||||
self.frame.pack(fill=X)
|
||||
self.label = Label(self.frame)
|
||||
self.label.pack()
|
||||
self.canvas = Canvas(self.frame)
|
||||
self.canvas.pack()
|
||||
self.report = Label(self.frame)
|
||||
self.report.pack()
|
||||
self.left = self.canvas.create_line(0, 0, 0, 0)
|
||||
self.right = self.canvas.create_line(0, 0, 0, 0)
|
||||
self.pivot = self.canvas.create_line(0, 0, 0, 0)
|
||||
self.items = []
|
||||
self.size = self.maxvalue = 0
|
||||
if data:
|
||||
self.setdata(data)
|
||||
|
||||
def setdata(self, data):
|
||||
olditems = self.items
|
||||
self.items = []
|
||||
for item in olditems:
|
||||
item.delete()
|
||||
self.size = len(data)
|
||||
self.maxvalue = max(data)
|
||||
self.canvas.config(width=(self.size+1)*XGRID,
|
||||
height=(self.maxvalue+1)*YGRID)
|
||||
for i in range(self.size):
|
||||
self.items.append(ArrayItem(self, i, data[i]))
|
||||
self.reset("Sort demo, size %d" % self.size)
|
||||
|
||||
speed = "normal"
|
||||
|
||||
def setspeed(self, speed):
|
||||
self.speed = speed
|
||||
|
||||
def destroy(self):
|
||||
self.frame.destroy()
|
||||
|
||||
in_mainloop = 0
|
||||
stop_mainloop = 0
|
||||
|
||||
def cancel(self):
|
||||
self.stop_mainloop = 1
|
||||
if self.in_mainloop:
|
||||
self.master.quit()
|
||||
|
||||
def step(self):
|
||||
if self.in_mainloop:
|
||||
self.master.quit()
|
||||
|
||||
def wait(self, msecs):
|
||||
if self.speed == "fastest":
|
||||
msecs = 0
|
||||
elif self.speed == "fast":
|
||||
msecs = msecs//10
|
||||
elif self.speed == "single-step":
|
||||
msecs = 1000000000
|
||||
if not self.stop_mainloop:
|
||||
self.master.update()
|
||||
id = self.master.after(msecs, self.master.quit)
|
||||
self.in_mainloop = 1
|
||||
self.master.mainloop()
|
||||
self.master.after_cancel(id)
|
||||
self.in_mainloop = 0
|
||||
if self.stop_mainloop:
|
||||
self.stop_mainloop = 0
|
||||
self.message("Cancelled")
|
||||
raise Array.Cancelled
|
||||
|
||||
def getsize(self):
|
||||
return self.size
|
||||
|
||||
def show_partition(self, first, last):
|
||||
for i in range(self.size):
|
||||
item = self.items[i]
|
||||
if first <= i < last:
|
||||
self.canvas.itemconfig(item, fill='red')
|
||||
else:
|
||||
self.canvas.itemconfig(item, fill='orange')
|
||||
self.hide_left_right_pivot()
|
||||
|
||||
def hide_partition(self):
|
||||
for i in range(self.size):
|
||||
item = self.items[i]
|
||||
self.canvas.itemconfig(item, fill='red')
|
||||
self.hide_left_right_pivot()
|
||||
|
||||
def show_left(self, left):
|
||||
if not 0 <= left < self.size:
|
||||
self.hide_left()
|
||||
return
|
||||
x1, y1, x2, y2 = self.items[left].position()
|
||||
## top, bot = HIRO
|
||||
self.canvas.coords(self.left, (x1 - 2, 0, x1 - 2, 9999))
|
||||
self.master.update()
|
||||
|
||||
def show_right(self, right):
|
||||
if not 0 <= right < self.size:
|
||||
self.hide_right()
|
||||
return
|
||||
x1, y1, x2, y2 = self.items[right].position()
|
||||
self.canvas.coords(self.right, (x2 + 2, 0, x2 + 2, 9999))
|
||||
self.master.update()
|
||||
|
||||
def hide_left_right_pivot(self):
|
||||
self.hide_left()
|
||||
self.hide_right()
|
||||
self.hide_pivot()
|
||||
|
||||
def hide_left(self):
|
||||
self.canvas.coords(self.left, (0, 0, 0, 0))
|
||||
|
||||
def hide_right(self):
|
||||
self.canvas.coords(self.right, (0, 0, 0, 0))
|
||||
|
||||
def show_pivot(self, pivot):
|
||||
x1, y1, x2, y2 = self.items[pivot].position()
|
||||
self.canvas.coords(self.pivot, (0, y1 - 2, 9999, y1 - 2))
|
||||
|
||||
def hide_pivot(self):
|
||||
self.canvas.coords(self.pivot, (0, 0, 0, 0))
|
||||
|
||||
def swap(self, i, j):
|
||||
if i == j: return
|
||||
self.countswap()
|
||||
item = self.items[i]
|
||||
other = self.items[j]
|
||||
self.items[i], self.items[j] = other, item
|
||||
item.swapwith(other)
|
||||
|
||||
def compare(self, i, j):
|
||||
self.countcompare()
|
||||
item = self.items[i]
|
||||
other = self.items[j]
|
||||
return item.compareto(other)
|
||||
|
||||
def reset(self, msg):
|
||||
self.ncompares = 0
|
||||
self.nswaps = 0
|
||||
self.message(msg)
|
||||
self.updatereport()
|
||||
self.hide_partition()
|
||||
|
||||
def message(self, msg):
|
||||
self.label.config(text=msg)
|
||||
|
||||
def countswap(self):
|
||||
self.nswaps = self.nswaps + 1
|
||||
self.updatereport()
|
||||
|
||||
def countcompare(self):
|
||||
self.ncompares = self.ncompares + 1
|
||||
self.updatereport()
|
||||
|
||||
def updatereport(self):
|
||||
text = "%d cmps, %d swaps" % (self.ncompares, self.nswaps)
|
||||
self.report.config(text=text)
|
||||
|
||||
|
||||
class ArrayItem:
|
||||
|
||||
def __init__(self, array, index, value):
|
||||
self.array = array
|
||||
self.index = index
|
||||
self.value = value
|
||||
self.canvas = array.canvas
|
||||
x1, y1, x2, y2 = self.position()
|
||||
self.item_id = array.canvas.create_rectangle(x1, y1, x2, y2,
|
||||
fill='red', outline='black', width=1)
|
||||
self.canvas.tag_bind(self.item_id, '<Button-1>', self.mouse_down)
|
||||
self.canvas.tag_bind(self.item_id, '<Button1-Motion>', self.mouse_move)
|
||||
self.canvas.tag_bind(self.item_id, '<ButtonRelease-1>', self.mouse_up)
|
||||
|
||||
def delete(self):
|
||||
item_id = self.item_id
|
||||
self.array = None
|
||||
self.item_id = None
|
||||
self.canvas.delete(item_id)
|
||||
|
||||
def mouse_down(self, event):
|
||||
self.lastx = event.x
|
||||
self.lasty = event.y
|
||||
self.origx = event.x
|
||||
self.origy = event.y
|
||||
self.canvas.tag_raise(self.item_id)
|
||||
|
||||
def mouse_move(self, event):
|
||||
self.canvas.move(self.item_id,
|
||||
event.x - self.lastx, event.y - self.lasty)
|
||||
self.lastx = event.x
|
||||
self.lasty = event.y
|
||||
|
||||
def mouse_up(self, event):
|
||||
i = self.nearestindex(event.x)
|
||||
if i >= self.array.getsize():
|
||||
i = self.array.getsize() - 1
|
||||
if i < 0:
|
||||
i = 0
|
||||
other = self.array.items[i]
|
||||
here = self.index
|
||||
self.array.items[here], self.array.items[i] = other, self
|
||||
self.index = i
|
||||
x1, y1, x2, y2 = self.position()
|
||||
self.canvas.coords(self.item_id, (x1, y1, x2, y2))
|
||||
other.setindex(here)
|
||||
|
||||
def setindex(self, index):
|
||||
nsteps = steps(self.index, index)
|
||||
if not nsteps: return
|
||||
if self.array.speed == "fastest":
|
||||
nsteps = 0
|
||||
oldpts = self.position()
|
||||
self.index = index
|
||||
newpts = self.position()
|
||||
trajectory = interpolate(oldpts, newpts, nsteps)
|
||||
self.canvas.tag_raise(self.item_id)
|
||||
for pts in trajectory:
|
||||
self.canvas.coords(self.item_id, pts)
|
||||
self.array.wait(50)
|
||||
|
||||
def swapwith(self, other):
|
||||
nsteps = steps(self.index, other.index)
|
||||
if not nsteps: return
|
||||
if self.array.speed == "fastest":
|
||||
nsteps = 0
|
||||
myoldpts = self.position()
|
||||
otheroldpts = other.position()
|
||||
self.index, other.index = other.index, self.index
|
||||
mynewpts = self.position()
|
||||
othernewpts = other.position()
|
||||
myfill = self.canvas.itemcget(self.item_id, 'fill')
|
||||
otherfill = self.canvas.itemcget(other.item_id, 'fill')
|
||||
self.canvas.itemconfig(self.item_id, fill='green')
|
||||
self.canvas.itemconfig(other.item_id, fill='yellow')
|
||||
self.array.master.update()
|
||||
if self.array.speed == "single-step":
|
||||
self.canvas.coords(self.item_id, mynewpts)
|
||||
self.canvas.coords(other.item_id, othernewpts)
|
||||
self.array.master.update()
|
||||
self.canvas.itemconfig(self.item_id, fill=myfill)
|
||||
self.canvas.itemconfig(other.item_id, fill=otherfill)
|
||||
self.array.wait(0)
|
||||
return
|
||||
mytrajectory = interpolate(myoldpts, mynewpts, nsteps)
|
||||
othertrajectory = interpolate(otheroldpts, othernewpts, nsteps)
|
||||
if self.value > other.value:
|
||||
self.canvas.tag_raise(self.item_id)
|
||||
self.canvas.tag_raise(other.item_id)
|
||||
else:
|
||||
self.canvas.tag_raise(other.item_id)
|
||||
self.canvas.tag_raise(self.item_id)
|
||||
try:
|
||||
for i in range(len(mytrajectory)):
|
||||
mypts = mytrajectory[i]
|
||||
otherpts = othertrajectory[i]
|
||||
self.canvas.coords(self.item_id, mypts)
|
||||
self.canvas.coords(other.item_id, otherpts)
|
||||
self.array.wait(50)
|
||||
finally:
|
||||
mypts = mytrajectory[-1]
|
||||
otherpts = othertrajectory[-1]
|
||||
self.canvas.coords(self.item_id, mypts)
|
||||
self.canvas.coords(other.item_id, otherpts)
|
||||
self.canvas.itemconfig(self.item_id, fill=myfill)
|
||||
self.canvas.itemconfig(other.item_id, fill=otherfill)
|
||||
|
||||
def compareto(self, other):
|
||||
myfill = self.canvas.itemcget(self.item_id, 'fill')
|
||||
otherfill = self.canvas.itemcget(other.item_id, 'fill')
|
||||
if self.value < other.value:
|
||||
myflash = 'white'
|
||||
otherflash = 'black'
|
||||
outcome = -1
|
||||
elif self.value > other.value:
|
||||
myflash = 'black'
|
||||
otherflash = 'white'
|
||||
outcome = 1
|
||||
else:
|
||||
myflash = otherflash = 'grey'
|
||||
outcome = 0
|
||||
try:
|
||||
self.canvas.itemconfig(self.item_id, fill=myflash)
|
||||
self.canvas.itemconfig(other.item_id, fill=otherflash)
|
||||
self.array.wait(500)
|
||||
finally:
|
||||
self.canvas.itemconfig(self.item_id, fill=myfill)
|
||||
self.canvas.itemconfig(other.item_id, fill=otherfill)
|
||||
return outcome
|
||||
|
||||
def position(self):
|
||||
x1 = (self.index+1)*XGRID - WIDTH//2
|
||||
x2 = x1+WIDTH
|
||||
y2 = (self.array.maxvalue+1)*YGRID
|
||||
y1 = y2 - (self.value)*YGRID
|
||||
return x1, y1, x2, y2
|
||||
|
||||
def nearestindex(self, x):
|
||||
return int(round(float(x)/XGRID)) - 1
|
||||
|
||||
|
||||
# Subroutines that don't need an object
|
||||
|
||||
def steps(here, there):
|
||||
nsteps = abs(here - there)
|
||||
if nsteps <= 3:
|
||||
nsteps = nsteps * 3
|
||||
elif nsteps <= 5:
|
||||
nsteps = nsteps * 2
|
||||
elif nsteps > 10:
|
||||
nsteps = 10
|
||||
return nsteps
|
||||
|
||||
def interpolate(oldpts, newpts, n):
|
||||
if len(oldpts) != len(newpts):
|
||||
raise ValueError("can't interpolate arrays of different length")
|
||||
pts = [0]*len(oldpts)
|
||||
res = [tuple(oldpts)]
|
||||
for i in range(1, n):
|
||||
for k in range(len(pts)):
|
||||
pts[k] = oldpts[k] + (newpts[k] - oldpts[k])*i//n
|
||||
res.append(tuple(pts))
|
||||
res.append(tuple(newpts))
|
||||
return res
|
||||
|
||||
|
||||
# Various (un)sorting algorithms
|
||||
|
||||
def uniform(array):
|
||||
size = array.getsize()
|
||||
array.setdata([(size+1)//2] * size)
|
||||
array.reset("Uniform data, size %d" % size)
|
||||
|
||||
def distinct(array):
|
||||
size = array.getsize()
|
||||
array.setdata(range(1, size+1))
|
||||
array.reset("Distinct data, size %d" % size)
|
||||
|
||||
def randomize(array):
|
||||
array.reset("Randomizing")
|
||||
n = array.getsize()
|
||||
for i in range(n):
|
||||
j = random.randint(0, n-1)
|
||||
array.swap(i, j)
|
||||
array.message("Randomized")
|
||||
|
||||
def insertionsort(array):
|
||||
size = array.getsize()
|
||||
array.reset("Insertion sort")
|
||||
for i in range(1, size):
|
||||
j = i-1
|
||||
while j >= 0:
|
||||
if array.compare(j, j+1) <= 0:
|
||||
break
|
||||
array.swap(j, j+1)
|
||||
j = j-1
|
||||
array.message("Sorted")
|
||||
|
||||
def selectionsort(array):
|
||||
size = array.getsize()
|
||||
array.reset("Selection sort")
|
||||
try:
|
||||
for i in range(size):
|
||||
array.show_partition(i, size)
|
||||
for j in range(i+1, size):
|
||||
if array.compare(i, j) > 0:
|
||||
array.swap(i, j)
|
||||
array.message("Sorted")
|
||||
finally:
|
||||
array.hide_partition()
|
||||
|
||||
def bubblesort(array):
|
||||
size = array.getsize()
|
||||
array.reset("Bubble sort")
|
||||
for i in range(size):
|
||||
for j in range(1, size):
|
||||
if array.compare(j-1, j) > 0:
|
||||
array.swap(j-1, j)
|
||||
array.message("Sorted")
|
||||
|
||||
def quicksort(array):
|
||||
size = array.getsize()
|
||||
array.reset("Quicksort")
|
||||
try:
|
||||
stack = [(0, size)]
|
||||
while stack:
|
||||
first, last = stack[-1]
|
||||
del stack[-1]
|
||||
array.show_partition(first, last)
|
||||
if last-first < 5:
|
||||
array.message("Insertion sort")
|
||||
for i in range(first+1, last):
|
||||
j = i-1
|
||||
while j >= first:
|
||||
if array.compare(j, j+1) <= 0:
|
||||
break
|
||||
array.swap(j, j+1)
|
||||
j = j-1
|
||||
continue
|
||||
array.message("Choosing pivot")
|
||||
j, i, k = first, (first+last) // 2, last-1
|
||||
if array.compare(k, i) < 0:
|
||||
array.swap(k, i)
|
||||
if array.compare(k, j) < 0:
|
||||
array.swap(k, j)
|
||||
if array.compare(j, i) < 0:
|
||||
array.swap(j, i)
|
||||
pivot = j
|
||||
array.show_pivot(pivot)
|
||||
array.message("Pivot at left of partition")
|
||||
array.wait(1000)
|
||||
left = first
|
||||
right = last
|
||||
while True:
|
||||
array.message("Sweep right pointer")
|
||||
right = right-1
|
||||
array.show_right(right)
|
||||
while right > first and array.compare(right, pivot) >= 0:
|
||||
right = right-1
|
||||
array.show_right(right)
|
||||
array.message("Sweep left pointer")
|
||||
left = left+1
|
||||
array.show_left(left)
|
||||
while left < last and array.compare(left, pivot) <= 0:
|
||||
left = left+1
|
||||
array.show_left(left)
|
||||
if left > right:
|
||||
array.message("End of partition")
|
||||
break
|
||||
array.message("Swap items")
|
||||
array.swap(left, right)
|
||||
array.message("Swap pivot back")
|
||||
array.swap(pivot, right)
|
||||
n1 = right-first
|
||||
n2 = last-left
|
||||
if n1 > 1: stack.append((first, right))
|
||||
if n2 > 1: stack.append((left, last))
|
||||
array.message("Sorted")
|
||||
finally:
|
||||
array.hide_partition()
|
||||
|
||||
def demosort(array):
|
||||
while True:
|
||||
for alg in [quicksort, insertionsort, selectionsort, bubblesort]:
|
||||
randomize(array)
|
||||
alg(array)
|
||||
|
||||
|
||||
# Sort demo class -- usable as a Grail applet
|
||||
|
||||
class SortDemo:
|
||||
|
||||
def __init__(self, master, size=15):
|
||||
self.master = master
|
||||
self.size = size
|
||||
self.busy = 0
|
||||
self.array = Array(self.master)
|
||||
|
||||
self.botframe = Frame(master)
|
||||
self.botframe.pack(side=BOTTOM)
|
||||
self.botleftframe = Frame(self.botframe)
|
||||
self.botleftframe.pack(side=LEFT, fill=Y)
|
||||
self.botrightframe = Frame(self.botframe)
|
||||
self.botrightframe.pack(side=RIGHT, fill=Y)
|
||||
|
||||
self.b_qsort = Button(self.botleftframe,
|
||||
text="Quicksort", command=self.c_qsort)
|
||||
self.b_qsort.pack(fill=X)
|
||||
self.b_isort = Button(self.botleftframe,
|
||||
text="Insertion sort", command=self.c_isort)
|
||||
self.b_isort.pack(fill=X)
|
||||
self.b_ssort = Button(self.botleftframe,
|
||||
text="Selection sort", command=self.c_ssort)
|
||||
self.b_ssort.pack(fill=X)
|
||||
self.b_bsort = Button(self.botleftframe,
|
||||
text="Bubble sort", command=self.c_bsort)
|
||||
self.b_bsort.pack(fill=X)
|
||||
|
||||
# Terrible hack to overcome limitation of OptionMenu...
|
||||
class MyIntVar(IntVar):
|
||||
def __init__(self, master, demo):
|
||||
self.demo = demo
|
||||
IntVar.__init__(self, master)
|
||||
def set(self, value):
|
||||
IntVar.set(self, value)
|
||||
if str(value) != '0':
|
||||
self.demo.resize(value)
|
||||
|
||||
self.v_size = MyIntVar(self.master, self)
|
||||
self.v_size.set(size)
|
||||
sizes = [1, 2, 3, 4] + list(range(5, 55, 5))
|
||||
if self.size not in sizes:
|
||||
sizes.append(self.size)
|
||||
sizes.sort()
|
||||
self.m_size = OptionMenu(self.botleftframe, self.v_size, *sizes)
|
||||
self.m_size.pack(fill=X)
|
||||
|
||||
self.v_speed = StringVar(self.master)
|
||||
self.v_speed.set("normal")
|
||||
self.m_speed = OptionMenu(self.botleftframe, self.v_speed,
|
||||
"single-step", "normal", "fast", "fastest")
|
||||
self.m_speed.pack(fill=X)
|
||||
|
||||
self.b_step = Button(self.botleftframe,
|
||||
text="Step", command=self.c_step)
|
||||
self.b_step.pack(fill=X)
|
||||
|
||||
self.b_randomize = Button(self.botrightframe,
|
||||
text="Randomize", command=self.c_randomize)
|
||||
self.b_randomize.pack(fill=X)
|
||||
self.b_uniform = Button(self.botrightframe,
|
||||
text="Uniform", command=self.c_uniform)
|
||||
self.b_uniform.pack(fill=X)
|
||||
self.b_distinct = Button(self.botrightframe,
|
||||
text="Distinct", command=self.c_distinct)
|
||||
self.b_distinct.pack(fill=X)
|
||||
self.b_demo = Button(self.botrightframe,
|
||||
text="Demo", command=self.c_demo)
|
||||
self.b_demo.pack(fill=X)
|
||||
self.b_cancel = Button(self.botrightframe,
|
||||
text="Cancel", command=self.c_cancel)
|
||||
self.b_cancel.pack(fill=X)
|
||||
self.b_cancel.config(state=DISABLED)
|
||||
self.b_quit = Button(self.botrightframe,
|
||||
text="Quit", command=self.c_quit)
|
||||
self.b_quit.pack(fill=X)
|
||||
|
||||
def resize(self, newsize):
|
||||
if self.busy:
|
||||
self.master.bell()
|
||||
return
|
||||
self.size = newsize
|
||||
self.array.setdata(range(1, self.size+1))
|
||||
|
||||
def c_qsort(self):
|
||||
self.run(quicksort)
|
||||
|
||||
def c_isort(self):
|
||||
self.run(insertionsort)
|
||||
|
||||
def c_ssort(self):
|
||||
self.run(selectionsort)
|
||||
|
||||
def c_bsort(self):
|
||||
self.run(bubblesort)
|
||||
|
||||
def c_demo(self):
|
||||
self.run(demosort)
|
||||
|
||||
def c_randomize(self):
|
||||
self.run(randomize)
|
||||
|
||||
def c_uniform(self):
|
||||
self.run(uniform)
|
||||
|
||||
def c_distinct(self):
|
||||
self.run(distinct)
|
||||
|
||||
def run(self, func):
|
||||
if self.busy:
|
||||
self.master.bell()
|
||||
return
|
||||
self.busy = 1
|
||||
self.array.setspeed(self.v_speed.get())
|
||||
self.b_cancel.config(state=NORMAL)
|
||||
try:
|
||||
func(self.array)
|
||||
except Array.Cancelled:
|
||||
pass
|
||||
self.b_cancel.config(state=DISABLED)
|
||||
self.busy = 0
|
||||
|
||||
def c_cancel(self):
|
||||
if not self.busy:
|
||||
self.master.bell()
|
||||
return
|
||||
self.array.cancel()
|
||||
|
||||
def c_step(self):
|
||||
if not self.busy:
|
||||
self.master.bell()
|
||||
return
|
||||
self.v_speed.set("single-step")
|
||||
self.array.setspeed("single-step")
|
||||
self.array.step()
|
||||
|
||||
def c_quit(self):
|
||||
if self.busy:
|
||||
self.array.cancel()
|
||||
self.master.after_idle(self.master.quit)
|
||||
|
||||
|
||||
# Main program -- for stand-alone operation outside Grail
|
||||
|
||||
def main():
|
||||
root = Tk()
|
||||
demo = SortDemo(root)
|
||||
root.protocol('WM_DELETE_WINDOW', demo.c_quit)
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
829
.CondaPkg/env/Tools/demo/spreadsheet.py
vendored
Normal file
829
.CondaPkg/env/Tools/demo/spreadsheet.py
vendored
Normal file
@@ -0,0 +1,829 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
SS1 -- a spreadsheet-like application.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from xml.parsers import expat
|
||||
from xml.sax.saxutils import escape
|
||||
|
||||
LEFT, CENTER, RIGHT = "LEFT", "CENTER", "RIGHT"
|
||||
|
||||
def ljust(x, n):
|
||||
return x.ljust(n)
|
||||
def center(x, n):
|
||||
return x.center(n)
|
||||
def rjust(x, n):
|
||||
return x.rjust(n)
|
||||
align2action = {LEFT: ljust, CENTER: center, RIGHT: rjust}
|
||||
|
||||
align2xml = {LEFT: "left", CENTER: "center", RIGHT: "right"}
|
||||
xml2align = {"left": LEFT, "center": CENTER, "right": RIGHT}
|
||||
|
||||
align2anchor = {LEFT: "w", CENTER: "center", RIGHT: "e"}
|
||||
|
||||
def sum(seq):
|
||||
total = 0
|
||||
for x in seq:
|
||||
if x is not None:
|
||||
total += x
|
||||
return total
|
||||
|
||||
class Sheet:
|
||||
|
||||
def __init__(self):
|
||||
self.cells = {} # {(x, y): cell, ...}
|
||||
self.ns = dict(
|
||||
cell = self.cellvalue,
|
||||
cells = self.multicellvalue,
|
||||
sum = sum,
|
||||
)
|
||||
|
||||
def cellvalue(self, x, y):
|
||||
cell = self.getcell(x, y)
|
||||
if hasattr(cell, 'recalc'):
|
||||
return cell.recalc(self.ns)
|
||||
else:
|
||||
return cell
|
||||
|
||||
def multicellvalue(self, x1, y1, x2, y2):
|
||||
if x1 > x2:
|
||||
x1, x2 = x2, x1
|
||||
if y1 > y2:
|
||||
y1, y2 = y2, y1
|
||||
seq = []
|
||||
for y in range(y1, y2+1):
|
||||
for x in range(x1, x2+1):
|
||||
seq.append(self.cellvalue(x, y))
|
||||
return seq
|
||||
|
||||
def getcell(self, x, y):
|
||||
return self.cells.get((x, y))
|
||||
|
||||
def setcell(self, x, y, cell):
|
||||
assert x > 0 and y > 0
|
||||
assert isinstance(cell, BaseCell)
|
||||
self.cells[x, y] = cell
|
||||
|
||||
def clearcell(self, x, y):
|
||||
try:
|
||||
del self.cells[x, y]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def clearcells(self, x1, y1, x2, y2):
|
||||
for xy in self.selectcells(x1, y1, x2, y2):
|
||||
del self.cells[xy]
|
||||
|
||||
def clearrows(self, y1, y2):
|
||||
self.clearcells(0, y1, sys.maxsize, y2)
|
||||
|
||||
def clearcolumns(self, x1, x2):
|
||||
self.clearcells(x1, 0, x2, sys.maxsize)
|
||||
|
||||
def selectcells(self, x1, y1, x2, y2):
|
||||
if x1 > x2:
|
||||
x1, x2 = x2, x1
|
||||
if y1 > y2:
|
||||
y1, y2 = y2, y1
|
||||
return [(x, y) for x, y in self.cells
|
||||
if x1 <= x <= x2 and y1 <= y <= y2]
|
||||
|
||||
def movecells(self, x1, y1, x2, y2, dx, dy):
|
||||
if dx == 0 and dy == 0:
|
||||
return
|
||||
if x1 > x2:
|
||||
x1, x2 = x2, x1
|
||||
if y1 > y2:
|
||||
y1, y2 = y2, y1
|
||||
assert x1+dx > 0 and y1+dy > 0
|
||||
new = {}
|
||||
for x, y in self.cells:
|
||||
cell = self.cells[x, y]
|
||||
if hasattr(cell, 'renumber'):
|
||||
cell = cell.renumber(x1, y1, x2, y2, dx, dy)
|
||||
if x1 <= x <= x2 and y1 <= y <= y2:
|
||||
x += dx
|
||||
y += dy
|
||||
new[x, y] = cell
|
||||
self.cells = new
|
||||
|
||||
def insertrows(self, y, n):
|
||||
assert n > 0
|
||||
self.movecells(0, y, sys.maxsize, sys.maxsize, 0, n)
|
||||
|
||||
def deleterows(self, y1, y2):
|
||||
if y1 > y2:
|
||||
y1, y2 = y2, y1
|
||||
self.clearrows(y1, y2)
|
||||
self.movecells(0, y2+1, sys.maxsize, sys.maxsize, 0, y1-y2-1)
|
||||
|
||||
def insertcolumns(self, x, n):
|
||||
assert n > 0
|
||||
self.movecells(x, 0, sys.maxsize, sys.maxsize, n, 0)
|
||||
|
||||
def deletecolumns(self, x1, x2):
|
||||
if x1 > x2:
|
||||
x1, x2 = x2, x1
|
||||
self.clearcells(x1, x2)
|
||||
self.movecells(x2+1, 0, sys.maxsize, sys.maxsize, x1-x2-1, 0)
|
||||
|
||||
def getsize(self):
|
||||
maxx = maxy = 0
|
||||
for x, y in self.cells:
|
||||
maxx = max(maxx, x)
|
||||
maxy = max(maxy, y)
|
||||
return maxx, maxy
|
||||
|
||||
def reset(self):
|
||||
for cell in self.cells.values():
|
||||
if hasattr(cell, 'reset'):
|
||||
cell.reset()
|
||||
|
||||
def recalc(self):
|
||||
self.reset()
|
||||
for cell in self.cells.values():
|
||||
if hasattr(cell, 'recalc'):
|
||||
cell.recalc(self.ns)
|
||||
|
||||
def display(self):
|
||||
maxx, maxy = self.getsize()
|
||||
width, height = maxx+1, maxy+1
|
||||
colwidth = [1] * width
|
||||
full = {}
|
||||
# Add column heading labels in row 0
|
||||
for x in range(1, width):
|
||||
full[x, 0] = text, alignment = colnum2name(x), RIGHT
|
||||
colwidth[x] = max(colwidth[x], len(text))
|
||||
# Add row labels in column 0
|
||||
for y in range(1, height):
|
||||
full[0, y] = text, alignment = str(y), RIGHT
|
||||
colwidth[0] = max(colwidth[0], len(text))
|
||||
# Add sheet cells in columns with x>0 and y>0
|
||||
for (x, y), cell in self.cells.items():
|
||||
if x <= 0 or y <= 0:
|
||||
continue
|
||||
if hasattr(cell, 'recalc'):
|
||||
cell.recalc(self.ns)
|
||||
if hasattr(cell, 'format'):
|
||||
text, alignment = cell.format()
|
||||
assert isinstance(text, str)
|
||||
assert alignment in (LEFT, CENTER, RIGHT)
|
||||
else:
|
||||
text = str(cell)
|
||||
if isinstance(cell, str):
|
||||
alignment = LEFT
|
||||
else:
|
||||
alignment = RIGHT
|
||||
full[x, y] = (text, alignment)
|
||||
colwidth[x] = max(colwidth[x], len(text))
|
||||
# Calculate the horizontal separator line (dashes and dots)
|
||||
sep = ""
|
||||
for x in range(width):
|
||||
if sep:
|
||||
sep += "+"
|
||||
sep += "-"*colwidth[x]
|
||||
# Now print The full grid
|
||||
for y in range(height):
|
||||
line = ""
|
||||
for x in range(width):
|
||||
text, alignment = full.get((x, y)) or ("", LEFT)
|
||||
text = align2action[alignment](text, colwidth[x])
|
||||
if line:
|
||||
line += '|'
|
||||
line += text
|
||||
print(line)
|
||||
if y == 0:
|
||||
print(sep)
|
||||
|
||||
def xml(self):
|
||||
out = ['<spreadsheet>']
|
||||
for (x, y), cell in self.cells.items():
|
||||
if hasattr(cell, 'xml'):
|
||||
cellxml = cell.xml()
|
||||
else:
|
||||
cellxml = '<value>%s</value>' % escape(cell)
|
||||
out.append('<cell row="%s" col="%s">\n %s\n</cell>' %
|
||||
(y, x, cellxml))
|
||||
out.append('</spreadsheet>')
|
||||
return '\n'.join(out)
|
||||
|
||||
def save(self, filename):
|
||||
text = self.xml()
|
||||
with open(filename, "w", encoding='utf-8') as f:
|
||||
f.write(text)
|
||||
if text and not text.endswith('\n'):
|
||||
f.write('\n')
|
||||
|
||||
def load(self, filename):
|
||||
with open(filename, 'rb') as f:
|
||||
SheetParser(self).parsefile(f)
|
||||
|
||||
class SheetParser:
|
||||
|
||||
def __init__(self, sheet):
|
||||
self.sheet = sheet
|
||||
|
||||
def parsefile(self, f):
|
||||
parser = expat.ParserCreate()
|
||||
parser.StartElementHandler = self.startelement
|
||||
parser.EndElementHandler = self.endelement
|
||||
parser.CharacterDataHandler = self.data
|
||||
parser.ParseFile(f)
|
||||
|
||||
def startelement(self, tag, attrs):
|
||||
method = getattr(self, 'start_'+tag, None)
|
||||
if method:
|
||||
method(attrs)
|
||||
self.texts = []
|
||||
|
||||
def data(self, text):
|
||||
self.texts.append(text)
|
||||
|
||||
def endelement(self, tag):
|
||||
method = getattr(self, 'end_'+tag, None)
|
||||
if method:
|
||||
method("".join(self.texts))
|
||||
|
||||
def start_cell(self, attrs):
|
||||
self.y = int(attrs.get("row"))
|
||||
self.x = int(attrs.get("col"))
|
||||
|
||||
def start_value(self, attrs):
|
||||
self.fmt = attrs.get('format')
|
||||
self.alignment = xml2align.get(attrs.get('align'))
|
||||
|
||||
start_formula = start_value
|
||||
|
||||
def end_int(self, text):
|
||||
try:
|
||||
self.value = int(text)
|
||||
except (TypeError, ValueError):
|
||||
self.value = None
|
||||
|
||||
end_long = end_int
|
||||
|
||||
def end_double(self, text):
|
||||
try:
|
||||
self.value = float(text)
|
||||
except (TypeError, ValueError):
|
||||
self.value = None
|
||||
|
||||
def end_complex(self, text):
|
||||
try:
|
||||
self.value = complex(text)
|
||||
except (TypeError, ValueError):
|
||||
self.value = None
|
||||
|
||||
def end_string(self, text):
|
||||
self.value = text
|
||||
|
||||
def end_value(self, text):
|
||||
if isinstance(self.value, BaseCell):
|
||||
self.cell = self.value
|
||||
elif isinstance(self.value, str):
|
||||
self.cell = StringCell(self.value,
|
||||
self.fmt or "%s",
|
||||
self.alignment or LEFT)
|
||||
else:
|
||||
self.cell = NumericCell(self.value,
|
||||
self.fmt or "%s",
|
||||
self.alignment or RIGHT)
|
||||
|
||||
def end_formula(self, text):
|
||||
self.cell = FormulaCell(text,
|
||||
self.fmt or "%s",
|
||||
self.alignment or RIGHT)
|
||||
|
||||
def end_cell(self, text):
|
||||
self.sheet.setcell(self.x, self.y, self.cell)
|
||||
|
||||
class BaseCell:
|
||||
__init__ = None # Must provide
|
||||
"""Abstract base class for sheet cells.
|
||||
|
||||
Subclasses may but needn't provide the following APIs:
|
||||
|
||||
cell.reset() -- prepare for recalculation
|
||||
cell.recalc(ns) -> value -- recalculate formula
|
||||
cell.format() -> (value, alignment) -- return formatted value
|
||||
cell.xml() -> string -- return XML
|
||||
"""
|
||||
|
||||
class NumericCell(BaseCell):
|
||||
|
||||
def __init__(self, value, fmt="%s", alignment=RIGHT):
|
||||
assert isinstance(value, (int, float, complex))
|
||||
assert alignment in (LEFT, CENTER, RIGHT)
|
||||
self.value = value
|
||||
self.fmt = fmt
|
||||
self.alignment = alignment
|
||||
|
||||
def recalc(self, ns):
|
||||
return self.value
|
||||
|
||||
def format(self):
|
||||
try:
|
||||
text = self.fmt % self.value
|
||||
except:
|
||||
text = str(self.value)
|
||||
return text, self.alignment
|
||||
|
||||
def xml(self):
|
||||
method = getattr(self, '_xml_' + type(self.value).__name__)
|
||||
return '<value align="%s" format="%s">%s</value>' % (
|
||||
align2xml[self.alignment],
|
||||
self.fmt,
|
||||
method())
|
||||
|
||||
def _xml_int(self):
|
||||
if -2**31 <= self.value < 2**31:
|
||||
return '<int>%s</int>' % self.value
|
||||
else:
|
||||
return '<long>%s</long>' % self.value
|
||||
|
||||
def _xml_float(self):
|
||||
return '<double>%r</double>' % self.value
|
||||
|
||||
def _xml_complex(self):
|
||||
return '<complex>%r</complex>' % self.value
|
||||
|
||||
class StringCell(BaseCell):
|
||||
|
||||
def __init__(self, text, fmt="%s", alignment=LEFT):
|
||||
assert isinstance(text, str)
|
||||
assert alignment in (LEFT, CENTER, RIGHT)
|
||||
self.text = text
|
||||
self.fmt = fmt
|
||||
self.alignment = alignment
|
||||
|
||||
def recalc(self, ns):
|
||||
return self.text
|
||||
|
||||
def format(self):
|
||||
return self.text, self.alignment
|
||||
|
||||
def xml(self):
|
||||
s = '<value align="%s" format="%s"><string>%s</string></value>'
|
||||
return s % (
|
||||
align2xml[self.alignment],
|
||||
self.fmt,
|
||||
escape(self.text))
|
||||
|
||||
class FormulaCell(BaseCell):
|
||||
|
||||
def __init__(self, formula, fmt="%s", alignment=RIGHT):
|
||||
assert alignment in (LEFT, CENTER, RIGHT)
|
||||
self.formula = formula
|
||||
self.translated = translate(self.formula)
|
||||
self.fmt = fmt
|
||||
self.alignment = alignment
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
self.value = None
|
||||
|
||||
def recalc(self, ns):
|
||||
if self.value is None:
|
||||
try:
|
||||
self.value = eval(self.translated, ns)
|
||||
except:
|
||||
exc = sys.exc_info()[0]
|
||||
if hasattr(exc, "__name__"):
|
||||
self.value = exc.__name__
|
||||
else:
|
||||
self.value = str(exc)
|
||||
return self.value
|
||||
|
||||
def format(self):
|
||||
try:
|
||||
text = self.fmt % self.value
|
||||
except:
|
||||
text = str(self.value)
|
||||
return text, self.alignment
|
||||
|
||||
def xml(self):
|
||||
return '<formula align="%s" format="%s">%s</formula>' % (
|
||||
align2xml[self.alignment],
|
||||
self.fmt,
|
||||
escape(self.formula))
|
||||
|
||||
def renumber(self, x1, y1, x2, y2, dx, dy):
|
||||
out = []
|
||||
for part in re.split(r'(\w+)', self.formula):
|
||||
m = re.match('^([A-Z]+)([1-9][0-9]*)$', part)
|
||||
if m is not None:
|
||||
sx, sy = m.groups()
|
||||
x = colname2num(sx)
|
||||
y = int(sy)
|
||||
if x1 <= x <= x2 and y1 <= y <= y2:
|
||||
part = cellname(x+dx, y+dy)
|
||||
out.append(part)
|
||||
return FormulaCell("".join(out), self.fmt, self.alignment)
|
||||
|
||||
def translate(formula):
|
||||
"""Translate a formula containing fancy cell names to valid Python code.
|
||||
|
||||
Examples:
|
||||
B4 -> cell(2, 4)
|
||||
B4:Z100 -> cells(2, 4, 26, 100)
|
||||
"""
|
||||
out = []
|
||||
for part in re.split(r"(\w+(?::\w+)?)", formula):
|
||||
m = re.match(r"^([A-Z]+)([1-9][0-9]*)(?::([A-Z]+)([1-9][0-9]*))?$", part)
|
||||
if m is None:
|
||||
out.append(part)
|
||||
else:
|
||||
x1, y1, x2, y2 = m.groups()
|
||||
x1 = colname2num(x1)
|
||||
if x2 is None:
|
||||
s = "cell(%s, %s)" % (x1, y1)
|
||||
else:
|
||||
x2 = colname2num(x2)
|
||||
s = "cells(%s, %s, %s, %s)" % (x1, y1, x2, y2)
|
||||
out.append(s)
|
||||
return "".join(out)
|
||||
|
||||
def cellname(x, y):
|
||||
"Translate a cell coordinate to a fancy cell name (e.g. (1, 1)->'A1')."
|
||||
assert x > 0 # Column 0 has an empty name, so can't use that
|
||||
return colnum2name(x) + str(y)
|
||||
|
||||
def colname2num(s):
|
||||
"Translate a column name to number (e.g. 'A'->1, 'Z'->26, 'AA'->27)."
|
||||
s = s.upper()
|
||||
n = 0
|
||||
for c in s:
|
||||
assert 'A' <= c <= 'Z'
|
||||
n = n*26 + ord(c) - ord('A') + 1
|
||||
return n
|
||||
|
||||
def colnum2name(n):
|
||||
"Translate a column number to name (e.g. 1->'A', etc.)."
|
||||
assert n > 0
|
||||
s = ""
|
||||
while n:
|
||||
n, m = divmod(n-1, 26)
|
||||
s = chr(m+ord('A')) + s
|
||||
return s
|
||||
|
||||
import tkinter as Tk
|
||||
|
||||
class SheetGUI:
|
||||
|
||||
"""Beginnings of a GUI for a spreadsheet.
|
||||
|
||||
TO DO:
|
||||
- clear multiple cells
|
||||
- Insert, clear, remove rows or columns
|
||||
- Show new contents while typing
|
||||
- Scroll bars
|
||||
- Grow grid when window is grown
|
||||
- Proper menus
|
||||
- Undo, redo
|
||||
- Cut, copy and paste
|
||||
- Formatting and alignment
|
||||
"""
|
||||
|
||||
def __init__(self, filename="sheet1.xml", rows=10, columns=5):
|
||||
"""Constructor.
|
||||
|
||||
Load the sheet from the filename argument.
|
||||
Set up the Tk widget tree.
|
||||
"""
|
||||
# Create and load the sheet
|
||||
self.filename = filename
|
||||
self.sheet = Sheet()
|
||||
if os.path.isfile(filename):
|
||||
self.sheet.load(filename)
|
||||
# Calculate the needed grid size
|
||||
maxx, maxy = self.sheet.getsize()
|
||||
rows = max(rows, maxy)
|
||||
columns = max(columns, maxx)
|
||||
# Create the widgets
|
||||
self.root = Tk.Tk()
|
||||
self.root.wm_title("Spreadsheet: %s" % self.filename)
|
||||
self.beacon = Tk.Label(self.root, text="A1",
|
||||
font=('helvetica', 16, 'bold'))
|
||||
self.entry = Tk.Entry(self.root)
|
||||
self.savebutton = Tk.Button(self.root, text="Save",
|
||||
command=self.save)
|
||||
self.cellgrid = Tk.Frame(self.root)
|
||||
# Configure the widget lay-out
|
||||
self.cellgrid.pack(side="bottom", expand=1, fill="both")
|
||||
self.beacon.pack(side="left")
|
||||
self.savebutton.pack(side="right")
|
||||
self.entry.pack(side="left", expand=1, fill="x")
|
||||
# Bind some events
|
||||
self.entry.bind("<Return>", self.return_event)
|
||||
self.entry.bind("<Shift-Return>", self.shift_return_event)
|
||||
self.entry.bind("<Tab>", self.tab_event)
|
||||
self.entry.bind("<Shift-Tab>", self.shift_tab_event)
|
||||
self.entry.bind("<Delete>", self.delete_event)
|
||||
self.entry.bind("<Escape>", self.escape_event)
|
||||
# Now create the cell grid
|
||||
self.makegrid(rows, columns)
|
||||
# Select the top-left cell
|
||||
self.currentxy = None
|
||||
self.cornerxy = None
|
||||
self.setcurrent(1, 1)
|
||||
# Copy the sheet cells to the GUI cells
|
||||
self.sync()
|
||||
|
||||
def delete_event(self, event):
|
||||
if self.cornerxy != self.currentxy and self.cornerxy is not None:
|
||||
self.sheet.clearcells(*(self.currentxy + self.cornerxy))
|
||||
else:
|
||||
self.sheet.clearcell(*self.currentxy)
|
||||
self.sync()
|
||||
self.entry.delete(0, 'end')
|
||||
return "break"
|
||||
|
||||
def escape_event(self, event):
|
||||
x, y = self.currentxy
|
||||
self.load_entry(x, y)
|
||||
|
||||
def load_entry(self, x, y):
|
||||
cell = self.sheet.getcell(x, y)
|
||||
if cell is None:
|
||||
text = ""
|
||||
elif isinstance(cell, FormulaCell):
|
||||
text = '=' + cell.formula
|
||||
else:
|
||||
text, alignment = cell.format()
|
||||
self.entry.delete(0, 'end')
|
||||
self.entry.insert(0, text)
|
||||
self.entry.selection_range(0, 'end')
|
||||
|
||||
def makegrid(self, rows, columns):
|
||||
"""Helper to create the grid of GUI cells.
|
||||
|
||||
The edge (x==0 or y==0) is filled with labels; the rest is real cells.
|
||||
"""
|
||||
self.rows = rows
|
||||
self.columns = columns
|
||||
self.gridcells = {}
|
||||
# Create the top left corner cell (which selects all)
|
||||
cell = Tk.Label(self.cellgrid, relief='raised')
|
||||
cell.grid_configure(column=0, row=0, sticky='NSWE')
|
||||
cell.bind("<ButtonPress-1>", self.selectall)
|
||||
# Create the top row of labels, and configure the grid columns
|
||||
for x in range(1, columns+1):
|
||||
self.cellgrid.grid_columnconfigure(x, minsize=64)
|
||||
cell = Tk.Label(self.cellgrid, text=colnum2name(x), relief='raised')
|
||||
cell.grid_configure(column=x, row=0, sticky='WE')
|
||||
self.gridcells[x, 0] = cell
|
||||
cell.__x = x
|
||||
cell.__y = 0
|
||||
cell.bind("<ButtonPress-1>", self.selectcolumn)
|
||||
cell.bind("<B1-Motion>", self.extendcolumn)
|
||||
cell.bind("<ButtonRelease-1>", self.extendcolumn)
|
||||
cell.bind("<Shift-Button-1>", self.extendcolumn)
|
||||
# Create the leftmost column of labels
|
||||
for y in range(1, rows+1):
|
||||
cell = Tk.Label(self.cellgrid, text=str(y), relief='raised')
|
||||
cell.grid_configure(column=0, row=y, sticky='WE')
|
||||
self.gridcells[0, y] = cell
|
||||
cell.__x = 0
|
||||
cell.__y = y
|
||||
cell.bind("<ButtonPress-1>", self.selectrow)
|
||||
cell.bind("<B1-Motion>", self.extendrow)
|
||||
cell.bind("<ButtonRelease-1>", self.extendrow)
|
||||
cell.bind("<Shift-Button-1>", self.extendrow)
|
||||
# Create the real cells
|
||||
for x in range(1, columns+1):
|
||||
for y in range(1, rows+1):
|
||||
cell = Tk.Label(self.cellgrid, relief='sunken',
|
||||
bg='white', fg='black')
|
||||
cell.grid_configure(column=x, row=y, sticky='NSWE')
|
||||
self.gridcells[x, y] = cell
|
||||
cell.__x = x
|
||||
cell.__y = y
|
||||
# Bind mouse events
|
||||
cell.bind("<ButtonPress-1>", self.press)
|
||||
cell.bind("<B1-Motion>", self.motion)
|
||||
cell.bind("<ButtonRelease-1>", self.release)
|
||||
cell.bind("<Shift-Button-1>", self.release)
|
||||
|
||||
def selectall(self, event):
|
||||
self.setcurrent(1, 1)
|
||||
self.setcorner(sys.maxsize, sys.maxsize)
|
||||
|
||||
def selectcolumn(self, event):
|
||||
x, y = self.whichxy(event)
|
||||
self.setcurrent(x, 1)
|
||||
self.setcorner(x, sys.maxsize)
|
||||
|
||||
def extendcolumn(self, event):
|
||||
x, y = self.whichxy(event)
|
||||
if x > 0:
|
||||
self.setcurrent(self.currentxy[0], 1)
|
||||
self.setcorner(x, sys.maxsize)
|
||||
|
||||
def selectrow(self, event):
|
||||
x, y = self.whichxy(event)
|
||||
self.setcurrent(1, y)
|
||||
self.setcorner(sys.maxsize, y)
|
||||
|
||||
def extendrow(self, event):
|
||||
x, y = self.whichxy(event)
|
||||
if y > 0:
|
||||
self.setcurrent(1, self.currentxy[1])
|
||||
self.setcorner(sys.maxsize, y)
|
||||
|
||||
def press(self, event):
|
||||
x, y = self.whichxy(event)
|
||||
if x > 0 and y > 0:
|
||||
self.setcurrent(x, y)
|
||||
|
||||
def motion(self, event):
|
||||
x, y = self.whichxy(event)
|
||||
if x > 0 and y > 0:
|
||||
self.setcorner(x, y)
|
||||
|
||||
release = motion
|
||||
|
||||
def whichxy(self, event):
|
||||
w = self.cellgrid.winfo_containing(event.x_root, event.y_root)
|
||||
if w is not None and isinstance(w, Tk.Label):
|
||||
try:
|
||||
return w.__x, w.__y
|
||||
except AttributeError:
|
||||
pass
|
||||
return 0, 0
|
||||
|
||||
def save(self):
|
||||
self.sheet.save(self.filename)
|
||||
|
||||
def setcurrent(self, x, y):
|
||||
"Make (x, y) the current cell."
|
||||
if self.currentxy is not None:
|
||||
self.change_cell()
|
||||
self.clearfocus()
|
||||
self.beacon['text'] = cellname(x, y)
|
||||
self.load_entry(x, y)
|
||||
self.entry.focus_set()
|
||||
self.currentxy = x, y
|
||||
self.cornerxy = None
|
||||
gridcell = self.gridcells.get(self.currentxy)
|
||||
if gridcell is not None:
|
||||
gridcell['bg'] = 'yellow'
|
||||
|
||||
def setcorner(self, x, y):
|
||||
if self.currentxy is None or self.currentxy == (x, y):
|
||||
self.setcurrent(x, y)
|
||||
return
|
||||
self.clearfocus()
|
||||
self.cornerxy = x, y
|
||||
x1, y1 = self.currentxy
|
||||
x2, y2 = self.cornerxy or self.currentxy
|
||||
if x1 > x2:
|
||||
x1, x2 = x2, x1
|
||||
if y1 > y2:
|
||||
y1, y2 = y2, y1
|
||||
for (x, y), cell in self.gridcells.items():
|
||||
if x1 <= x <= x2 and y1 <= y <= y2:
|
||||
cell['bg'] = 'lightBlue'
|
||||
gridcell = self.gridcells.get(self.currentxy)
|
||||
if gridcell is not None:
|
||||
gridcell['bg'] = 'yellow'
|
||||
self.setbeacon(x1, y1, x2, y2)
|
||||
|
||||
def setbeacon(self, x1, y1, x2, y2):
|
||||
if x1 == y1 == 1 and x2 == y2 == sys.maxsize:
|
||||
name = ":"
|
||||
elif (x1, x2) == (1, sys.maxsize):
|
||||
if y1 == y2:
|
||||
name = "%d" % y1
|
||||
else:
|
||||
name = "%d:%d" % (y1, y2)
|
||||
elif (y1, y2) == (1, sys.maxsize):
|
||||
if x1 == x2:
|
||||
name = "%s" % colnum2name(x1)
|
||||
else:
|
||||
name = "%s:%s" % (colnum2name(x1), colnum2name(x2))
|
||||
else:
|
||||
name1 = cellname(*self.currentxy)
|
||||
name2 = cellname(*self.cornerxy)
|
||||
name = "%s:%s" % (name1, name2)
|
||||
self.beacon['text'] = name
|
||||
|
||||
|
||||
def clearfocus(self):
|
||||
if self.currentxy is not None:
|
||||
x1, y1 = self.currentxy
|
||||
x2, y2 = self.cornerxy or self.currentxy
|
||||
if x1 > x2:
|
||||
x1, x2 = x2, x1
|
||||
if y1 > y2:
|
||||
y1, y2 = y2, y1
|
||||
for (x, y), cell in self.gridcells.items():
|
||||
if x1 <= x <= x2 and y1 <= y <= y2:
|
||||
cell['bg'] = 'white'
|
||||
|
||||
def return_event(self, event):
|
||||
"Callback for the Return key."
|
||||
self.change_cell()
|
||||
x, y = self.currentxy
|
||||
self.setcurrent(x, y+1)
|
||||
return "break"
|
||||
|
||||
def shift_return_event(self, event):
|
||||
"Callback for the Return key with Shift modifier."
|
||||
self.change_cell()
|
||||
x, y = self.currentxy
|
||||
self.setcurrent(x, max(1, y-1))
|
||||
return "break"
|
||||
|
||||
def tab_event(self, event):
|
||||
"Callback for the Tab key."
|
||||
self.change_cell()
|
||||
x, y = self.currentxy
|
||||
self.setcurrent(x+1, y)
|
||||
return "break"
|
||||
|
||||
def shift_tab_event(self, event):
|
||||
"Callback for the Tab key with Shift modifier."
|
||||
self.change_cell()
|
||||
x, y = self.currentxy
|
||||
self.setcurrent(max(1, x-1), y)
|
||||
return "break"
|
||||
|
||||
def change_cell(self):
|
||||
"Set the current cell from the entry widget."
|
||||
x, y = self.currentxy
|
||||
text = self.entry.get()
|
||||
cell = None
|
||||
if text.startswith('='):
|
||||
cell = FormulaCell(text[1:])
|
||||
else:
|
||||
for cls in int, float, complex:
|
||||
try:
|
||||
value = cls(text)
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
else:
|
||||
cell = NumericCell(value)
|
||||
break
|
||||
if cell is None and text:
|
||||
cell = StringCell(text)
|
||||
if cell is None:
|
||||
self.sheet.clearcell(x, y)
|
||||
else:
|
||||
self.sheet.setcell(x, y, cell)
|
||||
self.sync()
|
||||
|
||||
def sync(self):
|
||||
"Fill the GUI cells from the sheet cells."
|
||||
self.sheet.recalc()
|
||||
for (x, y), gridcell in self.gridcells.items():
|
||||
if x == 0 or y == 0:
|
||||
continue
|
||||
cell = self.sheet.getcell(x, y)
|
||||
if cell is None:
|
||||
gridcell['text'] = ""
|
||||
else:
|
||||
if hasattr(cell, 'format'):
|
||||
text, alignment = cell.format()
|
||||
else:
|
||||
text, alignment = str(cell), LEFT
|
||||
gridcell['text'] = text
|
||||
gridcell['anchor'] = align2anchor[alignment]
|
||||
|
||||
|
||||
def test_basic():
|
||||
"Basic non-gui self-test."
|
||||
a = Sheet()
|
||||
for x in range(1, 11):
|
||||
for y in range(1, 11):
|
||||
if x == 1:
|
||||
cell = NumericCell(y)
|
||||
elif y == 1:
|
||||
cell = NumericCell(x)
|
||||
else:
|
||||
c1 = cellname(x, 1)
|
||||
c2 = cellname(1, y)
|
||||
formula = "%s*%s" % (c1, c2)
|
||||
cell = FormulaCell(formula)
|
||||
a.setcell(x, y, cell)
|
||||
## if os.path.isfile("sheet1.xml"):
|
||||
## print "Loading from sheet1.xml"
|
||||
## a.load("sheet1.xml")
|
||||
a.display()
|
||||
a.save("sheet1.xml")
|
||||
|
||||
def test_gui():
|
||||
"GUI test."
|
||||
if sys.argv[1:]:
|
||||
filename = sys.argv[1]
|
||||
else:
|
||||
filename = "sheet1.xml"
|
||||
g = SheetGUI(filename)
|
||||
g.root.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
#test_basic()
|
||||
test_gui()
|
||||
94
.CondaPkg/env/Tools/demo/vector.py
vendored
Normal file
94
.CondaPkg/env/Tools/demo/vector.py
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
A demonstration of classes and their special methods in Python.
|
||||
"""
|
||||
|
||||
class Vec:
|
||||
"""A simple vector class.
|
||||
|
||||
Instances of the Vec class can be constructed from numbers
|
||||
|
||||
>>> a = Vec(1, 2, 3)
|
||||
>>> b = Vec(3, 2, 1)
|
||||
|
||||
added
|
||||
>>> a + b
|
||||
Vec(4, 4, 4)
|
||||
|
||||
subtracted
|
||||
>>> a - b
|
||||
Vec(-2, 0, 2)
|
||||
|
||||
and multiplied by a scalar on the left
|
||||
>>> 3.0 * a
|
||||
Vec(3.0, 6.0, 9.0)
|
||||
|
||||
or on the right
|
||||
>>> a * 3.0
|
||||
Vec(3.0, 6.0, 9.0)
|
||||
|
||||
and dot product
|
||||
>>> a.dot(b)
|
||||
10
|
||||
|
||||
and printed in vector notation
|
||||
>>> print(a)
|
||||
<1 2 3>
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *v):
|
||||
self.v = list(v)
|
||||
|
||||
@classmethod
|
||||
def fromlist(cls, v):
|
||||
if not isinstance(v, list):
|
||||
raise TypeError
|
||||
inst = cls()
|
||||
inst.v = v
|
||||
return inst
|
||||
|
||||
def __repr__(self):
|
||||
args = ', '.join([repr(x) for x in self.v])
|
||||
return f'{type(self).__name__}({args})'
|
||||
|
||||
def __str__(self):
|
||||
components = ' '.join([str(x) for x in self.v])
|
||||
return f'<{components}>'
|
||||
|
||||
def __len__(self):
|
||||
return len(self.v)
|
||||
|
||||
def __getitem__(self, i):
|
||||
return self.v[i]
|
||||
|
||||
def __add__(self, other):
|
||||
"Element-wise addition"
|
||||
v = [x + y for x, y in zip(self.v, other.v)]
|
||||
return Vec.fromlist(v)
|
||||
|
||||
def __sub__(self, other):
|
||||
"Element-wise subtraction"
|
||||
v = [x - y for x, y in zip(self.v, other.v)]
|
||||
return Vec.fromlist(v)
|
||||
|
||||
def __mul__(self, scalar):
|
||||
"Multiply by scalar"
|
||||
v = [x * scalar for x in self.v]
|
||||
return Vec.fromlist(v)
|
||||
|
||||
__rmul__ = __mul__
|
||||
|
||||
def dot(self, other):
|
||||
"Vector dot product"
|
||||
if not isinstance(other, Vec):
|
||||
raise TypeError
|
||||
return sum(x_i * y_i for (x_i, y_i) in zip(self, other))
|
||||
|
||||
|
||||
def test():
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
||||
test()
|
||||
BIN
.CondaPkg/env/Tools/i18n/__pycache__/makelocalealias.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/i18n/__pycache__/makelocalealias.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/i18n/__pycache__/msgfmt.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/i18n/__pycache__/msgfmt.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/i18n/__pycache__/pygettext.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/i18n/__pycache__/pygettext.cpython-311.pyc
vendored
Normal file
Binary file not shown.
153
.CondaPkg/env/Tools/i18n/makelocalealias.py
vendored
Normal file
153
.CondaPkg/env/Tools/i18n/makelocalealias.py
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Convert the X11 locale.alias file into a mapping dictionary suitable
|
||||
for locale.py.
|
||||
|
||||
Written by Marc-Andre Lemburg <mal@genix.com>, 2004-12-10.
|
||||
|
||||
"""
|
||||
import locale
|
||||
import sys
|
||||
_locale = locale
|
||||
|
||||
# Location of the X11 alias file.
|
||||
LOCALE_ALIAS = '/usr/share/X11/locale/locale.alias'
|
||||
# Location of the glibc SUPPORTED locales file.
|
||||
SUPPORTED = '/usr/share/i18n/SUPPORTED'
|
||||
|
||||
def parse(filename):
|
||||
|
||||
with open(filename, encoding='latin1') as f:
|
||||
lines = list(f)
|
||||
# Remove mojibake in /usr/share/X11/locale/locale.alias.
|
||||
# b'\xef\xbf\xbd' == '\ufffd'.encode('utf-8')
|
||||
lines = [line for line in lines if '\xef\xbf\xbd' not in line]
|
||||
data = {}
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
if line[:1] == '#':
|
||||
continue
|
||||
locale, alias = line.split()
|
||||
# Fix non-standard locale names, e.g. ks_IN@devanagari.UTF-8
|
||||
if '@' in alias:
|
||||
alias_lang, _, alias_mod = alias.partition('@')
|
||||
if '.' in alias_mod:
|
||||
alias_mod, _, alias_enc = alias_mod.partition('.')
|
||||
alias = alias_lang + '.' + alias_enc + '@' + alias_mod
|
||||
# Strip ':'
|
||||
if locale[-1] == ':':
|
||||
locale = locale[:-1]
|
||||
# Lower-case locale
|
||||
locale = locale.lower()
|
||||
# Ignore one letter locale mappings (except for 'c')
|
||||
if len(locale) == 1 and locale != 'c':
|
||||
continue
|
||||
# Normalize encoding, if given
|
||||
if '.' in locale:
|
||||
lang, encoding = locale.split('.')[:2]
|
||||
encoding = encoding.replace('-', '')
|
||||
encoding = encoding.replace('_', '')
|
||||
locale = lang + '.' + encoding
|
||||
data[locale] = alias
|
||||
return data
|
||||
|
||||
def parse_glibc_supported(filename):
|
||||
|
||||
with open(filename, encoding='latin1') as f:
|
||||
lines = list(f)
|
||||
data = {}
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
if line[:1] == '#':
|
||||
continue
|
||||
line = line.replace('/', ' ').strip()
|
||||
line = line.rstrip('\\').rstrip()
|
||||
words = line.split()
|
||||
if len(words) != 2:
|
||||
continue
|
||||
alias, alias_encoding = words
|
||||
# Lower-case locale
|
||||
locale = alias.lower()
|
||||
# Normalize encoding, if given
|
||||
if '.' in locale:
|
||||
lang, encoding = locale.split('.')[:2]
|
||||
encoding = encoding.replace('-', '')
|
||||
encoding = encoding.replace('_', '')
|
||||
locale = lang + '.' + encoding
|
||||
# Add an encoding to alias
|
||||
alias, _, modifier = alias.partition('@')
|
||||
alias = _locale._replace_encoding(alias, alias_encoding)
|
||||
if modifier and not (modifier == 'euro' and alias_encoding == 'ISO-8859-15'):
|
||||
alias += '@' + modifier
|
||||
data[locale] = alias
|
||||
return data
|
||||
|
||||
def pprint(data):
|
||||
items = sorted(data.items())
|
||||
for k, v in items:
|
||||
print(' %-40s%a,' % ('%a:' % k, v))
|
||||
|
||||
def print_differences(data, olddata):
|
||||
items = sorted(olddata.items())
|
||||
for k, v in items:
|
||||
if k not in data:
|
||||
print('# removed %a' % k)
|
||||
elif olddata[k] != data[k]:
|
||||
print('# updated %a -> %a to %a' % \
|
||||
(k, olddata[k], data[k]))
|
||||
# Additions are not mentioned
|
||||
|
||||
def optimize(data):
|
||||
locale_alias = locale.locale_alias
|
||||
locale.locale_alias = data.copy()
|
||||
for k, v in data.items():
|
||||
del locale.locale_alias[k]
|
||||
if locale.normalize(k) != v:
|
||||
locale.locale_alias[k] = v
|
||||
newdata = locale.locale_alias
|
||||
errors = check(data)
|
||||
locale.locale_alias = locale_alias
|
||||
if errors:
|
||||
sys.exit(1)
|
||||
return newdata
|
||||
|
||||
def check(data):
|
||||
# Check that all alias definitions from the X11 file
|
||||
# are actually mapped to the correct alias locales.
|
||||
errors = 0
|
||||
for k, v in data.items():
|
||||
if locale.normalize(k) != v:
|
||||
print('ERROR: %a -> %a != %a' % (k, locale.normalize(k), v),
|
||||
file=sys.stderr)
|
||||
errors += 1
|
||||
return errors
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--locale-alias', default=LOCALE_ALIAS,
|
||||
help='location of the X11 alias file '
|
||||
'(default: %a)' % LOCALE_ALIAS)
|
||||
parser.add_argument('--glibc-supported', default=SUPPORTED,
|
||||
help='location of the glibc SUPPORTED locales file '
|
||||
'(default: %a)' % SUPPORTED)
|
||||
args = parser.parse_args()
|
||||
|
||||
data = locale.locale_alias.copy()
|
||||
data.update(parse_glibc_supported(args.glibc_supported))
|
||||
data.update(parse(args.locale_alias))
|
||||
while True:
|
||||
# Repeat optimization while the size is decreased.
|
||||
n = len(data)
|
||||
data = optimize(data)
|
||||
if len(data) == n:
|
||||
break
|
||||
print_differences(data, locale.locale_alias)
|
||||
print()
|
||||
print('locale_alias = {')
|
||||
pprint(data)
|
||||
print('}')
|
||||
246
.CondaPkg/env/Tools/i18n/msgfmt.py
vendored
Normal file
246
.CondaPkg/env/Tools/i18n/msgfmt.py
vendored
Normal file
@@ -0,0 +1,246 @@
|
||||
#! /usr/bin/env python3
|
||||
# Written by Martin v. Löwis <loewis@informatik.hu-berlin.de>
|
||||
|
||||
"""Generate binary message catalog from textual translation description.
|
||||
|
||||
This program converts a textual Uniforum-style message catalog (.po file) into
|
||||
a binary GNU catalog (.mo file). This is essentially the same function as the
|
||||
GNU msgfmt program, however, it is a simpler implementation. Currently it
|
||||
does not handle plural forms but it does handle message contexts.
|
||||
|
||||
Usage: msgfmt.py [OPTIONS] filename.po
|
||||
|
||||
Options:
|
||||
-o file
|
||||
--output-file=file
|
||||
Specify the output file to write to. If omitted, output will go to a
|
||||
file named filename.mo (based off the input file name).
|
||||
|
||||
-h
|
||||
--help
|
||||
Print this message and exit.
|
||||
|
||||
-V
|
||||
--version
|
||||
Display version information and exit.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import ast
|
||||
import getopt
|
||||
import struct
|
||||
import array
|
||||
from email.parser import HeaderParser
|
||||
|
||||
__version__ = "1.2"
|
||||
|
||||
MESSAGES = {}
|
||||
|
||||
|
||||
def usage(code, msg=''):
|
||||
print(__doc__, file=sys.stderr)
|
||||
if msg:
|
||||
print(msg, file=sys.stderr)
|
||||
sys.exit(code)
|
||||
|
||||
|
||||
def add(ctxt, id, str, fuzzy):
|
||||
"Add a non-fuzzy translation to the dictionary."
|
||||
global MESSAGES
|
||||
if not fuzzy and str:
|
||||
if ctxt is None:
|
||||
MESSAGES[id] = str
|
||||
else:
|
||||
MESSAGES[b"%b\x04%b" % (ctxt, id)] = str
|
||||
|
||||
|
||||
def generate():
|
||||
"Return the generated output."
|
||||
global MESSAGES
|
||||
# the keys are sorted in the .mo file
|
||||
keys = sorted(MESSAGES.keys())
|
||||
offsets = []
|
||||
ids = strs = b''
|
||||
for id in keys:
|
||||
# For each string, we need size and file offset. Each string is NUL
|
||||
# terminated; the NUL does not count into the size.
|
||||
offsets.append((len(ids), len(id), len(strs), len(MESSAGES[id])))
|
||||
ids += id + b'\0'
|
||||
strs += MESSAGES[id] + b'\0'
|
||||
output = ''
|
||||
# The header is 7 32-bit unsigned integers. We don't use hash tables, so
|
||||
# the keys start right after the index tables.
|
||||
# translated string.
|
||||
keystart = 7*4+16*len(keys)
|
||||
# and the values start after the keys
|
||||
valuestart = keystart + len(ids)
|
||||
koffsets = []
|
||||
voffsets = []
|
||||
# The string table first has the list of keys, then the list of values.
|
||||
# Each entry has first the size of the string, then the file offset.
|
||||
for o1, l1, o2, l2 in offsets:
|
||||
koffsets += [l1, o1+keystart]
|
||||
voffsets += [l2, o2+valuestart]
|
||||
offsets = koffsets + voffsets
|
||||
output = struct.pack("Iiiiiii",
|
||||
0x950412de, # Magic
|
||||
0, # Version
|
||||
len(keys), # # of entries
|
||||
7*4, # start of key index
|
||||
7*4+len(keys)*8, # start of value index
|
||||
0, 0) # size and offset of hash table
|
||||
output += array.array("i", offsets).tobytes()
|
||||
output += ids
|
||||
output += strs
|
||||
return output
|
||||
|
||||
|
||||
def make(filename, outfile):
|
||||
ID = 1
|
||||
STR = 2
|
||||
CTXT = 3
|
||||
|
||||
# Compute .mo name from .po name and arguments
|
||||
if filename.endswith('.po'):
|
||||
infile = filename
|
||||
else:
|
||||
infile = filename + '.po'
|
||||
if outfile is None:
|
||||
outfile = os.path.splitext(infile)[0] + '.mo'
|
||||
|
||||
try:
|
||||
with open(infile, 'rb') as f:
|
||||
lines = f.readlines()
|
||||
except IOError as msg:
|
||||
print(msg, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
section = msgctxt = None
|
||||
fuzzy = 0
|
||||
|
||||
# Start off assuming Latin-1, so everything decodes without failure,
|
||||
# until we know the exact encoding
|
||||
encoding = 'latin-1'
|
||||
|
||||
# Parse the catalog
|
||||
lno = 0
|
||||
for l in lines:
|
||||
l = l.decode(encoding)
|
||||
lno += 1
|
||||
# If we get a comment line after a msgstr, this is a new entry
|
||||
if l[0] == '#' and section == STR:
|
||||
add(msgctxt, msgid, msgstr, fuzzy)
|
||||
section = msgctxt = None
|
||||
fuzzy = 0
|
||||
# Record a fuzzy mark
|
||||
if l[:2] == '#,' and 'fuzzy' in l:
|
||||
fuzzy = 1
|
||||
# Skip comments
|
||||
if l[0] == '#':
|
||||
continue
|
||||
# Now we are in a msgid or msgctxt section, output previous section
|
||||
if l.startswith('msgctxt'):
|
||||
if section == STR:
|
||||
add(msgctxt, msgid, msgstr, fuzzy)
|
||||
section = CTXT
|
||||
l = l[7:]
|
||||
msgctxt = b''
|
||||
elif l.startswith('msgid') and not l.startswith('msgid_plural'):
|
||||
if section == STR:
|
||||
add(msgctxt, msgid, msgstr, fuzzy)
|
||||
if not msgid:
|
||||
# See whether there is an encoding declaration
|
||||
p = HeaderParser()
|
||||
charset = p.parsestr(msgstr.decode(encoding)).get_content_charset()
|
||||
if charset:
|
||||
encoding = charset
|
||||
section = ID
|
||||
l = l[5:]
|
||||
msgid = msgstr = b''
|
||||
is_plural = False
|
||||
# This is a message with plural forms
|
||||
elif l.startswith('msgid_plural'):
|
||||
if section != ID:
|
||||
print('msgid_plural not preceded by msgid on %s:%d' % (infile, lno),
|
||||
file=sys.stderr)
|
||||
sys.exit(1)
|
||||
l = l[12:]
|
||||
msgid += b'\0' # separator of singular and plural
|
||||
is_plural = True
|
||||
# Now we are in a msgstr section
|
||||
elif l.startswith('msgstr'):
|
||||
section = STR
|
||||
if l.startswith('msgstr['):
|
||||
if not is_plural:
|
||||
print('plural without msgid_plural on %s:%d' % (infile, lno),
|
||||
file=sys.stderr)
|
||||
sys.exit(1)
|
||||
l = l.split(']', 1)[1]
|
||||
if msgstr:
|
||||
msgstr += b'\0' # Separator of the various plural forms
|
||||
else:
|
||||
if is_plural:
|
||||
print('indexed msgstr required for plural on %s:%d' % (infile, lno),
|
||||
file=sys.stderr)
|
||||
sys.exit(1)
|
||||
l = l[6:]
|
||||
# Skip empty lines
|
||||
l = l.strip()
|
||||
if not l:
|
||||
continue
|
||||
l = ast.literal_eval(l)
|
||||
if section == CTXT:
|
||||
msgctxt += l.encode(encoding)
|
||||
elif section == ID:
|
||||
msgid += l.encode(encoding)
|
||||
elif section == STR:
|
||||
msgstr += l.encode(encoding)
|
||||
else:
|
||||
print('Syntax error on %s:%d' % (infile, lno), \
|
||||
'before:', file=sys.stderr)
|
||||
print(l, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
# Add last entry
|
||||
if section == STR:
|
||||
add(msgctxt, msgid, msgstr, fuzzy)
|
||||
|
||||
# Compute output
|
||||
output = generate()
|
||||
|
||||
try:
|
||||
with open(outfile,"wb") as f:
|
||||
f.write(output)
|
||||
except IOError as msg:
|
||||
print(msg, file=sys.stderr)
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'hVo:',
|
||||
['help', 'version', 'output-file='])
|
||||
except getopt.error as msg:
|
||||
usage(1, msg)
|
||||
|
||||
outfile = None
|
||||
# parse options
|
||||
for opt, arg in opts:
|
||||
if opt in ('-h', '--help'):
|
||||
usage(0)
|
||||
elif opt in ('-V', '--version'):
|
||||
print("msgfmt.py", __version__)
|
||||
sys.exit(0)
|
||||
elif opt in ('-o', '--output-file'):
|
||||
outfile = arg
|
||||
# do it
|
||||
if not args:
|
||||
print('No input file given', file=sys.stderr)
|
||||
print("Try `msgfmt --help' for more information.", file=sys.stderr)
|
||||
return
|
||||
|
||||
for filename in args:
|
||||
make(filename, outfile)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
684
.CondaPkg/env/Tools/i18n/pygettext.py
vendored
Normal file
684
.CondaPkg/env/Tools/i18n/pygettext.py
vendored
Normal file
@@ -0,0 +1,684 @@
|
||||
#! /usr/bin/env python3
|
||||
# -*- coding: iso-8859-1 -*-
|
||||
# Originally written by Barry Warsaw <barry@python.org>
|
||||
#
|
||||
# Minimally patched to make it even more xgettext compatible
|
||||
# by Peter Funk <pf@artcom-gmbh.de>
|
||||
#
|
||||
# 2002-11-22 J<>rgen Hermann <jh@web.de>
|
||||
# Added checks that _() only contains string literals, and
|
||||
# command line args are resolved to module lists, i.e. you
|
||||
# can now pass a filename, a module or package name, or a
|
||||
# directory (including globbing chars, important for Win32).
|
||||
# Made docstring fit in 80 chars wide displays using pydoc.
|
||||
#
|
||||
|
||||
# for selftesting
|
||||
try:
|
||||
import fintl
|
||||
_ = fintl.gettext
|
||||
except ImportError:
|
||||
_ = lambda s: s
|
||||
|
||||
__doc__ = _("""pygettext -- Python equivalent of xgettext(1)
|
||||
|
||||
Many systems (Solaris, Linux, Gnu) provide extensive tools that ease the
|
||||
internationalization of C programs. Most of these tools are independent of
|
||||
the programming language and can be used from within Python programs.
|
||||
Martin von Loewis' work[1] helps considerably in this regard.
|
||||
|
||||
There's one problem though; xgettext is the program that scans source code
|
||||
looking for message strings, but it groks only C (or C++). Python
|
||||
introduces a few wrinkles, such as dual quoting characters, triple quoted
|
||||
strings, and raw strings. xgettext understands none of this.
|
||||
|
||||
Enter pygettext, which uses Python's standard tokenize module to scan
|
||||
Python source code, generating .pot files identical to what GNU xgettext[2]
|
||||
generates for C and C++ code. From there, the standard GNU tools can be
|
||||
used.
|
||||
|
||||
A word about marking Python strings as candidates for translation. GNU
|
||||
xgettext recognizes the following keywords: gettext, dgettext, dcgettext,
|
||||
and gettext_noop. But those can be a lot of text to include all over your
|
||||
code. C and C++ have a trick: they use the C preprocessor. Most
|
||||
internationalized C source includes a #define for gettext() to _() so that
|
||||
what has to be written in the source is much less. Thus these are both
|
||||
translatable strings:
|
||||
|
||||
gettext("Translatable String")
|
||||
_("Translatable String")
|
||||
|
||||
Python of course has no preprocessor so this doesn't work so well. Thus,
|
||||
pygettext searches only for _() by default, but see the -k/--keyword flag
|
||||
below for how to augment this.
|
||||
|
||||
[1] https://www.python.org/workshops/1997-10/proceedings/loewis.html
|
||||
[2] https://www.gnu.org/software/gettext/gettext.html
|
||||
|
||||
NOTE: pygettext attempts to be option and feature compatible with GNU
|
||||
xgettext where ever possible. However some options are still missing or are
|
||||
not fully implemented. Also, xgettext's use of command line switches with
|
||||
option arguments is broken, and in these cases, pygettext just defines
|
||||
additional switches.
|
||||
|
||||
Usage: pygettext [options] inputfile ...
|
||||
|
||||
Options:
|
||||
|
||||
-a
|
||||
--extract-all
|
||||
Extract all strings.
|
||||
|
||||
-d name
|
||||
--default-domain=name
|
||||
Rename the default output file from messages.pot to name.pot.
|
||||
|
||||
-E
|
||||
--escape
|
||||
Replace non-ASCII characters with octal escape sequences.
|
||||
|
||||
-D
|
||||
--docstrings
|
||||
Extract module, class, method, and function docstrings. These do
|
||||
not need to be wrapped in _() markers, and in fact cannot be for
|
||||
Python to consider them docstrings. (See also the -X option).
|
||||
|
||||
-h
|
||||
--help
|
||||
Print this help message and exit.
|
||||
|
||||
-k word
|
||||
--keyword=word
|
||||
Keywords to look for in addition to the default set, which are:
|
||||
%(DEFAULTKEYWORDS)s
|
||||
|
||||
You can have multiple -k flags on the command line.
|
||||
|
||||
-K
|
||||
--no-default-keywords
|
||||
Disable the default set of keywords (see above). Any keywords
|
||||
explicitly added with the -k/--keyword option are still recognized.
|
||||
|
||||
--no-location
|
||||
Do not write filename/lineno location comments.
|
||||
|
||||
-n
|
||||
--add-location
|
||||
Write filename/lineno location comments indicating where each
|
||||
extracted string is found in the source. These lines appear before
|
||||
each msgid. The style of comments is controlled by the -S/--style
|
||||
option. This is the default.
|
||||
|
||||
-o filename
|
||||
--output=filename
|
||||
Rename the default output file from messages.pot to filename. If
|
||||
filename is `-' then the output is sent to standard out.
|
||||
|
||||
-p dir
|
||||
--output-dir=dir
|
||||
Output files will be placed in directory dir.
|
||||
|
||||
-S stylename
|
||||
--style stylename
|
||||
Specify which style to use for location comments. Two styles are
|
||||
supported:
|
||||
|
||||
Solaris # File: filename, line: line-number
|
||||
GNU #: filename:line
|
||||
|
||||
The style name is case insensitive. GNU style is the default.
|
||||
|
||||
-v
|
||||
--verbose
|
||||
Print the names of the files being processed.
|
||||
|
||||
-V
|
||||
--version
|
||||
Print the version of pygettext and exit.
|
||||
|
||||
-w columns
|
||||
--width=columns
|
||||
Set width of output to columns.
|
||||
|
||||
-x filename
|
||||
--exclude-file=filename
|
||||
Specify a file that contains a list of strings that are not be
|
||||
extracted from the input files. Each string to be excluded must
|
||||
appear on a line by itself in the file.
|
||||
|
||||
-X filename
|
||||
--no-docstrings=filename
|
||||
Specify a file that contains a list of files (one per line) that
|
||||
should not have their docstrings extracted. This is only useful in
|
||||
conjunction with the -D option above.
|
||||
|
||||
If `inputfile' is -, standard input is read.
|
||||
""")
|
||||
|
||||
import os
|
||||
import importlib.machinery
|
||||
import importlib.util
|
||||
import sys
|
||||
import glob
|
||||
import time
|
||||
import getopt
|
||||
import ast
|
||||
import token
|
||||
import tokenize
|
||||
|
||||
__version__ = '1.5'
|
||||
|
||||
default_keywords = ['_']
|
||||
DEFAULTKEYWORDS = ', '.join(default_keywords)
|
||||
|
||||
EMPTYSTRING = ''
|
||||
|
||||
|
||||
|
||||
# The normal pot-file header. msgmerge and Emacs's po-mode work better if it's
|
||||
# there.
|
||||
pot_header = _('''\
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\\n"
|
||||
"POT-Creation-Date: %(time)s\\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\\n"
|
||||
"MIME-Version: 1.0\\n"
|
||||
"Content-Type: text/plain; charset=%(charset)s\\n"
|
||||
"Content-Transfer-Encoding: %(encoding)s\\n"
|
||||
"Generated-By: pygettext.py %(version)s\\n"
|
||||
|
||||
''')
|
||||
|
||||
|
||||
def usage(code, msg=''):
|
||||
print(__doc__ % globals(), file=sys.stderr)
|
||||
if msg:
|
||||
print(msg, file=sys.stderr)
|
||||
sys.exit(code)
|
||||
|
||||
|
||||
|
||||
def make_escapes(pass_nonascii):
|
||||
global escapes, escape
|
||||
if pass_nonascii:
|
||||
# Allow non-ascii characters to pass through so that e.g. 'msgid
|
||||
# "H<>he"' would result not result in 'msgid "H\366he"'. Otherwise we
|
||||
# escape any character outside the 32..126 range.
|
||||
mod = 128
|
||||
escape = escape_ascii
|
||||
else:
|
||||
mod = 256
|
||||
escape = escape_nonascii
|
||||
escapes = [r"\%03o" % i for i in range(mod)]
|
||||
for i in range(32, 127):
|
||||
escapes[i] = chr(i)
|
||||
escapes[ord('\\')] = r'\\'
|
||||
escapes[ord('\t')] = r'\t'
|
||||
escapes[ord('\r')] = r'\r'
|
||||
escapes[ord('\n')] = r'\n'
|
||||
escapes[ord('\"')] = r'\"'
|
||||
|
||||
|
||||
def escape_ascii(s, encoding):
|
||||
return ''.join(escapes[ord(c)] if ord(c) < 128 else c for c in s)
|
||||
|
||||
def escape_nonascii(s, encoding):
|
||||
return ''.join(escapes[b] for b in s.encode(encoding))
|
||||
|
||||
|
||||
def is_literal_string(s):
|
||||
return s[0] in '\'"' or (s[0] in 'rRuU' and s[1] in '\'"')
|
||||
|
||||
|
||||
def safe_eval(s):
|
||||
# unwrap quotes, safely
|
||||
return eval(s, {'__builtins__':{}}, {})
|
||||
|
||||
|
||||
def normalize(s, encoding):
|
||||
# This converts the various Python string types into a format that is
|
||||
# appropriate for .po files, namely much closer to C style.
|
||||
lines = s.split('\n')
|
||||
if len(lines) == 1:
|
||||
s = '"' + escape(s, encoding) + '"'
|
||||
else:
|
||||
if not lines[-1]:
|
||||
del lines[-1]
|
||||
lines[-1] = lines[-1] + '\n'
|
||||
for i in range(len(lines)):
|
||||
lines[i] = escape(lines[i], encoding)
|
||||
lineterm = '\\n"\n"'
|
||||
s = '""\n"' + lineterm.join(lines) + '"'
|
||||
return s
|
||||
|
||||
|
||||
def containsAny(str, set):
|
||||
"""Check whether 'str' contains ANY of the chars in 'set'"""
|
||||
return 1 in [c in str for c in set]
|
||||
|
||||
|
||||
def getFilesForName(name):
|
||||
"""Get a list of module files for a filename, a module or package name,
|
||||
or a directory.
|
||||
"""
|
||||
if not os.path.exists(name):
|
||||
# check for glob chars
|
||||
if containsAny(name, "*?[]"):
|
||||
files = glob.glob(name)
|
||||
list = []
|
||||
for file in files:
|
||||
list.extend(getFilesForName(file))
|
||||
return list
|
||||
|
||||
# try to find module or package
|
||||
try:
|
||||
spec = importlib.util.find_spec(name)
|
||||
name = spec.origin
|
||||
except ImportError:
|
||||
name = None
|
||||
if not name:
|
||||
return []
|
||||
|
||||
if os.path.isdir(name):
|
||||
# find all python files in directory
|
||||
list = []
|
||||
# get extension for python source files
|
||||
_py_ext = importlib.machinery.SOURCE_SUFFIXES[0]
|
||||
for root, dirs, files in os.walk(name):
|
||||
# don't recurse into CVS directories
|
||||
if 'CVS' in dirs:
|
||||
dirs.remove('CVS')
|
||||
# add all *.py files to list
|
||||
list.extend(
|
||||
[os.path.join(root, file) for file in files
|
||||
if os.path.splitext(file)[1] == _py_ext]
|
||||
)
|
||||
return list
|
||||
elif os.path.exists(name):
|
||||
# a single file
|
||||
return [name]
|
||||
|
||||
return []
|
||||
|
||||
|
||||
class TokenEater:
|
||||
def __init__(self, options):
|
||||
self.__options = options
|
||||
self.__messages = {}
|
||||
self.__state = self.__waiting
|
||||
self.__data = []
|
||||
self.__lineno = -1
|
||||
self.__freshmodule = 1
|
||||
self.__curfile = None
|
||||
self.__enclosurecount = 0
|
||||
|
||||
def __call__(self, ttype, tstring, stup, etup, line):
|
||||
# dispatch
|
||||
## import token
|
||||
## print('ttype:', token.tok_name[ttype], 'tstring:', tstring,
|
||||
## file=sys.stderr)
|
||||
self.__state(ttype, tstring, stup[0])
|
||||
|
||||
def __waiting(self, ttype, tstring, lineno):
|
||||
opts = self.__options
|
||||
# Do docstring extractions, if enabled
|
||||
if opts.docstrings and not opts.nodocstrings.get(self.__curfile):
|
||||
# module docstring?
|
||||
if self.__freshmodule:
|
||||
if ttype == tokenize.STRING and is_literal_string(tstring):
|
||||
self.__addentry(safe_eval(tstring), lineno, isdocstring=1)
|
||||
self.__freshmodule = 0
|
||||
return
|
||||
if ttype in (tokenize.COMMENT, tokenize.NL, tokenize.ENCODING):
|
||||
return
|
||||
self.__freshmodule = 0
|
||||
# class or func/method docstring?
|
||||
if ttype == tokenize.NAME and tstring in ('class', 'def'):
|
||||
self.__state = self.__suiteseen
|
||||
return
|
||||
if ttype == tokenize.NAME and tstring in opts.keywords:
|
||||
self.__state = self.__keywordseen
|
||||
return
|
||||
if ttype == tokenize.STRING:
|
||||
maybe_fstring = ast.parse(tstring, mode='eval').body
|
||||
if not isinstance(maybe_fstring, ast.JoinedStr):
|
||||
return
|
||||
for value in filter(lambda node: isinstance(node, ast.FormattedValue),
|
||||
maybe_fstring.values):
|
||||
for call in filter(lambda node: isinstance(node, ast.Call),
|
||||
ast.walk(value)):
|
||||
func = call.func
|
||||
if isinstance(func, ast.Name):
|
||||
func_name = func.id
|
||||
elif isinstance(func, ast.Attribute):
|
||||
func_name = func.attr
|
||||
else:
|
||||
continue
|
||||
|
||||
if func_name not in opts.keywords:
|
||||
continue
|
||||
if len(call.args) != 1:
|
||||
print(_(
|
||||
'*** %(file)s:%(lineno)s: Seen unexpected amount of'
|
||||
' positional arguments in gettext call: %(source_segment)s'
|
||||
) % {
|
||||
'source_segment': ast.get_source_segment(tstring, call) or tstring,
|
||||
'file': self.__curfile,
|
||||
'lineno': lineno
|
||||
}, file=sys.stderr)
|
||||
continue
|
||||
if call.keywords:
|
||||
print(_(
|
||||
'*** %(file)s:%(lineno)s: Seen unexpected keyword arguments'
|
||||
' in gettext call: %(source_segment)s'
|
||||
) % {
|
||||
'source_segment': ast.get_source_segment(tstring, call) or tstring,
|
||||
'file': self.__curfile,
|
||||
'lineno': lineno
|
||||
}, file=sys.stderr)
|
||||
continue
|
||||
arg = call.args[0]
|
||||
if not isinstance(arg, ast.Constant):
|
||||
print(_(
|
||||
'*** %(file)s:%(lineno)s: Seen unexpected argument type'
|
||||
' in gettext call: %(source_segment)s'
|
||||
) % {
|
||||
'source_segment': ast.get_source_segment(tstring, call) or tstring,
|
||||
'file': self.__curfile,
|
||||
'lineno': lineno
|
||||
}, file=sys.stderr)
|
||||
continue
|
||||
if isinstance(arg.value, str):
|
||||
self.__addentry(arg.value, lineno)
|
||||
|
||||
def __suiteseen(self, ttype, tstring, lineno):
|
||||
# skip over any enclosure pairs until we see the colon
|
||||
if ttype == tokenize.OP:
|
||||
if tstring == ':' and self.__enclosurecount == 0:
|
||||
# we see a colon and we're not in an enclosure: end of def
|
||||
self.__state = self.__suitedocstring
|
||||
elif tstring in '([{':
|
||||
self.__enclosurecount += 1
|
||||
elif tstring in ')]}':
|
||||
self.__enclosurecount -= 1
|
||||
|
||||
def __suitedocstring(self, ttype, tstring, lineno):
|
||||
# ignore any intervening noise
|
||||
if ttype == tokenize.STRING and is_literal_string(tstring):
|
||||
self.__addentry(safe_eval(tstring), lineno, isdocstring=1)
|
||||
self.__state = self.__waiting
|
||||
elif ttype not in (tokenize.NEWLINE, tokenize.INDENT,
|
||||
tokenize.COMMENT):
|
||||
# there was no class docstring
|
||||
self.__state = self.__waiting
|
||||
|
||||
def __keywordseen(self, ttype, tstring, lineno):
|
||||
if ttype == tokenize.OP and tstring == '(':
|
||||
self.__data = []
|
||||
self.__lineno = lineno
|
||||
self.__state = self.__openseen
|
||||
else:
|
||||
self.__state = self.__waiting
|
||||
|
||||
def __openseen(self, ttype, tstring, lineno):
|
||||
if ttype == tokenize.OP and tstring == ')':
|
||||
# We've seen the last of the translatable strings. Record the
|
||||
# line number of the first line of the strings and update the list
|
||||
# of messages seen. Reset state for the next batch. If there
|
||||
# were no strings inside _(), then just ignore this entry.
|
||||
if self.__data:
|
||||
self.__addentry(EMPTYSTRING.join(self.__data))
|
||||
self.__state = self.__waiting
|
||||
elif ttype == tokenize.STRING and is_literal_string(tstring):
|
||||
self.__data.append(safe_eval(tstring))
|
||||
elif ttype not in [tokenize.COMMENT, token.INDENT, token.DEDENT,
|
||||
token.NEWLINE, tokenize.NL]:
|
||||
# warn if we see anything else than STRING or whitespace
|
||||
print(_(
|
||||
'*** %(file)s:%(lineno)s: Seen unexpected token "%(token)s"'
|
||||
) % {
|
||||
'token': tstring,
|
||||
'file': self.__curfile,
|
||||
'lineno': self.__lineno
|
||||
}, file=sys.stderr)
|
||||
self.__state = self.__waiting
|
||||
|
||||
def __addentry(self, msg, lineno=None, isdocstring=0):
|
||||
if lineno is None:
|
||||
lineno = self.__lineno
|
||||
if not msg in self.__options.toexclude:
|
||||
entry = (self.__curfile, lineno)
|
||||
self.__messages.setdefault(msg, {})[entry] = isdocstring
|
||||
|
||||
def set_filename(self, filename):
|
||||
self.__curfile = filename
|
||||
self.__freshmodule = 1
|
||||
|
||||
def write(self, fp):
|
||||
options = self.__options
|
||||
timestamp = time.strftime('%Y-%m-%d %H:%M%z')
|
||||
encoding = fp.encoding if fp.encoding else 'UTF-8'
|
||||
print(pot_header % {'time': timestamp, 'version': __version__,
|
||||
'charset': encoding,
|
||||
'encoding': '8bit'}, file=fp)
|
||||
# Sort the entries. First sort each particular entry's keys, then
|
||||
# sort all the entries by their first item.
|
||||
reverse = {}
|
||||
for k, v in self.__messages.items():
|
||||
keys = sorted(v.keys())
|
||||
reverse.setdefault(tuple(keys), []).append((k, v))
|
||||
rkeys = sorted(reverse.keys())
|
||||
for rkey in rkeys:
|
||||
rentries = reverse[rkey]
|
||||
rentries.sort()
|
||||
for k, v in rentries:
|
||||
# If the entry was gleaned out of a docstring, then add a
|
||||
# comment stating so. This is to aid translators who may wish
|
||||
# to skip translating some unimportant docstrings.
|
||||
isdocstring = any(v.values())
|
||||
# k is the message string, v is a dictionary-set of (filename,
|
||||
# lineno) tuples. We want to sort the entries in v first by
|
||||
# file name and then by line number.
|
||||
v = sorted(v.keys())
|
||||
if not options.writelocations:
|
||||
pass
|
||||
# location comments are different b/w Solaris and GNU:
|
||||
elif options.locationstyle == options.SOLARIS:
|
||||
for filename, lineno in v:
|
||||
d = {'filename': filename, 'lineno': lineno}
|
||||
print(_(
|
||||
'# File: %(filename)s, line: %(lineno)d') % d, file=fp)
|
||||
elif options.locationstyle == options.GNU:
|
||||
# fit as many locations on one line, as long as the
|
||||
# resulting line length doesn't exceed 'options.width'
|
||||
locline = '#:'
|
||||
for filename, lineno in v:
|
||||
d = {'filename': filename, 'lineno': lineno}
|
||||
s = _(' %(filename)s:%(lineno)d') % d
|
||||
if len(locline) + len(s) <= options.width:
|
||||
locline = locline + s
|
||||
else:
|
||||
print(locline, file=fp)
|
||||
locline = "#:" + s
|
||||
if len(locline) > 2:
|
||||
print(locline, file=fp)
|
||||
if isdocstring:
|
||||
print('#, docstring', file=fp)
|
||||
print('msgid', normalize(k, encoding), file=fp)
|
||||
print('msgstr ""\n', file=fp)
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
global default_keywords
|
||||
try:
|
||||
opts, args = getopt.getopt(
|
||||
sys.argv[1:],
|
||||
'ad:DEhk:Kno:p:S:Vvw:x:X:',
|
||||
['extract-all', 'default-domain=', 'escape', 'help',
|
||||
'keyword=', 'no-default-keywords',
|
||||
'add-location', 'no-location', 'output=', 'output-dir=',
|
||||
'style=', 'verbose', 'version', 'width=', 'exclude-file=',
|
||||
'docstrings', 'no-docstrings',
|
||||
])
|
||||
except getopt.error as msg:
|
||||
usage(1, msg)
|
||||
|
||||
# for holding option values
|
||||
class Options:
|
||||
# constants
|
||||
GNU = 1
|
||||
SOLARIS = 2
|
||||
# defaults
|
||||
extractall = 0 # FIXME: currently this option has no effect at all.
|
||||
escape = 0
|
||||
keywords = []
|
||||
outpath = ''
|
||||
outfile = 'messages.pot'
|
||||
writelocations = 1
|
||||
locationstyle = GNU
|
||||
verbose = 0
|
||||
width = 78
|
||||
excludefilename = ''
|
||||
docstrings = 0
|
||||
nodocstrings = {}
|
||||
|
||||
options = Options()
|
||||
locations = {'gnu' : options.GNU,
|
||||
'solaris' : options.SOLARIS,
|
||||
}
|
||||
|
||||
# parse options
|
||||
for opt, arg in opts:
|
||||
if opt in ('-h', '--help'):
|
||||
usage(0)
|
||||
elif opt in ('-a', '--extract-all'):
|
||||
options.extractall = 1
|
||||
elif opt in ('-d', '--default-domain'):
|
||||
options.outfile = arg + '.pot'
|
||||
elif opt in ('-E', '--escape'):
|
||||
options.escape = 1
|
||||
elif opt in ('-D', '--docstrings'):
|
||||
options.docstrings = 1
|
||||
elif opt in ('-k', '--keyword'):
|
||||
options.keywords.append(arg)
|
||||
elif opt in ('-K', '--no-default-keywords'):
|
||||
default_keywords = []
|
||||
elif opt in ('-n', '--add-location'):
|
||||
options.writelocations = 1
|
||||
elif opt in ('--no-location',):
|
||||
options.writelocations = 0
|
||||
elif opt in ('-S', '--style'):
|
||||
options.locationstyle = locations.get(arg.lower())
|
||||
if options.locationstyle is None:
|
||||
usage(1, _('Invalid value for --style: %s') % arg)
|
||||
elif opt in ('-o', '--output'):
|
||||
options.outfile = arg
|
||||
elif opt in ('-p', '--output-dir'):
|
||||
options.outpath = arg
|
||||
elif opt in ('-v', '--verbose'):
|
||||
options.verbose = 1
|
||||
elif opt in ('-V', '--version'):
|
||||
print(_('pygettext.py (xgettext for Python) %s') % __version__)
|
||||
sys.exit(0)
|
||||
elif opt in ('-w', '--width'):
|
||||
try:
|
||||
options.width = int(arg)
|
||||
except ValueError:
|
||||
usage(1, _('--width argument must be an integer: %s') % arg)
|
||||
elif opt in ('-x', '--exclude-file'):
|
||||
options.excludefilename = arg
|
||||
elif opt in ('-X', '--no-docstrings'):
|
||||
fp = open(arg)
|
||||
try:
|
||||
while 1:
|
||||
line = fp.readline()
|
||||
if not line:
|
||||
break
|
||||
options.nodocstrings[line[:-1]] = 1
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
# calculate escapes
|
||||
make_escapes(not options.escape)
|
||||
|
||||
# calculate all keywords
|
||||
options.keywords.extend(default_keywords)
|
||||
|
||||
# initialize list of strings to exclude
|
||||
if options.excludefilename:
|
||||
try:
|
||||
with open(options.excludefilename) as fp:
|
||||
options.toexclude = fp.readlines()
|
||||
except IOError:
|
||||
print(_(
|
||||
"Can't read --exclude-file: %s") % options.excludefilename, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
else:
|
||||
options.toexclude = []
|
||||
|
||||
# resolve args to module lists
|
||||
expanded = []
|
||||
for arg in args:
|
||||
if arg == '-':
|
||||
expanded.append(arg)
|
||||
else:
|
||||
expanded.extend(getFilesForName(arg))
|
||||
args = expanded
|
||||
|
||||
# slurp through all the files
|
||||
eater = TokenEater(options)
|
||||
for filename in args:
|
||||
if filename == '-':
|
||||
if options.verbose:
|
||||
print(_('Reading standard input'))
|
||||
fp = sys.stdin.buffer
|
||||
closep = 0
|
||||
else:
|
||||
if options.verbose:
|
||||
print(_('Working on %s') % filename)
|
||||
fp = open(filename, 'rb')
|
||||
closep = 1
|
||||
try:
|
||||
eater.set_filename(filename)
|
||||
try:
|
||||
tokens = tokenize.tokenize(fp.readline)
|
||||
for _token in tokens:
|
||||
eater(*_token)
|
||||
except tokenize.TokenError as e:
|
||||
print('%s: %s, line %d, column %d' % (
|
||||
e.args[0], filename, e.args[1][0], e.args[1][1]),
|
||||
file=sys.stderr)
|
||||
finally:
|
||||
if closep:
|
||||
fp.close()
|
||||
|
||||
# write the output
|
||||
if options.outfile == '-':
|
||||
fp = sys.stdout
|
||||
closep = 0
|
||||
else:
|
||||
if options.outpath:
|
||||
options.outfile = os.path.join(options.outpath, options.outfile)
|
||||
fp = open(options.outfile, 'w')
|
||||
closep = 1
|
||||
try:
|
||||
eater.write(fp)
|
||||
finally:
|
||||
if closep:
|
||||
fp.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
# some more test strings
|
||||
# this one creates a warning
|
||||
_('*** Seen unexpected token "%(token)s"') % {'token': 'test'}
|
||||
_('more' 'than' 'one' 'string')
|
||||
5
.CondaPkg/env/Tools/scripts/2to3.py
vendored
Normal file
5
.CondaPkg/env/Tools/scripts/2to3.py
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
import sys
|
||||
from lib2to3.main import main
|
||||
|
||||
sys.exit(main("lib2to3.fixes"))
|
||||
BIN
.CondaPkg/env/Tools/scripts/__pycache__/2to3.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/2to3.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/abitype.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/abitype.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/analyze_dxp.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/analyze_dxp.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/byext.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/byext.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/byteyears.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/byteyears.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/checkpip.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/checkpip.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/cleanfuture.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/cleanfuture.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/combinerefs.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/combinerefs.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/copytime.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/copytime.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/crlf.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/crlf.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/db2pickle.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/db2pickle.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/deepfreeze.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/deepfreeze.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/diff.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/diff.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/dutree.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/dutree.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/eptags.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/eptags.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/find-uname.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/find-uname.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/find_recursionlimit.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/find_recursionlimit.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/finddiv.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/finddiv.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/findlinksto.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/findlinksto.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/findnocoding.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/findnocoding.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/fixcid.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/fixcid.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/fixdiv.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/fixdiv.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/fixheader.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/fixheader.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/fixnotice.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/fixnotice.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/fixps.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/fixps.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/freeze_modules.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/freeze_modules.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/generate_global_objects.cpython-310.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/generate_global_objects.cpython-310.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/generate_global_objects.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/generate_global_objects.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/generate_opcode_h.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/generate_opcode_h.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/generate_re_casefix.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/generate_re_casefix.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/generate_sre_constants.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/generate_sre_constants.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/generate_stdlib_module_names.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/generate_stdlib_module_names.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/generate_token.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/generate_token.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/get-remote-certificate.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/get-remote-certificate.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/google.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/google.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/gprof2html.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/gprof2html.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/highlight.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/highlight.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/ifdef.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/ifdef.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/import_diagnostics.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/import_diagnostics.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/lfcr.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/lfcr.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/linktree.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/linktree.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/lll.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/lll.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/mailerdaemon.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/mailerdaemon.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/make_ctype.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/make_ctype.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/md5sum.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/md5sum.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/mkreal.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/mkreal.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/ndiff.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/ndiff.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/nm2def.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/nm2def.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/objgraph.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/objgraph.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/parse_html5_entities.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/parse_html5_entities.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/parseentities.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/parseentities.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/patchcheck.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/patchcheck.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/pathfix.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/pathfix.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/pdeps.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/pdeps.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/pep384_macrocheck.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/pep384_macrocheck.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/pickle2db.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/pickle2db.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/pindent.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/pindent.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/ptags.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/ptags.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/pydoc3.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/pydoc3.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/pysource.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/pysource.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/reindent-rst.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/reindent-rst.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/reindent.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/reindent.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/rgrep.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/rgrep.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/run_tests.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/run_tests.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/smelly.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/smelly.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/stable_abi.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/stable_abi.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Tools/scripts/__pycache__/startuptime.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Tools/scripts/__pycache__/startuptime.cpython-311.pyc
vendored
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user