Skip to content

Commit

Permalink
test on more configurations
Browse files Browse the repository at this point in the history
  • Loading branch information
idanpa committed Mar 29, 2024
1 parent 78431ae commit 6deff23
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 21 deletions.
9 changes: 5 additions & 4 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@ on:
jobs:
build:

runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
python-version: ["3.11"]
python-version: ["3.12"]
os: [windows-latest, macOS-latest, ubuntu-latest,]

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,17 @@ on:
jobs:
build:

runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11"]
python-version: ["3.10", "3.11", "3.12",]
os: [windows-latest, macOS-latest, ubuntu-latest,]

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
Expand Down
8 changes: 7 additions & 1 deletion calcpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,14 @@ class CalcPy(IPython.core.magic.Magics):
bitwidth = traitlets.Int(0, config=True, help="bitwidth of displayed binary integers, if 0 adjusted accordingly")
chop = traitlets.Bool(True, config=True, help="replace small numbers with zero")
units_prefixes = traitlets.Bool(False, config=True, help="units prefixes (e.g. 2k=2000)")
gui = traitlets.Unicode('auto', config=True, allow_none=True, help="matplotlib gui backend, set None to skip")
precision = property(
lambda calcpy: calcpy.shell.run_line_magic('precision', ''),
lambda calcpy, p: calcpy.shell.run_line_magic('precision', p))

_print_transformed_code = traitlets.Bool(False, config=False)

def __init__(self, shell=None, **kwargs):
def __init__(self, shell:IPython.InteractiveShell, **kwargs):
''''''
super(CalcPy, self).__init__(shell, **kwargs)

Expand Down Expand Up @@ -141,6 +142,7 @@ def load_previewer(self):
previewer_config = self.shell.config.copy()
previewer_config.CalcPy.previewer = False
previewer_config.CalcPy.auto_store = False
previewer_config.CalcPy.gui = None
previewer.load_ipython_extension(self.shell, config=previewer_config, formatter=formatters.previewer_formatter, debug=self.debug)

def unload_previewer(self):
Expand Down Expand Up @@ -175,6 +177,10 @@ def show_usage():
info.init(ip)
currency.init(ip)

# fix it for --simple-prompt case and -c e.g. calcpy --simple-prompt
if ip.calcpy.gui is not None and ip.config.TerminalInteractiveShell.simple_prompt != True:
ip.enable_matplotlib(ip.calcpy.gui)

# we hide ourselves all initial variable, (instead of ipython InteractiveShellApp.hide_initial_ns)
# so autostore and user startups variables would be exposed to who, who_ls
ip.user_ns_hidden.update(ip.user_ns)
Expand Down
25 changes: 22 additions & 3 deletions calcpy/info.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from functools import partial
import IPython
from IPython.utils.coloransi import TermColors
import shutil
import sympy
from contextlib import suppress
Expand All @@ -11,6 +12,11 @@ def calcpy_info_input_transformer_cleanup(lines):
lines[-1] += ')'
return lines

# check this on dark theme:
# give it another color, not lightgray
def cmd_color(cmd, comment=''):
return TermColors.LightGray + cmd + TermColors.LightGreen + comment + TermColors.Normal

def print_info_job(res):
ip = IPython.get_ipython()
terminal_size = shutil.get_terminal_size()
Expand Down Expand Up @@ -115,6 +121,7 @@ def print_info_job(res):
print(f'\n{N_p} = N(_)')
elif isinstance(res, sympy.matrices.MatrixBase):
if res.rows == res.cols:
# add nullspace and columnspace
print(f'\n{pretty(sympy.det(res))} = det(_)')
print(f'{pretty(sympy.trace(res))} = trace(_)')
try:
Expand All @@ -127,19 +134,19 @@ def print_info_job(res):
if len(evs_print) > page:
evs = [(sympy.N(ev[0]), ev[1], tuple(map(sympy.N, ev[2]))) for ev in evs]
evs_print = pretty(evs)
print(f'\n{evs_print} = _.eigenvects() # ((eval, mult, evec),...')
print(f'\n{evs_print}', cmd_color('= _.eigenvects()',' # ((eval, mult, evec),...'))
try:
diag = res.diagonalize()
diag_print = pretty(diag)
if len(diag_print) > page:
diag_print = pretty(list(map(sympy.N, diag)))
print(f'\n{diag_print} = _.diagonalize() # (P,D) so _=PDP^-1')
print(diag_print, cmd_color('= _.diagonalize()',' # (P,D) so _=PDP^-1'))
except sympy.matrices.matrices.MatrixError:
jord = res.jordan_form(chop=ip.calcpy.chop)
jord_print = pretty(jord)
if len(jord_print) > page:
jord_print = pretty(list(map(sympy.N, jord)))
print(f'\n{jord_print} = _.jordan_form() # (P,J) so _=PJP^-1')
print(f'\n{jord_print}', cmd_color('= _.jordan_form() ', '# (P,J) so _=PJP^-1'))

elif res.rows > 1 and res.cols > 1:
print(f'\n{pretty(res.rank())} = _.rank()')
Expand Down Expand Up @@ -167,6 +174,18 @@ def print_info(res):
ip.calcpy.jobs.new(print_info_job, res, daemon=True)
return res

import IPython.core.oinspect

def init(ip:IPython.InteractiveShell):
# old_pinfo = IPython.core.oinspect.Inspector.pinfo

# def pinfo(self, obj, oname="", formatter=None, info=None, detail_level=0, enable_html_pager=True, omit_sections=()):
# if isinstance(obj, (sympy.Expr, sympy.matrices.MatrixBase)):
# print_info(obj)
# else:
# old_pinfo(self, obj, oname=oname, formatter=formatter, info=info, detail_level=detail_level, enable_html_pager=enable_html_pager, omit_sections=omit_sections)

# IPython.core.oinspect.Inspector.pinfo = pinfo

ip.input_transformers_cleanup.append(calcpy_info_input_transformer_cleanup)

1 change: 0 additions & 1 deletion calcpy/tests/test_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ def test_setup(venv_dir):
def check_output(cmd):
return subprocess.check_output(activate + cmd, shell=True, text=True)

assert venv_dir in check_output('pip --version')
check_output('pip install ' + calcpy_path)
assert 'Out[1]: 2' in check_output('calcpy -c 1+1')
assert 'Out[1]: 2' in check_output('python -m calcpy -c 1+1')
17 changes: 14 additions & 3 deletions calcpy/tests/test_startup_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,29 @@
import time

def test_startup_time(n=10):
elapsed = []
for i in range(n):
p = subprocess.Popen('calcpy', stdout=subprocess.PIPE, stdin=subprocess.PIPE)
start_time = time.time()
elapsed.append(time.time() - start_time)

print(f'max {max(elapsed)}')
print(f'min {min(elapsed)}')
print(f'avg {sum(elapsed)/n}')

def test_exec_time(n=10):
# warmup:
subprocess.check_call(['calcpy', '-c', '4+4'], stdout=None, stdin=subprocess.PIPE)
subprocess.check_call(['calcpy', '-c', '4+4'], stdin=subprocess.PIPE)

elapsed = []
for i in range(n):
start_time = time.time()
subprocess.check_call(['calcpy', '-c', '4+4'], stdout=None, stdin=subprocess.PIPE)
subprocess.check_call(['calcpy', '-c', '4+4'], stdin=subprocess.PIPE)
elapsed.append(time.time() - start_time)
print(elapsed[-1])
print(f'max {max(elapsed)}')
print(f'min {min(elapsed)}')
print(f'avg {sum(elapsed)/n}')

if __name__ == "__main__":
test_startup_time()
test_exec_time()
22 changes: 22 additions & 0 deletions calcpy/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,25 @@ def copy(obj):
r.clipboard_append(obj)
r.update()
r.destroy()

# import sympy

# class SpecialNumber(sympy.Number):
# """
# special number that get casted to itself on every operation, so its properties are sticky
# """

# @cacheit
# def __new__(cls, *args, evaluate=None, _sympify=True):
# # def __init__(self, value:sympy.Number):
# # super().__init__()
# pass
# # hold type

# def __add__(self, other):
# return self.type.__new__(self+other)

# class Currency(SpecialNumber):

# def __init__(self, name, rates):
# self.name = name
18 changes: 15 additions & 3 deletions docs/demo/asciinario.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,21 @@ def play_inscript(text, screen_id):
player.do(line)

parser = ArgumentParser()
parser.add_argument('-t', '--type', default='asciinema', help="type of recorder")
parser.add_argument("--keep", action="store_true", help="don't kill session")
parser.add_argument("scenario")
parser.add_argument("output")
args, args_reminder = parser.parse_known_args()
instructions = Path(args.scenario).read_text()

screen_id = str(uuid4())
cmd = f"screen -S {screen_id}"
recorder_proc = subprocess.Popen(["asciinema", "rec", "--overwrite", "--cols", "80", "--rows", "20", "-c", cmd, args.output])
if args.type == 'asciinema':
cmd = f"screen -S {screen_id}"
recorder_proc = subprocess.Popen(["asciinema", "rec", "--overwrite", "--cols", "80", "--rows", "20", "-c", cmd, args.output])
elif args.type == 'screen':
recorder_proc = subprocess.Popen(["screen", "-L", "-Logfile", args.output, "-S", screen_id])
elif args.type == 'script':
recorder_proc = subprocess.Popen(["screen", "-S", screen_id])

# give some time for screen to start
for _ in range(10):
Expand All @@ -140,6 +147,11 @@ def play_inscript(text, screen_id):
else:
sys.exit(f"screen session {screen_id} could not be found")

if args.type == 'script':
subprocess.check_output(["screen", "-S", screen_id, "-X", "stuff", rf"script {args.output}\n"])
time.sleep(.5)

play_inscript(instructions, screen_id)
subprocess.check_output(["screen", "-S", screen_id, "-X", "quit"])
if not args.keep:
subprocess.check_output(["screen", "-S", screen_id, "-X", "quit"])
recorder_proc.wait()
14 changes: 12 additions & 2 deletions previewer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ def initialize(self):
self.previewer_ip.ast_transformers.append(self.disable_assign)
self.ns_thread = threading.Thread(target=self.ns_job, daemon=True, name='ns_job')
self.ns_thread.start()
# self.ctrl_thread = PipeListener(self.ctrl_conn, self.ctrl_cb)

self.sandbox_post()

Expand All @@ -142,12 +143,16 @@ def ns_job(self):
except Exception as e:
print(f'ns error: {repr(e)}')

# def ctrl_cb(self, ctrl_msg):
# if ctrl_msg == 'ctrl_c':
# self.ctrl_c()

def ask_restart(self):
print('asking restart')
print('asking restart', flush=True)
self.ctrl_conn.send('restart')

def ctrl_c(self):
print('sending SIGINT')
print('sending SIGINT', flush=True)
signal.raise_signal(signal.SIGINT)

def run(self):
Expand Down Expand Up @@ -194,6 +199,11 @@ def run_code(self, code, assign):
self.disable_assign.active = not assign
print(f'In [1]: {code}')
result = self.previewer_ip.run_cell(code, store_history=False)
# if result.error_in_exec is not None:
# print(f'error in exec: {repr(result.error_in_exec)} result: {result.result}')
# # print(result.info.raw_cell)
# # traceback.print_exception(result.error_in_exec)
sys.stdout.flush()
if result.result is None:
return ''
return self.formatter(result.result)
Expand Down

0 comments on commit 6deff23

Please sign in to comment.