diff --git a/.gitignore b/.gitignore index e25117bd..1e4eadf4 100755 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,5 @@ dist __pycache__ .coverage coverage.lcov -docs/obj/* -log/* +staging +log diff --git a/Makefile b/Makefile index efceadf2..6fd7b1ce 100755 --- a/Makefile +++ b/Makefile @@ -1,70 +1,42 @@ -.RECIPEPREFIX=> -export MAKEFLAGS=-Otarget --no-print-directory -r -R --warn +.RECIPEPREFIX = > +export MAKEFLAGS=-Otarget --no-print-directory -r -R --warn #-j30 export COLUMNS=40 +PATH := $(HOME)/.local/bin:/usr/bin -# topj: -# > @ make -j 3 default -PATH := $(HOME)/.local/bin:/usr/bin -EMACS := emacs -POETRY := poetry -PR := $(POETRY) run - -RUN_MODVERSION := $(PR) python tools/modversion.py -RUN_MAKESTDVARS := $(PR) python tools/makestdvars.py -RUN_COVERAGE := $(PR) coverage -RUN_PYTEST := $(PR) pytest - -LOG_DIR := log -DOCS_DIR := docs -VERSION_FILE := p2g/VERSION - -LINTS := pyright mypy pylint ruff flake8 -LOG_LINTS := $(patsubst %,$(LOG_DIR)/%.llog, $(LINTS)) - -DISTDIFFS_ERROR := $(LOG_DIR)/distdiffs-error -LOG_DISTDIFFS := $(LOG_DIR)/distdiffs.log -LOG_DISTGOT := $(LOG_DIR)/distgot.log -LOG_DISTWANT := $(LOG_DIR)/distwant.log - -LOG_DIST := $(LOG_DIR)/FILES-IN-DIST.LOG -LOG_DOC := $(LOG_DIR)/doc.log -LOG_EXAMPLES := $(LOG_DIR)/examples.log -LOG_LINT := $(LOG_DIR)/ALL-LINTS.LOG -LOG_POETRY := $(LOG_DIR)/poetry.log -LOG_COVERAGE := $(LOG_DIR)/coverage.log -LOG_TESTS := $(LOG_DIR)/pytest.log -THIS_VERSION := $(shell cat $(VERSION_FILE)) -LOG_TOX := $(LOG_DIR)/tox.log -VERSION_STAMP := $(LOG_DIR)/version-$(THIS_VERSION).log - - -.PHONY : lint test start finish examples docs poetry version dist -default : start | finish -docs : $(LOG_DOC) -examples : $(LOG_EXAMPLES) -lint : $(LOG_LINT) -poetry : $(LOG_POETRY) -tests : $(LOG_TESTS) -version : $(VERSION_STAMP) -tox : $(LOG_TOX) -dist : $(LOG_DIST) - -# only need this if rebuilding doc. -OX_GFM_DIR = ~/.emacs.d/straight/build/ox-gfm +LOG_DIR := log +DIST_DIR := dist +DOCS_DIR := docs +STAGING_DIR := staging -HR = @ echo "*******" +VERSION_FILE := p2g/VERSION +VERSION := $(shell cat $(VERSION_FILE)) +DIST_FILE := dist/p2g-$(VERSION).tar.gz + +LOG_POETRY := $(LOG_DIR)/poetry.log +LOG_COVERAGE := $(LOG_DIR)/coverage.log +LOG_TESTS := $(LOG_DIR)/pytest.log +LOG_LINTS := $(LOG_DIR)/lints.log + +LINTS := pyright mypy pylint ruff flake8 + +POETRY := poetry +PR := $(POETRY) run + +default : dist + +H0 = @ echo "*" H1 = @ echo "***" H2 = @ echo "*****" -HW = @ echo "newer deps " $? +HR = @ echo "*******" + ###################################################################### # files used, should only appear once. -P2G_GEN_SRC := \ - p2g/haas.py -ALL_P2G_SRC := \ +ALL_P2G_SRC := \ p2g/__init__.py \ p2g/__main__.py \ + p2g/abandon.py \ p2g/axis.py \ p2g/builtin.py \ p2g/coords.py \ @@ -72,6 +44,7 @@ ALL_P2G_SRC := \ p2g/fstring.py \ p2g/gbl.py \ p2g/goto.py \ + p2g/haas.py \ p2g/main.py \ p2g/nd.py \ p2g/op.py \ @@ -84,13 +57,13 @@ ALL_P2G_SRC := \ p2g/walkexpr.py \ p2g/walkfunc.py \ p2g/walkstat.py \ - $(P2G_GEN_SRC) -TOOL_SRC := \ +TOOL_SRC := \ tools/modversion.py \ - tools/makestdvars.py + tools/makestdvars.py \ + tools/fakeorg.py -FUNC_TEST_FILES := \ +FUNC_TEST_FILES := \ tests/test_assert.py \ tests/test_axes.py \ tests/test_badpytest.py \ @@ -127,18 +100,31 @@ FUNC_TEST_FILES := \ tests/test_vars.py \ tests/test_vector.py -READMEMD := README.MD -DIST_DOC := \ +DIST_DOC := \ docs/howto.md \ docs/howto.txt \ docs/haas.txt \ - docs/pytest.svg \ docs/coverage.svg \ + docs/pytest.svg \ docs/mit.svg \ - $(READMEMD) + readme.md + -INCLUDED_ORGS := \ - docs/src/authors.org \ +EXAMPLES := \ + examples/probecalibrate.nc \ + examples/vicecenter.nc \ + examples/maxflutes.nc \ + examples/maxflutes.py \ + examples/probecalibrate.py \ + examples/usrlib.py \ + examples/vicecenter.py \ + +ALL_TEST_SRC := \ + $(FUNC_TEST_FILES) \ + tests/conftest.py + +ALL_ORGS := \ +docs/src/authors.org \ docs/src/axes.org \ docs/src/badges.org \ docs/src/coordinates.org \ @@ -147,10 +133,14 @@ INCLUDED_ORGS := \ docs/src/expressions.org \ docs/src/goto.org \ docs/src/haas.org \ + docs/src/howto.org \ docs/src/install.org \ docs/src/introduction.org \ docs/src/license.org \ + docs/src/maint.org \ + docs/src/maintopt.org \ docs/src/notes.org \ + docs/src/readme.org \ docs/src/release.org \ docs/src/symboltables.org \ docs/src/thanksto.org \ @@ -161,85 +151,35 @@ INCLUDED_ORGS := \ docs/src/when.org \ docs/src/why.org -COMPILED_EXAMPLES := \ - examples/probecalibrate.nc \ - examples/vicecenter.nc \ - examples/maxflutes.nc -EXAMPLE_SRC := \ - examples/maxflutes.py \ - examples/probecalibrate.py \ - examples/usrlib.py \ - examples/vicecenter.py \ - -ALL_TEST_SRC := \ - $(FUNC_TEST_FILES) \ - $(EXAMPLE_SRC) \ - tests/conftest.py - - - -###################################################################### -ALL_EXAMPLES := $(EXAMPLE_SRC) $(COMPILED_EXAMPLES) -DIST_FILE := dist/p2g-$(THIS_VERSION).tar.gz -ALL_PY := $(ALL_P2G_SRC) $(TOOL_SRC) $(ALL_TEST_SRC) LINTABLE_SRC := $(ALL_P2G_SRC) $(TOOL_SRC) -CONTROL_FILES := Makefile pyproject.toml .scrutinizer.yml - - -VERSIONED_FILES = p2g/__init__.py pyproject.toml docs/src/introduction.org -IN_DIST := $(ALL_EXAMPLES) $(DIST_DOC) $(ALL_P2G_SRC) $(VERSION_FILE) - -.PRECIOUS: $(LOG_POETRY) -.PRECIOUS: $(IN_DIST) -.PRECIOUS: $(LOG_DOC) -.PRECIOUS: $(LOG_TESTS) -.PRECIOUS: $(LOG_LINT) -.PRECIOUS: $(DIST_FILE) -DEFAULT_DEPS := \ - $(LOG_POETRY) \ - $(IN_DIST) \ - $(LOG_DOC) \ - $(LOG_TESTS) \ - $(LOG_LINT) \ - $(DIST_FILE) +VERSIONED_FILES := p2g/__init__.py pyproject.toml docs/src/introduction.org +IN_DIST := $(EXAMPLES) $(DIST_DOC) $(ALL_P2G_SRC) $(VERSION_FILE) -###################################################################### -.EXTRA_PREREQS:= .mkdirs - -.mkdirs: ->mkdir -p $(LOG_DIR) $(DOCS_DIR)/obj -> touch $@ -$(DOCS_DIR)/obj $(LOG_DIR): -> mkdir -p $@ - -start : -> $(HR) -> $(H1) $$(python --version) p2g $(THIS_VERSION) +###################################################################### +.EXTRA_PREREQS := $(LOG_POETRY) -finish : $(DEFAULT_DEPS) $(LOG_DISTDIFFS) +dist : tests lint $(DIST_FILE) > $(HR) +> $(H1) $$(python --version) p2g $(VERSION) > $(H1) Package in $(DIST_FILE) - -install : $(DIST_FILE) +install : $(DIST_FILE) > pip install --user $< ###################################################################### # Init environment -$(VERSION_STAMP) : $(VERSION_FILE) $(LOG_POETRY) -> $(RUN_MODVERSION) \ - --truth $(VERSION_FILE) \ - --names $(VERSIONED_FILES) \ - --stdout > $@ - -$(VERSIONED_FILES) : $(VERSION_STAMP) +$(VERSIONED_FILES) &: $(VERSION_FILE) $(LOG_POETRY) +> $(PR) python tools/modversion.py \ + --truth $(VERSION_FILE) \ + --victims $(VERSIONED_FILES) -.PRECIOUS: $(LOG_POETRY) -$(LOG_POETRY) : +.PRECIOUS : $(LOG_POETRY) +$(LOG_POETRY) : +> mkdir -p $(LOG_DIR) $(DIST_DIR) > # take opportunity to make dest directories. > $(HR) > which poetry || curl -sSL https://install.python-poetry.org | python3 @@ -248,259 +188,168 @@ $(LOG_POETRY) : > $(HR) > $(POETRY) install > $(POETRY) update -> $(POETRY) export --without-hashes > requirements.txt +> #$(POETRY) export --without-hashes > requirements.txt > $(POETRY) --version > $(LOG_POETRY) +> # make the log file old - things don't depend on +> # when poetry was installed, just that it was. +> @touch -t 200001010101 $(LOG_POETRY) + ###################################################################### -# examples -#$(LOG_EXAMPLES) : $(COMPILED_EXAMPLES) -#n -#examples/%.nc:examples/%.py -#> $(PR) p2g $< $@ | tee -a $(LOG_EXAMPLES) + +examples/%.nc: examples/%.py +> poetry run p2g --no-id $< $@ ###################################################################### # machine generated code -p2g/haas.py : tools/makestdvars.py $(LOG_POETRY) -> $(RUN_MAKESTDVARS) --py=$@ +p2g/haas.py : tools/makestdvars.py $(LOG_POETRY) +> $(PR) python tools/makestdvars.py --py=$@ docs/haas.txt : tools/makestdvars.py $(LOG_POETRY) -> $(RUN_MAKESTDVARS) --txt=$@ +> $(PR) python tools/makestdvars.py --txt=$@ docs/haas.html : tools/makestdvars.py $(LOG_POETRY) -> $(RUN_MAKESTDVARS) --html=$@ - -###################################################################### -# emacs path -# only make docs if there's an emacs. -ifeq ($(shell which $(EMACS)),) -$(LOG_DOC) : -> echo "DOC not being rebuilt, needs emacs." | tee $@ -> touch $(DIST_DOC) -EVAL=@ echo "NO EMACS" -else -ifeq ($(wildcard $(OX_GFM_DIR)),) -$(LOG_DOC) : ->@ echo "EMACS installed, but still need" \ - "github markdown org export." \ -| tee $@ -> touch $(DIST_DOC) -EVAL=@ echo NEED GITHUB MARKDOWN EXPORT" -else -# run emacs in batch to expand and include files -# which make up the final doc. Sed out the -# loquacity. -EVAL = \ - emacs $(abspath $<) \ - -q -Q \ - --chdir $(dir $(abspath $<)) \ - -L $(OX_GFM_DIR) \ - --batch \ - --load $(abspath tools/org-to-x.el) \ - -f org-to-any \ - $(abspath $@) \ - 2>&1 | sed \ - -e '/Code block.*/d' \ - -e 's:executing Python code block::g' ; \ - test -s $@ || echo "EMPTY FILE"; \ - test -s $@ - -###################################################################### -# the readme md includes some of the exorgs and the toc., see what changed. -TMP_ORGS = $(patsubst docs/src/%,docs/obj/%,$(INCLUDED_ORGS)) -ORG_DIFFS = $(patsubst %.org, %.diff,$(TMP_ORGS)) -$(LOG_DOC) : $(DIST_DOC) $(ORG_DIFFS) -> @ cat $(ORG_DIFFS) | tee $@.error -> if test -s $@.error ; then \ - echo "DOC HAS DIFFERENCES" ; \ - echo "maybe cp docs/obj/*.org docs/src" ; \ - exit 1; \ -fi -> mv $@.error $@ - -endif - - -###################################################################### -# tmp orgs are org files with includes and evaluation. - -VPATH = docs/src - -docs/obj/%.org:%.org $(VERSION_STAMP) -> $(EVAL) - - -docs/obj/%.diff:docs/obj/%.org -> - diff docs/src/$*.org $< > $@ - -%.md:%.org $(TMP_ORGS) -> $(EVAL) - -README.MD : readme.org $(TMP_ORGS) -> $(EVAL) - -$(INCLUDED_ORGS) : $(VERSION_STAMP) - -docs/howto.txt docs/howto.md: docs/obj/howto.org $(TMP_ORGS) -> $(EVAL) - -endif - -###################################################################### -# badges - -STYLE=?style=plastic - - -docs/coverage.svg: docs/src/coverage.in.svg $(LOG_COVERAGE) -> inside=$$(grep TOTAL log/coverage.log | sed -E "s:.* ([0-9]+)%:\1%:g"); sed -E s:100%:$$inside:g $< >$@ - -docs/pytest.svg: docs/src/pytest.in.svg $(LOG_TESTS) -> inside=$$(grep "^[0-9]" $(LOG_TESTS)); sed -E s:XXX:$$inside:g $< >$@ - -docs/mit.svg: docs/src/mit.in.svg -> cp $< $@ - - +> $(PR) python tools/makestdvars.py --html=$@ ####################################################################### # lints -$(LOG_DIR)/%.llog : $(LINTABLE_SRC) +LINTOUTS = $(patsubst %,$(LOG_DIR)/%.lintout, $(LINTS)) + +$(LOG_DIR)/%.lintout : $(LINTABLE_SRC) > @ # run lint over p2g directory -> $(PR) $* p2g | tee $@ +> $(PR) $* p2g tools | tee $@ # use all lintlogs to make one big one. -$(LOG_LINT) : $(LOG_LINTS) -> @ cat $^ > $@ +$(LOG_LINTS) : $(LINTOUTS) +> cat $^ > $@ + +lint : $(LOG_LINTS) +> cat $(LOG_LINTS) ###################################################################### # Tests -$(LOG_TESTS): $(ALL_P2G_SRC) $(ALL_TEST_SRC) $(ALL_EXAMPLES) +$(LOG_COVERAGE) $(LOG_TESTS) &: $(ALL_P2G_SRC) $(ALL_TEST_SRC) $(EXAMPLES) > $(HR) > $(H1) pytest. -> $(RUN_PYTEST) | tee $(LOG_TESTS) - -$(LOG_COVERAGE): $(LOG_TESTS) -> $(RUN_COVERAGE) lcov -q -> $(RUN_COVERAGE) report | tee $@ +> $(PR) pytest | tee $(LOG_TESTS) +> $(PR) coverage lcov -q +> $(PR) coverage report | tee $(LOG_COVERAGE) > $(HR) -###################################################################### -# make a release : build the distribution .tar for pip -# test it for sanity - -# want to distribute docs and examples, so copy -# into src tree just while the packager is busy. -$(DIST_FILE) $(LOG_DIST) &: $(IN_DIST) -> $(HR) -> $(H1) "Make dist" -> rsync docs/*.* p2g/docs -> rsync examples/* p2g/examples -> $(POETRY) build -> rm -rf p2g/examples -> rm -rf p2g/docs -> tar ztvf $(DIST_FILE) > $(LOG_DIST) - - - - -######################################################################$ - - -# make sure everything in dist is in makefile and viceversa. -# a dist tar file has elements like this: -# -rwxr-xr-x 0/0 9790 2023-07-22 22:06 p2g-0.2.220/p2g/walkstat.py -# dist with doc in top/p2g/doc, but in the tree as top/doc etc. -# we mess with the paths to make them match up with our tree. -# and remove junk, then compare with what we have. -# any differences need to be investigated. - -$(LOG_DISTGOT) : $(DIST_FILE) -> $(HR) -> $(H1) Comparing expected and actual distribution. -> tar tzvf $(DIST_FILE) \ -| sed -E 'sX.*[0-9][0-9]:[[:digit:]]{2} [^/]+/XXg' \ -| egrep -v "(pyproject.toml|PKG-INFO)" \ -| sort > $(LOG_DISTGOT) - - -$(LOG_DISTWANT) : $(IN_DIST) -> $(H2) Make $(LOG_DISTWANT) -> echo $(IN_DIST) \ -| sed -E "s:(examples|docs)/:p2g/\\1/:g" \ -| xargs -n 1 \ -| sort > $(LOG_DISTWANT) - -$(LOG_DISTDIFFS) : $(LOG_DISTWANT) $(LOG_DISTGOT) -> $(H1) Compare want with got -> $(H2) "BOTH COLUMNS SHOULD BE SAME" > $(DISTDIFFS_ERROR) -> @ printf "%9s%40s\n" "***WANT***" "***GOT***" >> $(DISTDIFFS_ERROR) -> @ sdiff -w 70 $(LOG_DISTWANT) $(LOG_DISTGOT) >> $(DISTDIFFS_ERROR) -> diff -u $(LOG_DISTWANT) $(LOG_DISTGOT) -> $(H1) All OK -> mv $(DISTDIFFS_ERROR) $(LOG_DISTDIFFS) -> $(HR) +tests: $(LOG_TESTS) +> cat $(LOG_TESTS) - -$(LOG_TOX) : $(DIST_FILE) -> $(PR) tox --installpkg $(DIST_FILE) | tee $@ +###################################################################### +# build release from a dummy tree +# copy only things explicityly named here. + +$(DIST_FILE) : $(IN_DIST) +> rm -rf $(STAGING_DIR) +> mkdir -p $(STAGING_DIR) +> tar cf - $(IN_DIST) | tar -C $(STAGING_DIR) -xf - +> mv $(STAGING_DIR)/docs $(STAGING_DIR)/p2g +> mv $(STAGING_DIR)/examples $(STAGING_DIR)/p2g +> cp pyproject.toml $(STAGING_DIR) +> (cd $(STAGING_DIR); poetry build) +> mv $(STAGING_DIR)/dist/* dist + +tox : $(DIST_FILE) +> $(PR) tox --installpkg $(DIST_FILE) ########## release: -> gh release create v$(THIS_VERSION) --notes="release v$(THIS_VERSION)" - -newwork: -> git fetch origin -> - git branch -C dev$(THIS_VERSION) origin/main -> git push origin dev$(THIS_VERSION) -tagit: -> git fetch origin -> git tag -a v$(THIS_VERSION) -m "release v$(THIS_VERSION)" -> git push origin v$(THIS_VERSION) - -togithub : -> git commit --allow-empty -m v$(THIS_VERSION) -a -#> git tag v$(THIS_VERSION) -> git push $(T) -> git push --tags $(T) --force - +> gh release create v$(VERSION) --notes="release v$(VERSION)" ###################################################################### # cleanup stuff -########## -.PHONY: + isort:$(LINTABLE_SRC) > $(PR) isort $^ -########## -.PHONY: + ssort:$(LINTABLE_SRC) -> - $(PR) ssort $^ -########## -.PHONY: +> - $(PR) ssort $^ + autopep8:$(LINTABLE_SRC) > $(PR) autopep8 --in-place $^ -########## -.PHONY: + black:$(LINTABLE_SRC) > $(PR) black $^ -########## -.PHONY: + autoflake:$(LINTABLE_SRC) > $(PR) autoflake --ignore-init-module-imports --remove-all-unused-imports -i -v $^ -########## -.PHONY: -cleanup: isort ssort black + +cleanup: isort ssort black autopep8 ###################################################################### # utils -.PHONY: + clean: > if [ $$(which p2g) ] ; then rm -f $$(which p2g); fi > git clean -fdx + ###################################################################### +# DOC + +# for rebuilding doc, may never need it +EMACS := emacs +OX_GFM := ~/.emacs.d/straight/build/ox-gfm/ox-gfm.el + +CAN_EMACS := YES + +ifeq ($(wildcard $(OX_GFM)),) +CAN_EMACS := NO +endif +ifeq ($(wildcard $(shell which $(EMACS))),) +CAN_EMACS := NO +endif + +ifeq ($(CAN_EMACS),NO) +docs/%.txt docs/%.md: docs/src/%.org $(ALLORGS) +> $(HR) +> $(HR) +> $(H0) "DOC not being rebuilt, needs emacs and ox-gfm." +> touch $@ +else +# readme.md and howto.md from .org +EVAL = \ + $(EMACS) $(abspath $<) \ + -q -Q \ + --chdir $(dir $(abspath $<)) \ + -L $(dir $(OX_GFM)) \ + --batch \ + --load $(abspath tools/org-to-x.el) \ + -f org-to-any \ + $(abspath $@) + +docs/howto.txt : docs/src/howto.org $(ALL_ORGS) docs/haas.txt +> $(PR) python tools/fakeorg.py $(dir $<) +> $(EVAL) + +%.md docs/%.md: docs/src/%.org docs/howto.txt docs/haas.txt +> $(EVAL) + +endif + ###################################################################### +# badges +docs/coverage.svg: docs/src/coverage.in.svg $(LOG_COVERAGE) +> $(H1) Make $@ +> @ inside=$$(grep TOTAL $(LOG_COVERAGE) | sed -E "s:.* ([0-9]+)%:\1%:g"); sed -E s:100%:$$inside:g $< >$@ + +docs/pytest.svg: docs/src/pytest.in.svg $(LOG_TESTS) +> $(H1) Make $@ +> @ inside=$$(grep "^[0-9]" $(LOG_TESTS)); sed -E s:XXX:$$inside:g $< >$@ + +docs/mit.svg: docs/src/mit.in.svg +> $(H1) Make $@ +> @ cp $< $@ + +###################################################################### + + #for my machine. telnet: @@ -564,8 +413,11 @@ help: > python -m p2g - msv: > python tools/makestdvars.py --dpy=- -example: -> python -m p2g examples/fasterviceceneter.py + +.PHONY:aexample pdb +aexample: +> echo HIU +> python -m p2g help version #--job=O123 examples/vicecenter.py apytest: > poetry run pytest tests/test_dprnt.py @@ -580,6 +432,8 @@ mtest: tmodversion: > python tools/modversion.py --truth $(VERSION_FILE) --top . --out .build --names $(VERSIONED_FILES) +fakeorg: +> python docs/src/fakeorg.py docs/src/fish.org > justt: > poetry run p2g t.py @@ -589,15 +443,9 @@ justt: #pdb: btest #pdb: mdc #pdb: fakeorg -pdb:example +pdb: aexample -# T=tests/test_assert.py -# T=tests/test_badpytest.py -# T=tests/test_vector.py -# T=tests/test_axis.py -ARGS=--pdb -RUNNER=poetry run pytest sxpdb: @@ -612,3 +460,20 @@ p: # Local Variables: # makefile-backslash-column:20 # End: + + +###################################################################### +newwork: +> git fetch origin +> - git branch -C dev$(VERSION) origin/main +> git push origin dev$(VERSION) +tagit: +> git fetch origin +> git tag -a v$(VERSION) -m "release v$(VERSION)" +> git push origin v$(VERSION) + +togithub : +> git commit --allow-empty -m v$(VERSION) -a +#> git tag v$(VERSION) +> git push $(T) +> git push --tags $(T) --force diff --git a/docs/coverage.svg b/docs/coverage.svg index d659e878..19479fb0 100644 --- a/docs/coverage.svg +++ b/docs/coverage.svg @@ -1,4 +1,4 @@ - + coverage: 100% @@ -8,12 +8,12 @@ - + - - - + + + + +
+ # Introduction -## Version 0.3.7 +## Version 0.3.13 P2G makes it simple to ensure that parts are in fixtures correctly, coordinate systems are adjusted to deal with stock placement and cope with movement and rotation of workpieces through multiple operations. @@ -20,20 +22,22 @@ It comes with a set of macro variable definitions for a Haas mill with NCD. And 1. [Introduction](#introduction) 2. [Install](#install) 3. [Usage](#usage) -4. [Demo.](#vdemo) +4. [Demo](#demo) 5. [Examples](#examples) 6. [Variables](#variables) 7. [Coordinates](#coordinates) -8. [Goto](#goto) -9. [Axes](#axes) -10. [When](#when) -11. [DPRNT](#dprnt) -12. [Symbol Tables](#symboltables) -13. [Notes](#notes) -14. [MIT License](#mit) -15. [Authors](#authors) -16. [Thanks](#thanks) -17. [Haas macro variables](#haas) +8. [Expressions](#expressions) +9. [Goto](#goto) +10. [Axes](#axes) +11. [When](#when) +12. [DPRNT](#dprnt) +13. [Symbol Tables](#symbol-tables) +14. [Notes](#notes) +15. [Maintenance options](#maintenance-options) +16. [MIT License](#mit-license) +17. [Authors](#authors) +18. [Thanks](#thanks) +19. [Haas macrovars](#haas-macrovars) # Install @@ -54,7 +58,7 @@ $ pip install p2g ### fetch dependencies, rebuild and install with pip ``` -$ git clone https://github.com/0x5ac/attempt1 p2g +$ git clone https://github.com/0x5ac/p2g p2g $ cd p2g $ make install ``` @@ -63,7 +67,7 @@ $ make install ### fetch dependencies and rebuild ``` -$ git clone https://github.com/0x5ac/attempt1 p2g +$ git clone https://github.com/0x5ac/p2g p2g $ cd p2g $ make ``` @@ -71,19 +75,14 @@ $ make # Usage -```python - -``` - ``` p2g - Turn Python into G-Code. Usage: p2g [options] [] p2g help [ all | topics | maint | version | location | ] - p2g examples + p2g build-examples - For bare p2g: p2g tram-rotary.py ~/_nc_/O{countdown}tr.nc Makes an output of the form ~/_nc_/O1234tr.nc @@ -91,9 +90,8 @@ Usage: Read from stdin, look for the 'thisone' function and write to to stdout. - Arguments: - Source python file. [default: stdin] + Source python file. Destination G-Code file. [default: stdout] {countdown} in file name creates a decrementing prefix for the output file which makes looking for the .nc in @@ -103,14 +101,10 @@ Arguments: [ all | topics | maint | version | location | ] all Print all readme. topics List all topics. - maint Print maintenance options. version Show version - location Show absdir of main + location Show absdir of main module. Print from readme starting at topic. - - - Options: --job= Olabel for output code. --function= Function to be compiled, @@ -119,14 +113,13 @@ Options: makes text fit more easily into a narrow program window. --short-filenames Emit just the lsb of filenames. + ``` -# Demo. +# Demo - - - +[![img](https://github.com/0x5ac/p2g/blob/main/docs/png/vicecenter1.png)](https://youtu.be/PX818-iRb1Q) # Examples @@ -157,7 +150,7 @@ def simple_demo(): " ⇨ `directly` ⇨ ``` -O0001 (simple_demo: 0.3.7) +O00001 (simple_demo: 0.3.13) #100= 199. ( x = Var[199] ) #102= 0. ( for y in range[10]: ) N1000 @@ -184,7 +177,7 @@ import p2g def maxflutes(): mx_flutes = p2g.Var(p2g.haas.TOOL_TBL_FLUTES[0]) - for n_flutes in p2g.haas.TOOL_TBL_FLUTES: + for n_flutes in p2g.haas.TOOL_TBL_FLUTES[1:]: if n_flutes > mx_flutes: mx_flutes = n_flutes @@ -195,11 +188,11 @@ def maxflutes(): ⇨ `p2g maxflutes.py` ⇨ ``` -O0001 (maxflutes: 0.3.7) +O00001 (maxflutes: 0.3.13) #100= #1601 ( mx_flutes = Var[haas.TOOL_TBL_FLUTES[0]]) - #101= 1601. ( for n_flutes in haas.TOOL_TBL_FLUTES:) + #101= 1602. ( for n_flutes in haas.TOOL_TBL_FLUTES[1:]:) N1000 - IF [#101 GE 1801.] GOTO 1002 ( for n_flutes in haas.TOOL_TBL_FLUTES:) + IF [#101 GE 1801.] GOTO 1002 ( for n_flutes in haas.TOOL_TBL_FLUTES[1:]:) IF [#[#101] LE #100] GOTO 1003 ( if n_flutes > mx_flutes: ) #100= #[#101] ( mx_flutes = n_flutes ) GOTO 1004 @@ -263,7 +256,7 @@ def less_trivial(): ⇨ `p2g less_trival.py` ⇨ ``` -O0001 (less_trivial: 0.3.7) +O00001 (less_trivial: 0.3.13) #100= 2. ( cursor = Var[3][2, 3, 4] ) #101= 3. #102= 4. @@ -303,7 +296,7 @@ Example: ```python -from p2g import * # this is the common header +from p2g import * def variables(): # On my machine, Renishaw skip positions are @@ -329,7 +322,7 @@ def variables(): ⇨ `p2g variables.py` ⇨ ``` -O0001 (variables: 0.3.7) +O00001 (variables: 0.3.13) #100= #5061 * 2. + #5041 + #5061( tmp0 = Var[skip0.xyz * 2.0 + workpos + skip1]) #101= #5062 * 2. + #5042 + #5062 #102= #5063 * 2. + #5043 + #5063 @@ -388,7 +381,7 @@ def coordinates(): ⇨ `p2g coordinates.py` ⇨ ``` -O0001 (coordinates: 0.3.7) +O00001 (coordinates: 0.3.13) ( Describe 3 variables at 3000 ) ( Fill with 1,2,31 ) #3000= 1. ( dst.var = [1, 2, 31] ) @@ -432,6 +425,74 @@ O0001 (coordinates: 0.3.7) ``` +# Expressions + +Python expressions turn into G-Code as you may expect, save that native Python uses radians for trig, and G-Code uses degrees, so folding is done in degrees. + +```python + +from p2g import * # this is the common header +from p2g.haas import * # to all the examples + +def expressions(): + com("Variables go into macro variables.") + theta = Var(0.3) + angle = Var(sin(theta)) + + com("Constants are elided in G-code.") + thetak = Const(0.3) + anglek = Var(sin(thetak)) + + com("Lots of things are folded.") + t1 = Var(2 * thetak + 7) + + com("Simple array math:") + + box_size = Const([4, 4, 2]) + tlhc = Var(-box_size / 2) + brhc = Var(box_size / 2) + diff = Var(tlhc - brhc) + + a, b, x = Var(), Var(), Var() + a = tlhc[0] / tlhc[1] + b = tlhc[0] % tlhc[1] + x = tlhc[0] & tlhc[1] + tlhc.xy = ((a - b + 3) / sin(x), (a + b + 3) / cos(x)) + +``` + +⇨ `p2g expressions.py` ⇨ + +``` +O00001 (expressions: 0.3.13) +( Variables go into macro variables. ) + #100= 0.3 ( theta = Var[0.3] ) + #101= SIN[#100] ( angle = Var[sin[theta]] ) +( Constants are elided in G-code. ) + #102= 0.0052 ( anglek = Var[sin[thetak]] ) +( Lots of things are folded. ) + #103= 7.6 ( t1 = Var[2 * thetak + 7] ) +( Simple array math: ) + #104= -2. ( tlhc = Var[-box_size / 2] ) + #105= -2. + #106= -1. + #107= 2. ( brhc = Var[box_size / 2] ) + #108= 2. + #109= 1. + #110= #104 - #107 ( diff = Var[tlhc - brhc] ) + #111= #105 - #108 + #112= #106 - #109 + #113= #104 / #105 ( a = tlhc[0] / tlhc[1] ) + #114= #104 MOD #105 ( b = tlhc[0] % tlhc[1] ) + #115= #104 AND #105 ( x = tlhc[0] & tlhc[1] ) +( tlhc.xy = [[a - b + 3] / sin[x], [a + b + 3] / cos[x]]) + #104= [#113 - #114 + 3.] / SIN[#115] + #105= [#113 + #114 + 3.] / COS[#115] + M30 +% +``` + + # Goto Goto functions are constructed from parts, and make building blocks when partially applied. @@ -494,7 +555,7 @@ def goto_demo(): ⇨ `p2g goto_demo.py` ⇨ ``` -O0001 (goto_demo: 0.3.7) +O00001 (goto_demo: 0.3.13) ( in work cosys, goto x=1, y=2, z=3 at 20ips ) G90 G01 G55 F20. x1. y2. z3. ( g1[1, 2, 3] ) @@ -579,7 +640,7 @@ def axes(): ⇨ `p2g axes.py` ⇨ ``` -O0001 (axes: 0.3.7) +O00001 (axes: 0.3.13) ( rhs of vector ops get expanded as needed ) #5241= 0. ( G55.var = [0, 1] ) #5242= 1. @@ -641,7 +702,7 @@ def start(): ⇨ `p2g when_lookahead.py` ⇨ ``` -O0001 (start: 0.3.7) +O00001 (start: 0.3.13) ( turn off lookahead before the probe ) M97 P123 ( with sys.Lookahead[lookahead = False] :) @@ -705,7 +766,7 @@ def when_demo_block_delete(): ``` - O0001 (when_demo_block_delete: 0.3.7) + O0001 (when_demo_block_delete: 0.3.10) T01 M06 ( sys.load_tool[PROBE] ) G65 P9832 ( Probe on. ) #100= 9. ( tmp = Var[9] ) @@ -740,7 +801,7 @@ def dprint_constants(): ⇨ `p2g dprnt_constants.py` ⇨ - O0001 (dprint_constants: 0.3.7) + O0001 (dprint_constants: 0.3.10) DPRNT[A***12.34***2.00***3.00] DPRNT[B**12.34**2.00**3.00] DPRNT[C*a*12.340ba**2.000ba**3.000b] @@ -763,7 +824,7 @@ def dprint_vectors(): ⇨ `p2g dprnt_vectors.py` ⇨ - O0001 (dprint_vectors: 0.3.7) + O0001 (dprint_vectors: 0.3.10) DPRNT[A*#100[42]#101[42]] DPRNT[B*#100[32]#101[32]] DPRNT[C*a#100[33]ba#101[33]b] @@ -788,7 +849,7 @@ def dprnt_subs(): ⇨ `p2g dprnt_subs.py` ⇨ - O0001 (dprnt_subs: 0.3.7) + O0001 (dprnt_subs: 0.3.10) DPRNT[results:*j0#100[31],*j1#101[31]] DPRNT[results:*j0**7.3,*j1**8.1] M30 @@ -810,7 +871,7 @@ def dprnt_painless(): ⇨ `p2g dprnt_painless.py` ⇨ ``` -O0001 (dprnt_painless: 0.3.7) +O00001 (dprnt_painless: 0.3.13) #101= 0. ( for idx in range[10]: ) N1000 IF [#101 GE 10.] GOTO 1002 ( for idx in range[10]: ) @@ -842,7 +903,7 @@ def dprnt_std_python(): ⇨ `p2g dprnt_std_python.py` ⇨ ``` -O0001 (dprnt_std_python: 0.3.7) +O00001 (dprnt_std_python: 0.3.13) #100= 32. ( x = Var[32] ) #101= 27. ( y = Var[27] ) #103= 0. ( for q in range[10]: ) @@ -886,7 +947,7 @@ fish = 10 not_used = 12 def symbol_table_demo(): - p2g.Control.symbol_table = True + p2g.Control.symbol_table = True p2g.comment("Only used symbols are in output table.") p2g.Var(MACHINE_ABS_ABOVE_OTS) p2g.Var(MACHINE_ABS_ABOVE_VICE * fish) @@ -897,7 +958,7 @@ def symbol_table_demo(): ⇨ `p2g symbol_table_demo.py` ⇨ ``` -O0001 (symbol_table_demo: 0.3.7) +O00001 (symbol_table_demo: 0.3.13) ( Symbol Table ) ( MACHINE_ABS_ABOVE_OTS : -7.000, 8.000, 9.000 ) @@ -981,7 +1042,7 @@ def cool(): ⇨ `p2g cool.py` ⇨ ``` -O0001 (cool: 0.3.7) +O00001 (cool: 0.3.13) ( You can do surprising things. ) #100= 100. ( avariable_scalar = Var[100] ) #101= 7. ( another_xandy = Var[7, 8] ) @@ -1029,7 +1090,7 @@ def beware0(): ⇨ `p2g beware0.py` ⇨ ``` -O0001 (beware0: 0.3.7) +O00001 (beware0: 0.3.13) ( this moves contents of macro var 200 into 100 ) ( it doesn't rewrite a. ) #100= #200 ( a = b[0] ) @@ -1057,6 +1118,13 @@ O0001 (beware0: 0.3.7) ``` +# Maintenance options + +- `--bp` call pdb.set\_trace() on error + +- `-verbose=` changes loquacity. + + # MIT License Copyright © 2023 Steve Chamberlain @@ -1107,7 +1175,7 @@ THE SOFTWARE. ``` -# Haas macro variables +# Haas macrovars ``` HAAS Macro Variables @@ -1314,5 +1382,7 @@ THE SOFTWARE. │ #52601 … #52800 │ 200 │ V │ float │ PROBE_TYPE │ │ #52801 │ -47740 │ _ │ float │ an error │ └─────────────────┴────────┴────┴─────────────┴───────────────────────────┘ - Generated by /home/sac/vf3/progs/p2g/tools/makestdvars.py -``` \ No newline at end of file + Generated by /home/sac/vf3/p2g/tools/makestdvars.py +``` + +o x \ No newline at end of file diff --git a/docs/howto.txt b/docs/howto.txt index 783cc729..46f16411 100644 --- a/docs/howto.txt +++ b/docs/howto.txt @@ -8,8 +8,8 @@ 1 Introduction ══════════════ -Version 0.3.7 -───────────── +Version 0.3.13 +────────────── P2G makes it simple to ensure that parts are in fixtures correctly, coordinate systems are adjusted to deal with stock placement and cope @@ -32,20 +32,22 @@ Version 0.3.7 1. Introduction 2. Install 3. Usage - 4. Demo. + 4. Demo 5. Examples 6. Variables 7. Coordinates - 8. Goto - 9. Axes - 10. When - 11. DPRNT - 12. Symbol Tables - 13. Notes - 14. MIT License - 15. Authors - 16. Thanks - 17. Haas macro variables + 8. Expressions + 9. Goto + 10. Axes + 11. When + 12. DPRNT + 13. Symbol Tables + 14. Notes + 15. Maintenance options + 16. MIT License + 17. Authors + 18. Thanks + 19. Haas macrovars 2 Install @@ -68,7 +70,7 @@ fetch dependencies, rebuild and install with pip ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┌──── - │ $ git clone https://github.com/0x5ac/attempt1 p2g + │ $ git clone https://github.com/0x5ac/p2g p2g │ $ cd p2g │ $ make install └──── @@ -78,7 +80,7 @@ fetch dependencies and rebuild ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┌──── - │ $ git clone https://github.com/0x5ac/attempt1 p2g + │ $ git clone https://github.com/0x5ac/p2g p2g │ $ cd p2g │ $ make └──── @@ -87,19 +89,14 @@ fetch dependencies and rebuild 3 Usage ═══════ - ┌──── - - └──── - ┌──── │ p2g - Turn Python into G-Code. │ │ Usage: │ p2g [options] [] │ p2g help [ all | topics | maint | version | location | ] - │ p2g examples + │ p2g build-examples │ - │ For bare p2g: │ p2g tram-rotary.py ~/_nc_/O{countdown}tr.nc │ Makes an output of the form ~/_nc_/O1234tr.nc │ @@ -107,9 +104,8 @@ fetch dependencies and rebuild │ Read from stdin, look for the 'thisone' function and write to │ to stdout. │ - │ │ Arguments: - │ Source python file. [default: stdin] + │ Source python file. │ Destination G-Code file. [default: stdout] │ {countdown} in file name creates a decrementing prefix │ for the output file which makes looking for the .nc in @@ -119,14 +115,10 @@ fetch dependencies and rebuild │ [ all | topics | maint | version | location | ] │ all Print all readme. │ topics List all topics. - │ maint Print maintenance options. │ version Show version - │ location Show absdir of main + │ location Show absdir of main module. │ Print from readme starting at topic. │ - │ - │ - │ │ Options: │ --job= Olabel for output code. │ --function= Function to be compiled, @@ -135,11 +127,18 @@ fetch dependencies and rebuild │ makes text fit more easily into │ a narrow program window. │ --short-filenames Emit just the lsb of filenames. + │ └──── -4 Demo. -═══════ +4 Demo +══════ + + [https://github.com/0x5ac/p2g/blob/main/docs/png/vicecenter1.png] + + +[https://github.com/0x5ac/p2g/blob/main/docs/png/vicecenter1.png] + 5 Examples @@ -169,7 +168,7 @@ Simple demo " ⇨ `directly' ⇨ ┌──── - │ O0001 (simple_demo: 0.3.7) + │ O00001 (simple_demo: 0.3.13) │ #100= 199. ( x = Var[199] ) │ #102= 0. ( for y in range[10]: ) │ N1000 @@ -197,7 +196,7 @@ Find largest number of flutes in tool table │ def maxflutes(): │ │ mx_flutes = p2g.Var(p2g.haas.TOOL_TBL_FLUTES[0]) - │ for n_flutes in p2g.haas.TOOL_TBL_FLUTES: + │ for n_flutes in p2g.haas.TOOL_TBL_FLUTES[1:]: │ if n_flutes > mx_flutes: │ mx_flutes = n_flutes │ @@ -206,11 +205,11 @@ Find largest number of flutes in tool table └──── ⇨ `p2g maxflutes.py' ⇨ ┌──── - │ O0001 (maxflutes: 0.3.7) + │ O00001 (maxflutes: 0.3.13) │ #100= #1601 ( mx_flutes = Var[haas.TOOL_TBL_FLUTES[0]]) - │ #101= 1601. ( for n_flutes in haas.TOOL_TBL_FLUTES:) + │ #101= 1602. ( for n_flutes in haas.TOOL_TBL_FLUTES[1:]:) │ N1000 - │ IF [#101 GE 1801.] GOTO 1002 ( for n_flutes in haas.TOOL_TBL_FLUTES:) + │ IF [#101 GE 1801.] GOTO 1002 ( for n_flutes in haas.TOOL_TBL_FLUTES[1:]:) │ IF [#[#101] LE #100] GOTO 1003 ( if n_flutes > mx_flutes: ) │ #100= #[#101] ( mx_flutes = n_flutes ) │ GOTO 1004 @@ -274,7 +273,7 @@ Less trivial example ⇨ `p2g less_trival.py' ⇨ ┌──── - │ O0001 (less_trivial: 0.3.7) + │ O00001 (less_trivial: 0.3.13) │ #100= 2. ( cursor = Var[3][2, 3, 4] ) │ #101= 3. │ #102= 4. @@ -315,7 +314,7 @@ Less trivial example Example: ┌──── │ - │ from p2g import * # this is the common header + │ from p2g import * │ │ def variables(): │ # On my machine, Renishaw skip positions are @@ -339,7 +338,7 @@ Less trivial example └──── ⇨ `p2g variables.py' ⇨ ┌──── - │ O0001 (variables: 0.3.7) + │ O00001 (variables: 0.3.13) │ #100= #5061 * 2. + #5041 + #5061( tmp0 = Var[skip0.xyz * 2.0 + workpos + skip1]) │ #101= #5062 * 2. + #5042 + #5062 │ #102= #5063 * 2. + #5043 + #5063 @@ -398,7 +397,7 @@ Less trivial example └──── ⇨ `p2g coordinates.py' ⇨ ┌──── - │ O0001 (coordinates: 0.3.7) + │ O00001 (coordinates: 0.3.13) │ ( Describe 3 variables at 3000 ) │ ( Fill with 1,2,31 ) │ #3000= 1. ( dst.var = [1, 2, 31] ) @@ -442,7 +441,76 @@ Less trivial example └──── -8 Goto +8 Expressions +═════════════ + + Python expressions turn into G-Code as you may expect, save that + native Python uses radians for trig, and G-Code uses degrees, so + folding is done in degrees. + + ┌──── + │ + │ from p2g import * # this is the common header + │ from p2g.haas import * # to all the examples + │ + │ def expressions(): + │ com("Variables go into macro variables.") + │ theta = Var(0.3) + │ angle = Var(sin(theta)) + │ + │ com("Constants are elided in G-code.") + │ thetak = Const(0.3) + │ anglek = Var(sin(thetak)) + │ + │ com("Lots of things are folded.") + │ t1 = Var(2 * thetak + 7) + │ + │ com("Simple array math:") + │ + │ box_size = Const([4, 4, 2]) + │ tlhc = Var(-box_size / 2) + │ brhc = Var(box_size / 2) + │ diff = Var(tlhc - brhc) + │ + │ a, b, x = Var(), Var(), Var() + │ a = tlhc[0] / tlhc[1] + │ b = tlhc[0] % tlhc[1] + │ x = tlhc[0] & tlhc[1] + │ tlhc.xy = ((a - b + 3) / sin(x), (a + b + 3) / cos(x)) + │ + └──── + ⇨ `p2g expressions.py' ⇨ + ┌──── + │ O00001 (expressions: 0.3.13) + │ ( Variables go into macro variables. ) + │ #100= 0.3 ( theta = Var[0.3] ) + │ #101= SIN[#100] ( angle = Var[sin[theta]] ) + │ ( Constants are elided in G-code. ) + │ #102= 0.0052 ( anglek = Var[sin[thetak]] ) + │ ( Lots of things are folded. ) + │ #103= 7.6 ( t1 = Var[2 * thetak + 7] ) + │ ( Simple array math: ) + │ #104= -2. ( tlhc = Var[-box_size / 2] ) + │ #105= -2. + │ #106= -1. + │ #107= 2. ( brhc = Var[box_size / 2] ) + │ #108= 2. + │ #109= 1. + │ #110= #104 - #107 ( diff = Var[tlhc - brhc] ) + │ #111= #105 - #108 + │ #112= #106 - #109 + │ #113= #104 / #105 ( a = tlhc[0] / tlhc[1] ) + │ #114= #104 MOD #105 ( b = tlhc[0] % tlhc[1] ) + │ #115= #104 AND #105 ( x = tlhc[0] & tlhc[1] ) + │ ( tlhc.xy = [[a - b + 3] / sin[x], [a + b + 3] / cos[x]]) + │ #104= [#113 - #114 + 3.] / SIN[#115] + │ #105= [#113 + #114 + 3.] / COS[#115] + │ M30 + │ % + └──── + + +9 Goto ══════ Goto functions are constructed from parts, and make building blocks @@ -505,7 +573,7 @@ Less trivial example └──── ⇨ `p2g goto_demo.py' ⇨ ┌──── - │ O0001 (goto_demo: 0.3.7) + │ O00001 (goto_demo: 0.3.13) │ │ ( in work cosys, goto x=1, y=2, z=3 at 20ips ) │ G90 G01 G55 F20. x1. y2. z3. ( g1[1, 2, 3] ) @@ -543,8 +611,8 @@ Less trivial example └──── -9 Axes -══════ +10 Axes +═══════ Any number of axes are supported, default just being xy and z. @@ -591,7 +659,7 @@ Less trivial example └──── ⇨ `p2g axes.py' ⇨ ┌──── - │ O0001 (axes: 0.3.7) + │ O00001 (axes: 0.3.13) │ ( rhs of vector ops get expanded as needed ) │ #5241= 0. ( G55.var = [0, 1] ) │ #5242= 1. @@ -623,7 +691,7 @@ Less trivial example └──── -10 When +11 When ═══════ 'when' works as in python, save there are no exceptions; useful for @@ -655,7 +723,7 @@ Setting and resetting lookahead. └──── ⇨ `p2g when_lookahead.py' ⇨ ┌──── - │ O0001 (start: 0.3.7) + │ O00001 (start: 0.3.13) │ │ ( turn off lookahead before the probe ) │ M97 P123 ( with sys.Lookahead[lookahead = False] :) @@ -721,7 +789,7 @@ Setting and resetting lookahead. └──── ┌──── - │ O0001 (when_demo_block_delete: 0.3.7) + │ O0001 (when_demo_block_delete: 0.3.10) │ T01 M06 ( sys.load_tool[PROBE] ) │ G65 P9832 ( Probe on. ) │ #100= 9. ( tmp = Var[9] ) @@ -733,7 +801,7 @@ Setting and resetting lookahead. └──── -11 DPRNT +12 DPRNT ════════ P2G turns Python f string into runes that DPRNT can digest. @@ -758,7 +826,7 @@ Constants └──── ⇨ `p2g dprnt_constants.py' ⇨ ┌──── - │ O0001 (dprint_constants: 0.3.7) + │ O0001 (dprint_constants: 0.3.10) │ DPRNT[A***12.34***2.00***3.00] │ DPRNT[B**12.34**2.00**3.00] │ DPRNT[C*a*12.340ba**2.000ba**3.000b] @@ -782,7 +850,7 @@ Vectors └──── ⇨ `p2g dprnt_vectors.py' ⇨ ┌──── - │ O0001 (dprint_vectors: 0.3.7) + │ O0001 (dprint_vectors: 0.3.10) │ DPRNT[A*#100[42]#101[42]] │ DPRNT[B*#100[32]#101[32]] │ DPRNT[C*a#100[33]ba#101[33]b] @@ -808,7 +876,7 @@ In subroutines. └──── ⇨ `p2g dprnt_subs.py' ⇨ ┌──── - │ O0001 (dprnt_subs: 0.3.7) + │ O0001 (dprnt_subs: 0.3.10) │ DPRNT[results:*j0#100[31],*j1#101[31]] │ DPRNT[results:*j0**7.3,*j1**8.1] │ M30 @@ -830,7 +898,7 @@ So painless. └──── ⇨ `p2g dprnt_painless.py' ⇨ ┌──── - │ O0001 (dprnt_painless: 0.3.7) + │ O00001 (dprnt_painless: 0.3.13) │ #101= 0. ( for idx in range[10]: ) │ N1000 │ IF [#101 GE 10.] GOTO 1002 ( for idx in range[10]: ) @@ -861,7 +929,7 @@ Can use Python f-strings too. └──── ⇨ `p2g dprnt_std_python.py' ⇨ ┌──── - │ O0001 (dprnt_std_python: 0.3.7) + │ O00001 (dprnt_std_python: 0.3.13) │ #100= 32. ( x = Var[32] ) │ #101= 27. ( y = Var[27] ) │ #103= 0. ( for q in range[10]: ) @@ -899,7 +967,7 @@ Extended f-string syntax As an «e-string», but only expanded between items. -12 Symbol Tables +13 Symbol Tables ════════════════ Set the global `p2g.Control.symbol_table' to get a symbol table in the @@ -916,7 +984,7 @@ Extended f-string syntax │ not_used = 12 │ │ def symbol_table_demo(): - │ p2g.Control.symbol_table = True + │ p2g.Control.symbol_table = True │ p2g.comment("Only used symbols are in output table.") │ p2g.Var(MACHINE_ABS_ABOVE_OTS) │ p2g.Var(MACHINE_ABS_ABOVE_VICE * fish) @@ -925,7 +993,7 @@ Extended f-string syntax └──── ⇨ `p2g symbol_table_demo.py' ⇨ ┌──── - │ O0001 (symbol_table_demo: 0.3.7) + │ O00001 (symbol_table_demo: 0.3.13) │ ( Symbol Table ) │ │ ( MACHINE_ABS_ABOVE_OTS : -7.000, 8.000, 9.000 ) @@ -949,7 +1017,7 @@ Extended f-string syntax └──── -13 Notes +14 Notes ════════ Stuff you already know @@ -1015,7 +1083,7 @@ Cool example └──── ⇨ `p2g cool.py' ⇨ ┌──── - │ O0001 (cool: 0.3.7) + │ O00001 (cool: 0.3.13) │ ( You can do surprising things. ) │ #100= 100. ( avariable_scalar = Var[100] ) │ #101= 7. ( another_xandy = Var[7, 8] ) @@ -1062,7 +1130,7 @@ Beware └──── ⇨ `p2g beware0.py' ⇨ ┌──── - │ O0001 (beware0: 0.3.7) + │ O00001 (beware0: 0.3.13) │ ( this moves contents of macro var 200 into 100 ) │ ( it doesn't rewrite a. ) │ #100= #200 ( a = b[0] ) @@ -1090,7 +1158,15 @@ Beware └──── -14 MIT License +15 Maintenance options +══════════════════════ + + ‣ `--bp' call pdb.set_trace() on error + + ‣ `-verbose=' changes loquacity. + + +16 MIT License ══════════════ Copyright © 2023 Steve Chamberlain @@ -1115,13 +1191,13 @@ Beware WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -15 Authors +17 Authors ══════════ sac@pobox.com -16 Thanks +18 Thanks ═════════ all the good parts of walk*.py are from: @@ -1156,8 +1232,8 @@ Beware └──── -17 Haas macro variables -═══════════════════════ +19 Haas macrovars +═════════════════ ┌──── │ HAAS Macro Variables @@ -1364,5 +1440,6 @@ Beware │ │ #52601 … #52800 │ 200 │ V │ float │ PROBE_TYPE │ │ │ #52801 │ -47740 │ _ │ float │ an error │ │ └─────────────────┴────────┴────┴─────────────┴───────────────────────────┘ - │ Generated by /home/sac/vf3/progs/p2g/tools/makestdvars.py + │ Generated by /home/sac/vf3/p2g/tools/makestdvars.py └──── + o x diff --git a/docs/mit.svg b/docs/mit.svg index 4015dd53..da9fcb81 100644 --- a/docs/mit.svg +++ b/docs/mit.svg @@ -1 +1,29 @@ -license: MITlicenseMIT \ No newline at end of file + + + license: MIT + + + + + + + + + + + + + + + + + + license + + + MIT + + + diff --git a/docs/pytest.svg b/docs/pytest.svg index cdc977da..2b2fac96 100644 --- a/docs/pytest.svg +++ b/docs/pytest.svg @@ -1,5 +1,5 @@ - + pytest: 100.0% @@ -9,12 +9,12 @@ - + - - - + + + + +
+ #+END_EXPORT diff --git a/docs/src/coordinates.org b/docs/src/coordinates.org index 47392a7b..7a27cf67 100644 --- a/docs/src/coordinates.org +++ b/docs/src/coordinates.org @@ -47,7 +47,7 @@ def coordinates(): ⇨ ~p2g coordinates.py~ ⇨ #+results: coordinates1 #+begin_example -O0001 (coordinates: 0.3.7) +O00001 (coordinates: 0.3.13) ( Describe 3 variables at 3000 ) ( Fill with 1,2,31 ) #3000= 1. ( dst.var = [1, 2, 31] ) diff --git a/docs/src/coverage.in.svg b/docs/src/coverage.in.svg index d659e878..19479fb0 100644 --- a/docs/src/coverage.in.svg +++ b/docs/src/coverage.in.svg @@ -1,4 +1,4 @@ - + coverage: 100% @@ -8,12 +8,12 @@ - + - - - + + + - - -#+END_EXPORT +[[https://youtu.be/PX818-iRb1Q][https://github.com/0x5ac/p2g/blob/main/docs/png/vicecenter1.png]] diff --git a/docs/src/when.org b/docs/src/when.org index ed9bf5a5..541c5082 100644 --- a/docs/src/when.org +++ b/docs/src/when.org @@ -33,7 +33,7 @@ def start(): ⇨ ~p2g when_lookahead.py~ ⇨ #+RESULTS: when_lookahead #+begin_example -O0001 (start: 0.3.7) +O00001 (start: 0.3.13) ( turn off lookahead before the probe ) M97 P123 ( with sys.Lookahead[lookahead = False] :) @@ -100,7 +100,7 @@ def when_demo_block_delete(): #+end_src #+RESULTS: when_demo_block_delete -: O0001 (when_demo_block_delete: 0.3.7) +: O0001 (when_demo_block_delete: 0.3.10) : T01 M06 ( sys.load_tool[PROBE] ) : G65 P9832 ( Probe on. ) : #100= 9. ( tmp = Var[9] ) diff --git a/examples/maxflutes.nc b/examples/maxflutes.nc index 6c1131f3..59d21563 100644 --- a/examples/maxflutes.nc +++ b/examples/maxflutes.nc @@ -1,8 +1,8 @@ O00001 (maxflutes) #100= #1601 ( mx_flutes = Var[haas.TOOL_TBL_FLUTES[0]]) - #101= 1601. ( for n_flutes in haas.TOOL_TBL_FLUTES:) + #101= 1602. ( for n_flutes in haas.TOOL_TBL_FLUTES[1:]:) N1000 - IF [#101 GE 1801.] GOTO 1002 ( for n_flutes in haas.TOOL_TBL_FLUTES:) + IF [#101 GE 1801.] GOTO 1002 ( for n_flutes in haas.TOOL_TBL_FLUTES[1:]:) IF [#[#101] LE #100] GOTO 1003 ( if n_flutes > mx_flutes: ) #100= #[#101] ( mx_flutes = n_flutes ) GOTO 1004 @@ -13,4 +13,4 @@ N1004 N1002 #3006= #100 ( haas.MESSAGE.var = mx_flutes ) M30 -% \ No newline at end of file +% diff --git a/examples/maxflutes.py b/examples/maxflutes.py index a1d2f348..8a15173c 100644 --- a/examples/maxflutes.py +++ b/examples/maxflutes.py @@ -7,7 +7,7 @@ def maxflutes(): mx_flutes = p2g.Var(p2g.haas.TOOL_TBL_FLUTES[0]) - for n_flutes in p2g.haas.TOOL_TBL_FLUTES: + for n_flutes in p2g.haas.TOOL_TBL_FLUTES[1:]: if n_flutes > mx_flutes: mx_flutes = n_flutes diff --git a/examples/probecalibrate.nc b/examples/probecalibrate.nc index cdb41156..e3ff7e91 100644 --- a/examples/probecalibrate.nc +++ b/examples/probecalibrate.nc @@ -45,4 +45,4 @@ O00001 (probecalibrate) G90 G53 G01 G55 F600. x0. y0. G65 P9833 ( Probe off. ) M30 -% \ No newline at end of file +% diff --git a/examples/vicecenter.nc b/examples/vicecenter.nc index 69eee4b5..0a198a73 100644 --- a/examples/vicecenter.nc +++ b/examples/vicecenter.nc @@ -285,4 +285,4 @@ N123 G04 P1 G04 P1 M99 -% \ No newline at end of file +% diff --git a/license.md b/license.md index d3f6e71e..6c8bac01 100644 --- a/license.md +++ b/license.md @@ -1,9 +1,27 @@ + +# Table of Contents + + + MIT License -Copyright © 2023 Steve Chamberlain +Copyright © 2023 Stephen Chamberlain + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/p2g/VERSION b/p2g/VERSION index 0f826853..e4737652 100644 --- a/p2g/VERSION +++ b/p2g/VERSION @@ -1 +1 @@ -0.3.7 +0.3.13 diff --git a/p2g/__init__.py b/p2g/__init__.py index 6126ad0d..cc292782 100755 --- a/p2g/__init__.py +++ b/p2g/__init__.py @@ -66,4 +66,4 @@ "sqrt", "tan", ] -VERSION = "0.3.7" +VERSION = "0.3.13" diff --git a/p2g/abandon.py b/p2g/abandon.py new file mode 100644 index 00000000..46d8779c --- /dev/null +++ b/p2g/abandon.py @@ -0,0 +1,141 @@ +import ast +import pathlib +import re +import sys + +from p2g import axis +from p2g import err +from p2g import gbl +from p2g import stat +from p2g import symbol +from p2g import VERSION +from p2g import walkfunc + + +def find_desc(walker, func_name, srcpath): + try: + fncdef = walker.ns[func_name] + desc = fncdef(walkfunc.Marker()) + except KeyError as exn: + raise err.CompilerError( + f"No such function '{func_name}' in '{srcpath}'." + ) from exn + return desc + + +def find_defined_funcs(sourcelines): + for line in sourcelines: + # find last line with def in it, that's the function we need + mares = re.match("def (.*?)\\(", line) + if mares: + yield mares.group(1) + + +# make sure any def test_func is after the TESTS BELOW +# comment, or future sedding will make us sad. +def check_test_after_marker(sourcelines, node): + if not gbl.config.in_pytestwant: + return + + had_marker = False + for line in sourcelines: + if line.startswith("# TESTS BELOW"): + had_marker = True + if line.startswith("def test_"): + if not had_marker: + err.compiler(f"need TEST BELOW before {line}", node=node) + + +def find_main_func_name(sourcelines, func_name_arg): + if func_name_arg != "": + return func_name_arg + + function_to_call = "no function in file" + + for fname in find_defined_funcs(sourcelines): + function_to_call = fname + + return function_to_call + + +def digest_top(walker, func_name, srcpath): + desc = find_desc(walker, func_name, srcpath) + stat.add_stat(stat.Lazy(symbol.Table.yield_table())) + + walkfunc.inline(desc) + stat.codenl(["M30"], comment_txt=stat.CommentGen.NONE) + for handler in gbl.on_exit: + handler() + + stat.add_stat(stat.Percent()) + # stat.codenl(["%"], comment_txt=stat.CommentGen.NONE) + return desc + + +@gbl.g2l +def compile2g(func_name_arg, srcfile_name, job_name): + + with stat.Nest() as cursor: + try: + axis.NAMES = "xyz" + gbl.reset() + symbol.Table.reset() + + src_path = pathlib.Path(srcfile_name) + src_lines = gbl.get_lines(src_path) + + sys.path.insert(0, str(src_path.parent)) + + gbl.log(f"Starting {func_name_arg} {cursor.next_label}") + func_name = find_main_func_name(src_lines, func_name_arg) + + version = "" if gbl.config.no_id else f": {VERSION}" + stat.code( + f"{job_name} ({func_name}{version})", + comment_txt=stat.CommentGen.NONE, + ) + + node = ast.parse("\n".join(src_lines), filename=srcfile_name) + + for el in ast.walk(node): + gbl.set_ast_file_name(el, srcfile_name) + + # load everything + + walker = walkfunc.Walk() + walker.visit_module(node, srcfile_name) + + if node.body: + funcdef = digest_top( + walker, + func_name, + src_path, + ) + + check_test_after_marker(src_lines, funcdef.node) + + # careful with use of generators, because symbol table may + # be emitted at the top, yet needs things used last on. + res = list(cursor.to_full_lines()) + + yield from res + except FileNotFoundError as exn: + # happens when python can't open file + togo_node = gbl.make_fake_node(srcfile_name, 0, 0, 0) + raise err.CompilerError(str(exn), report_line=False, node=togo_node) from exn + except SyntaxError as exn: + # comes from inside python when importing file. + + togo_node = gbl.make_fake_node( + exn.filename, exn.lineno, exn.offset, exn.end_offset + ) + raise err.CompilerError(exn.msg, node=togo_node) from exn + + except ( + TypeError, + KeyError, + ModuleNotFoundError, + AttributeError, + IndexError, + ) as exn: + raise err.CompilerError(str(exn)) from exn diff --git a/p2g/coords.py b/p2g/coords.py index e375a3b7..fc3fd43c 100755 --- a/p2g/coords.py +++ b/p2g/coords.py @@ -11,18 +11,15 @@ def flatten(args): - res = [] for el in args: for subel in el.everything(): - res.append(subel) - return res + yield subel def unpack(args, kwargs) -> vector.TupleV: resmap: typing.Dict[int, scalar.Scalar] = {} if args: - args = map(vector.wrap, args) - args = flatten(args) + args = list(flatten(map(vector.wrap, args))) for idx, value in enumerate(args): resmap[idx] = value # can have x=1,y=1 or xy=(somthing) diff --git a/p2g/err.py b/p2g/err.py index 27e470b8..aeb70f15 100755 --- a/p2g/err.py +++ b/p2g/err.py @@ -7,6 +7,7 @@ def code_context_node(node: ast.AST): file_name = gbl.ast_file_name(node) + file_path = pathlib.Path(file_name).absolute() reportable_line = node.lineno @@ -49,7 +50,7 @@ class CompilerError(Exception): message: str report_line: bool - def __init__(self, message, report_line=True, node=gbl.astnone): + def __init__(self, message, report_line=True, node=gbl.ASTNONE): super().__init__() if gbl.config.bp_on_error: @@ -57,7 +58,7 @@ def __init__(self, message, report_line=True, node=gbl.astnone): self.report_line = report_line self.message = message - self.node = gbl.iface.last_node if node is gbl.astnone else node + self.node = gbl.iface.last_node if node is gbl.ASTNONE else node def get_report_lines(self): @@ -83,6 +84,6 @@ def get_report_lines(self): return [line_prefix + source_line, source_context, message] -def compiler(message: str = "", node=gbl.astnone, exn=None): +def compiler(message: str = "", node=gbl.ASTNONE, exn=None): raise CompilerError(message, node=node) from exn diff --git a/p2g/fstring.py b/p2g/fstring.py index ddd428aa..c21aef32 100644 --- a/p2g/fstring.py +++ b/p2g/fstring.py @@ -99,7 +99,7 @@ def format_for_n(val, fmt): if not fmt: fmt = "7.2f" gcode_fmt = py_fmt_to_gcode(fmt) - if op.get_nelements(val) > 1: + if nd.get_nelements(val) > 1: return format_expand(val, gcode_fmt) return format_for_one(p2g.scalar.wrap_scalar(val), gcode_fmt, 0) diff --git a/p2g/gbl.py b/p2g/gbl.py index ba630a40..15f08507 100755 --- a/p2g/gbl.py +++ b/p2g/gbl.py @@ -173,7 +173,7 @@ def make_fake_node(filename, lineno, offset, end_offset): return fake_node -astnone = make_fake_node("empty", 1, 0, 0) +ASTNONE = make_fake_node(None, 1, 0, 0) class PerTranslation: @@ -185,7 +185,7 @@ def __init__(self): self.ebss = 100 self.varrefs = {} - self.last_node = astnone + self.last_node = ASTNONE def next_bss(self, size): addr = self.ebss diff --git a/p2g/main.py b/p2g/main.py index 7269c9d3..74c90592 100755 --- a/p2g/main.py +++ b/p2g/main.py @@ -1,79 +1,57 @@ import collections +import dataclasses import datetime import pathlib import re import shutil +import sys import typing -import docopt - +from p2g import abandon from p2g import err from p2g import gbl -from p2g import walkfunc - - -DOC = """ -p2g - Turn Python into G-Code. - -Usage: - p2g [options] [] - p2g help [ all | topics | maint | version | location | ] - p2g examples - -# For bare p2g: -# p2g tram-rotary.py ~/_nc_/O{countdown}tr.nc -# Makes an output of the form ~/_nc_/O1234tr.nc -# -# p2g --func=thisone - -# Read from stdin, look for the 'thisone' function and write to -# to stdout. -# - -Arguments: - Source python file. [default: stdin] - Destination G-Code file. [default: stdout] - {countdown} in file name creates a decrementing prefix - for the output file which makes looking for the .nc in - a crowded directory less painful - it's at the top. - (It's the number of seconds until midnight, so clear - the directory once a day.) - [ all | topics | maint | version | location | ] - # all Print all readme. - # topics List all topics. - # maint Print maintenance options. - # version Show version - # location Show absdir of main - # Print from readme starting at topic. - - - - -Options: - --job= Olabel for output code. - --function= Function to be compiled, - default is last one in source file. - --narrow Emit comments on their own line, - makes text fit more easily into - a narrow program window. - --short-filenames Emit just the lsb of filenames. -! -!For maintenance: -! --break pdb.set_trace() on error. -! --no-id= Don't put version in outputs. -! --verbose= Set verbosity level [default: 0] -""" - - -def do_examples(outdir): +from p2g import VERSION + + +# usage printed when bad args are seen, +# lines starting with ! don't get printed unless +# help used. + + +@dataclasses.dataclass +class Opts: + bp = False + help = False + location = False + main = False + narrow = False + shortfilenames = False + buildexamples = False + version = False + job = "" + function = "" + verbose = 0 + name1 = "" + name2 = "" + help_argument = "" + + +def build_examples(opts): + if not opts.name1: + raise err.CompilerError("Need destination directory.") + + outdir = pathlib.Path(opts.name1) find_examples = gbl.find_ours("vicecenter.py") dst_dir = outdir.resolve() example_dir = find_examples.parent example_files = example_dir.glob("[a-z]*.py") outdir.mkdir(exist_ok=True, parents=True) + for src in example_files: dst_name = outdir / src.name gbl.sprint(f"Copying {src} {dst_name}") shutil.copy(src, dst_name) + for job in ["vicecenter", "probecalibrate", "maxflutes"]: rootname = dst_dir / job sysargs = [ @@ -84,35 +62,38 @@ def do_examples(outdir): main(sysargs) -# chop readme.txt into bits given back by +# chop howto.txt into bits given back by # choice of section. -def do_doc(want): - +def show_doc(want): doc = gbl.find_ours("howto.txt").read_text() lines = doc.split("\n") - by_section = collections.defaultdict(list) - # a section header comes the text, not TOC, looks like: - # the form + + # a section header comes from the text, don't confuse + # with TOC, looks like <number> <title> + # keep dict of section names -> list of lines till next name. want = want.lower() + by_section = collections.defaultdict(list) section_name = "" for line in lines: got = re.match("^\\d+[. ]+(.*)", line) if got: section_name = got.group(1).lower() - by_section[section_name].append(line) + if section_name: + by_section[section_name].append(line) if want == "topics": for section in by_section: print(f" {section}") return - doneone = False + doneone = False for section, lines in by_section.items(): if want == "all" or want in section: doneone = True for line in lines: print(line) + if not doneone: print(f"{want} not found, topics:") for section in by_section: @@ -120,8 +101,7 @@ def do_doc(want): def calculate_output_file_name(provided_filename): - # if provided_filename is empty then output is stdout. - if provided_filename is None: + if not provided_filename or provided_filename == "-": return "-" now = datetime.datetime.now() @@ -131,116 +111,109 @@ def calculate_output_file_name(provided_filename): return provided_filename.replace("{countdown}", f"{mins_togo:04d}") -def do_gen(src_name, job_name, func_name, output_name): +def compile_to_gcode(opts): + job_name = opts.job or "O00001" + func_name = opts.function or "<last>" + + if not opts.name1: + raise err.CompilerError("Need <src> [<dst>].") + + if not opts.name2: + opts.name2 = "-" + + src_path = pathlib.Path(opts.name1) + output_name = calculate_output_file_name(opts.name2) - if func_name is None: - func_name = "<last>" - job_name = job_name if job_name else "O0001" - output_name = calculate_output_file_name(output_name) - src_path = pathlib.Path(src_name) gbl.v1print(f"src: {src_path}") gbl.v1print(f"fnc: {func_name}") gbl.v1print(f"job: {job_name}") gbl.v1print(f"out: {output_name}") - try: - res = walkfunc.compile2g(func_name, src_path, job_name=job_name) - gbl.write_nl_lines(res, output_name) - return 0 + res = abandon.compile2g(func_name, src_path, job_name=job_name) + gbl.write_nl_lines(res, output_name) - except err.CompilerError as exn: - for line in exn.get_report_lines(): - gbl.eprint(line) - return 1 +def grab_options(args): + opts = Opts() + def add_filename(name): + if not opts.name1: + opts.name1 = name + return + if not opts.name2: + opts.name2 = name + return + raise err.CompilerError(f"Too many filenames at '{name}'.") -def prepare_optionns(options): - # remove comments from source to docopt. - parseable_opts = re.sub("\n# .*", "", DOC) - # uncomment the maint options so they can - # be parsed. - parseable_opts = re.sub("\n!(.*)", "\n\\1", parseable_opts) - opts = docopt.docopt(parseable_opts, help=False, argv=options) - gbl.config = gbl.config._replace( - bp_on_error=opts["--break"], - short_filenames=opts["--short-filenames"], - verbose=(int(opts["--verbose"])), - narrow_output=gbl.config.narrow_output or opts["--narrow"], - no_id=gbl.config.no_id or opts["--no-id"], - ) - return opts + for arg in args: + if arg == "-" or "/" in arg or "." in arg: + add_filename(arg) + continue + while arg.startswith("-"): + arg = arg[1:] -def do_help_options(opts): - if opts["<topic>"]: - do_doc(opts["<topic>"]) - elif opts["all"]: - do_doc("all") - elif opts["maint"]: - docstr = re.sub("\n!", "\n", re.sub("\n[^!].*", "", DOC)) - gbl.sprint(docstr) - elif opts["topics"]: - do_doc("topics") - else: - # remove comment chars from usage - # and the maint commands too. - docstr = DOC.strip("\n").replace("#", "") - docstr = re.sub("\n!.*", "", docstr) - gbl.sprint(docstr) - - -def handled_dash_options(opts): - if opts["version"]: - from p2g import VERSION + as_field = arg.replace("-", "") - gbl.sprint(VERSION) - return 1 - if opts["location"]: - gbl.sprint(f"{__file__}") - return 1 - if opts["help"]: - do_help_options(opts) - return 1 - if opts["examples"]: - do_examples(pathlib.Path(opts["<dstdir>"])) - return 1 - return 0 + if (split := as_field.find("=")) > 0: + name = as_field[:split] + value = as_field[split + 1 :] + else: + name = as_field + value = "1" + if name not in Opts.__dict__: + add_filename(name) + else: + setattr(opts, name, value) -# trick - looking at the syntax for the options, -# if a 'srcfile' is called 'help', then we pretend were called -# with --help. So you can't compile a file called help. -def trick_help_on_cmdline(opts): + return opts - # if srcfile matches any of the other attributes, behave - # as if that was typed. - if opts["<srcfile>"] == "examples": +def wrappedmain(args: typing.Optional[list[str]] = None): + if args is None: + args = sys.argv[1:] - opts["examples"] = True - opts["<dstdir>"] = opts["<dstfile>"] if opts["<dstfile>"] else "demo" + if not args: + show_doc("usage") + return - elif opts["<srcfile>"] == "help": - otherkey = opts["<dstfile>"] - opts["help"] = True - if otherkey in opts: - opts[otherkey] = True - else: - opts["<topic>"] = otherkey + opts = grab_options(args) + if opts.buildexamples: + build_examples(opts) + return -def main(options: typing.Optional[list[str]] = None): + if opts.version: + gbl.sprint(VERSION) + return - opts = prepare_optionns(options) + if opts.location: + gbl.sprint(f"{__file__}") + return - trick_help_on_cmdline(opts) - if handled_dash_options(opts): - return 0 + if opts.help: + if not opts.name1: + show_doc("usage") + return + show_doc(opts.name1) + return - return do_gen( - src_name=opts["<srcfile>"], - job_name=opts["--job"], - func_name=opts["--function"], - output_name=opts["<dstfile>"], + gbl.config = gbl.config._replace( + bp_on_error=opts.bp, + short_filenames=opts.shortfilenames, + verbose=int(opts.verbose), + narrow_output=gbl.config.narrow_output or opts.narrow, ) + + compile_to_gcode(opts) + + +def main(args: typing.Optional[list[str]] = None): + try: + wrappedmain(args) + except err.CompilerError as exn: + for line in exn.get_report_lines(): + gbl.eprint(line) + return 1 + return 0 diff --git a/p2g/nd.py b/p2g/nd.py index e107b412..1fec35a7 100755 --- a/p2g/nd.py +++ b/p2g/nd.py @@ -21,12 +21,6 @@ class Opinfo(typing.NamedTuple): g_func: bool = False opt: typing.Callable = opt_null - # def rtl_get_arg_(self, _idx): - # return self.pyn - - # def rtl_arg_info_(self): - # return ["opinfo"] - const_nd = Opinfo(astc=ast.Constant, pyn="konstant", gname="", prec=20) @@ -112,3 +106,11 @@ def to_gcode(thing, modifier=NodeModifier.EMPTY) -> str: return to_gcode_from_float(thing, modifier) return thing.to_gcode(modifier) + + +def get_nelements(node): + mth = getattr(node, "nelements", None) + if mth: + return mth() + + return 1 diff --git a/p2g/op.py b/p2g/op.py index 10326d5a..7fcf4cf7 100755 --- a/p2g/op.py +++ b/p2g/op.py @@ -84,21 +84,10 @@ def get_unop(node): return None -def get_nelements(node): - if isinstance(node, vector.Vec): - return node.nelements() - - return 1 - - def hashop(arg): return Unop(allops["#"], arg) -# make sure that whatever expression is in node -# ends up in a macro variable on - - def reload(node: scalar.Scalar): unop = get_unop(node) if unop and unop.opfo.pyn == "#": @@ -127,7 +116,6 @@ def same(self, other): def to_gcode(self, modi: nd.NodeModifier) -> str: if modi == nd.NodeModifier.ARGUMENT: - return parensif(True, self.to_gcode(nd.NodeModifier.EMPTY)) if self.opfo.g_func: @@ -141,17 +129,13 @@ def to_gcode(self, modi: nd.NodeModifier) -> str: outer_prec = self.opfo.prec - def handle_term(node): + def term(node): return parensif( get_prec(node) < outer_prec, nd.to_gcode(node, modi), ) - res.append(handle_term(self.lhs)) - res.append(self.opfo.gname) - res.append(handle_term(self.rhs)) - - return " ".join(res) + return f"{term(self.lhs)} {self.opfo.gname} {term(self.rhs)}" def __repr__(self): return f"({self.lhs}{self.opfo.pyn}{self.rhs})" @@ -225,8 +209,7 @@ def make_vec_binop(opfo, lhs, rhs=None, force_ourtype=False): lhs = vector.wrap(lhs) if rhs is None: - # actually unop. - + # turns out this binop wasn't. return vector.sorv_from_list( [make_scalar_unop(opfo, el) for el in lhs.everything()] ) @@ -313,16 +296,16 @@ def opt_div(opfo, lhs, rhs) -> OptRes: def opt_not(_nd, arg) -> OptRes: + # not k becomes elided if arg.is_constant: return scalar.Constant(not arg.value) - # got not(comop, turn into (inverted compop)) + # not (a < b) becomes a >= b if notted := not_compop.get(arg.opfo.pyn): return make_scalar_binop(allops[notted], arg.lhs, arg.rhs) - rhs = scalar.Constant(0) - return make_scalar_binop(allops["!="], arg, rhs) + return make_scalar_binop(allops["!="], arg, scalar.Constant(0)) def opt_plus(_, arg) -> OptRes: @@ -335,11 +318,10 @@ def opt_invert(_, arg) -> OptRes: return make_scalar_binop(allops["^"], arg, rhs) -# turn a1 > a2 == 0 -# => (a1 <= a2) - - +# handles eq and ne def opt_eq(opfo, lhs: scalar.Scalar, rhs: scalar.Scalar) -> OptRes: + + # identities are easy to compare if gbl.same(lhs, rhs): return scalar.Constant(opfo.pyn == "==") @@ -347,6 +329,7 @@ def opt_eq(opfo, lhs: scalar.Scalar, rhs: scalar.Scalar) -> OptRes: return None if isinstance(lhs, Binop): + # (a1 > a2) == 0 becomes a1 <= a2 if rev := not_compop.get(lhs.opfo.pyn): if opfo.pyn == "==": return make_scalar_binop( @@ -365,9 +348,13 @@ def opt_matmul(_opfo, _lhs, _rhs) -> OptRes: # no cover def opt_add(opfo, lhs, rhs) -> OptRes: if (res := opt_fold(opfo, lhs, rhs)) is not None: return res + + # x + (-y) becomes x - y if isinstance(rhs, Unop) and rhs.opfo.pyn == "un-": return make_scalar_binop(allops["-"], lhs, rhs.child) + # x + (-k) becomes x - k + # x + 0 becomes x if isinstance(rhs, scalar.Constant): rhsv = rhs.to_float() if rhsv < 0.0: @@ -409,8 +396,8 @@ def make_slice(low, high, step): ) -# breakpoint() -# vector.MemVec.make_hashop = make_hashop +# install opfo methods into classes for Vec and Scalar. +# new dunder methods implement magic math. def nd_install(opfo: nd.Opinfo): diff --git a/p2g/scalar.py b/p2g/scalar.py index 4ca968d2..7f5a6778 100755 --- a/p2g/scalar.py +++ b/p2g/scalar.py @@ -49,8 +49,6 @@ def __init__(self, value: int | float): super().__init__(nd.const_nd) self._value = value - # def get_address(self): - # err.compiler("Can't take address of constant.") @property def value(self): return self._value diff --git a/p2g/symbol.py b/p2g/symbol.py index d62a5e45..4bd13c16 100755 --- a/p2g/symbol.py +++ b/p2g/symbol.py @@ -96,7 +96,3 @@ def reset(cls): cls.name_to_thing = collections.defaultdict(list) cls.addrs_used = set() gbl.Control.symbol_table = False - - -class TSUB: - pass diff --git a/p2g/vector.py b/p2g/vector.py index 81ef2439..2a18a081 100755 --- a/p2g/vector.py +++ b/p2g/vector.py @@ -207,7 +207,7 @@ def __setitem__(self, indexes, src): stat.append_set(self[idx], sel) def __repr__(self): - return f"(array {self._addr} {self._size})" + return f"(array {self._addr} {self._size})" def wrap(thing) -> typing.Union[Vec, scalar.Scalar]: diff --git a/p2g/walkfunc.py b/p2g/walkfunc.py index 9354fc2f..6196c294 100755 --- a/p2g/walkfunc.py +++ b/p2g/walkfunc.py @@ -1,19 +1,11 @@ import ast import dataclasses import itertools -import pathlib -import re -import sys as realsys import typing -import p2g - -from p2g import axis from p2g import err from p2g import gbl from p2g import op -from p2g import stat -from p2g import symbol from p2g import sys from p2g import walkbase from p2g import walkexpr @@ -82,7 +74,7 @@ def gather_func_formals(func_def, *args, **kwargs): final_dict = {} formalspec = func_def.node.args if formalspec.vararg: - final_dict[formalspec.vararg.arg] = args[len(formalspec.args) :] + final_dict[formalspec.vararg.arg] = args[len(formalspec.args):] else: if len(args) > len(formalspec.args): err.compiler( @@ -205,17 +197,6 @@ def _visit_functiondef(self, node): self.ns[node.name] = ifunc -def find_desc(walker, func_name, srcpath): - try: - fncdef = walker.ns[func_name] - desc = fncdef(Marker()) - except KeyError as exn: - raise err.CompilerError( - f"No such function '{func_name}' in '{srcpath}'." - ) from exn - return desc - - class Walk( walkstat.WalkStatement, walkexpr.WalkExpr, @@ -224,121 +205,3 @@ class Walk( walkbase.WalkBase, ): pass - - -def find_defined_funcs(sourcelines): - for line in sourcelines: - # find last line with def in it, that's the function we need - mares = re.match("def (.*?)\\(", line) - if mares: - yield mares.group(1) - - -# make sure any def test_func is after the TESTS BELOW -# comment, or future sedding will make us sad. -def check_test_after_marker(sourcelines, node): - if not gbl.config.in_pytestwant: - return - - had_marker = False - for line in sourcelines: - if line.startswith("# TESTS BELOW"): - had_marker = True - if line.startswith("def test_"): - if not had_marker: - err.compiler(f"need TEST BELOW before {line}", node=node) - - -def find_main_func_name(sourcelines, func_name_arg): - if func_name_arg != "<last>": - return func_name_arg - - function_to_call = "no function in file" - - for fname in find_defined_funcs(sourcelines): - function_to_call = fname - - return function_to_call - - -def digest_top(walker, func_name, srcpath): - desc = find_desc(walker, func_name, srcpath) - stat.add_stat(stat.Lazy(symbol.Table.yield_table())) - - inline(desc) - stat.codenl(["M30"], comment_txt=stat.CommentGen.NONE) - for handler in gbl.on_exit: - handler() - - stat.add_stat(stat.Percent()) - # stat.codenl(["%"], comment_txt=stat.CommentGen.NONE) - return desc - - -@gbl.g2l -def compile2g(func_name_arg, srcfile_name, job_name): - - with stat.Nest() as cursor: - try: - axis.NAMES = "xyz" - gbl.reset() - symbol.Table.reset() - - src_path = pathlib.Path(srcfile_name) - src_lines = gbl.get_lines(src_path) - - realsys.path.insert(0, str(src_path.parent)) - - gbl.log(f"Starting {func_name_arg} {cursor.next_label}") - func_name = find_main_func_name(src_lines, func_name_arg) - - version = "" if gbl.config.no_id else f": {p2g.VERSION}" - stat.code( - f"{job_name} ({func_name}{version})", - comment_txt=stat.CommentGen.NONE, - ) - - node = ast.parse("\n".join(src_lines), filename=srcfile_name) - - for el in ast.walk(node): - gbl.set_ast_file_name(el, srcfile_name) - - # load everything - - walker = Walk() - walker.visit_module(node, srcfile_name) - - if node.body: - funcdef = digest_top( - walker, - func_name, - src_path, - ) - - check_test_after_marker(src_lines, funcdef.node) - - # careful with use of generators, because symbol table may - # be emitted at the top, yet needs things used last on. - res = list(cursor.to_full_lines()) - - yield from res - except FileNotFoundError as exn: - # happens when python can't open file - togo_node = gbl.make_fake_node(srcfile_name, 0, 0, 0) - raise err.CompilerError(str(exn), report_line=False, node=togo_node) from exn - except SyntaxError as exn: - # comes from inside python when importing file. - - togo_node = gbl.make_fake_node( - exn.filename, exn.lineno, exn.offset, exn.end_offset - ) - raise err.CompilerError(exn.msg, node=togo_node) from exn - - except ( - TypeError, - KeyError, - ModuleNotFoundError, - AttributeError, - IndexError, - ) as exn: - raise err.CompilerError(str(exn)) from exn diff --git a/poetry.lock b/poetry.lock index 3f85695a..5fb99fb3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -58,13 +58,13 @@ files = [ [[package]] name = "click" -version = "8.1.6" +version = "8.1.7" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" files = [ - {file = "click-8.1.6-py3-none-any.whl", hash = "sha256:fa244bb30b3b5ee2cae3da8f55c9e5e0c0e86093306301fb418eb9dc40fbded5"}, - {file = "click-8.1.6.tar.gz", hash = "sha256:48ee849951919527a045bfe3bf7baa8a959c423134e1a5b98c05c20ba75a1cbd"}, + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, ] [package.dependencies] @@ -203,13 +203,13 @@ files = [ [[package]] name = "exceptiongroup" -version = "1.1.2" +version = "1.1.3" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.2-py3-none-any.whl", hash = "sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f"}, - {file = "exceptiongroup-1.1.2.tar.gz", hash = "sha256:12c3e887d6485d16943a309616de20ae5582633e0a2eda17f4e10fd61c1e8af5"}, + {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, + {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, ] [package.extras] @@ -384,33 +384,38 @@ files = [ [[package]] name = "mypy" -version = "1.5.0" +version = "1.5.1" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ad3109bec37cc33654de8db30fe8ff3a1bb57ea65144167d68185e6dced9868d"}, - {file = "mypy-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b4ea3a0241cb005b0ccdbd318fb99619b21ae51bcf1660b95fc22e0e7d3ba4a1"}, - {file = "mypy-1.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fe816e26e676c1311b9e04fd576543b873576d39439f7c24c8e5c7728391ecf"}, - {file = "mypy-1.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:42170e68adb1603ccdc55a30068f72bcfcde2ce650188e4c1b2a93018b826735"}, - {file = "mypy-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:d145b81a8214687cfc1f85c03663a5bbe736777410e5580e54d526e7e904f564"}, - {file = "mypy-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c36011320e452eb30bec38b9fd3ba20569dc9545d7d4540d967f3ea1fab9c374"}, - {file = "mypy-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f3940cf5845b2512b3ab95463198b0cdf87975dfd17fdcc6ce9709a9abe09e69"}, - {file = "mypy-1.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9166186c498170e1ff478a7f540846b2169243feb95bc228d39a67a1a450cdc6"}, - {file = "mypy-1.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:725b57a19b7408ef66a0fd9db59b5d3e528922250fb56e50bded27fea9ff28f0"}, - {file = "mypy-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:eec5c927aa4b3e8b4781840f1550079969926d0a22ce38075f6cfcf4b13e3eb4"}, - {file = "mypy-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:79c520aa24f21852206b5ff2cf746dc13020113aa73fa55af504635a96e62718"}, - {file = "mypy-1.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:769ddb6bfe55c2bd9c7d6d7020885a5ea14289619db7ee650e06b1ef0852c6f4"}, - {file = "mypy-1.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbf18f8db7e5f060d61c91e334d3b96d6bb624ddc9ee8a1cde407b737acbca2c"}, - {file = "mypy-1.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a2500ad063413bc873ae102cf655bf49889e0763b260a3a7cf544a0cbbf7e70a"}, - {file = "mypy-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:84cf9f7d8a8a22bb6a36444480f4cbf089c917a4179fbf7eea003ea931944a7f"}, - {file = "mypy-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a551ed0fc02455fe2c1fb0145160df8336b90ab80224739627b15ebe2b45e9dc"}, - {file = "mypy-1.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:372fd97293ed0076d52695849f59acbbb8461c4ab447858cdaeaf734a396d823"}, - {file = "mypy-1.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8a7444d6fcac7e2585b10abb91ad900a576da7af8f5cffffbff6065d9115813"}, - {file = "mypy-1.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:35b13335c6c46a386577a51f3d38b2b5d14aa619e9633bb756bd77205e4bd09f"}, - {file = "mypy-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:2c9d570f53908cbea326ad8f96028a673b814d9dca7515bf71d95fa662c3eb6f"}, - {file = "mypy-1.5.0-py3-none-any.whl", hash = "sha256:69b32d0dedd211b80f1b7435644e1ef83033a2af2ac65adcdc87c38db68a86be"}, - {file = "mypy-1.5.0.tar.gz", hash = "sha256:f3460f34b3839b9bc84ee3ed65076eb827cd99ed13ed08d723f9083cada4a212"}, + {file = "mypy-1.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f33592ddf9655a4894aef22d134de7393e95fcbdc2d15c1ab65828eee5c66c70"}, + {file = "mypy-1.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:258b22210a4a258ccd077426c7a181d789d1121aca6db73a83f79372f5569ae0"}, + {file = "mypy-1.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9ec1f695f0c25986e6f7f8778e5ce61659063268836a38c951200c57479cc12"}, + {file = "mypy-1.5.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:abed92d9c8f08643c7d831300b739562b0a6c9fcb028d211134fc9ab20ccad5d"}, + {file = "mypy-1.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:a156e6390944c265eb56afa67c74c0636f10283429171018446b732f1a05af25"}, + {file = "mypy-1.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6ac9c21bfe7bc9f7f1b6fae441746e6a106e48fc9de530dea29e8cd37a2c0cc4"}, + {file = "mypy-1.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:51cb1323064b1099e177098cb939eab2da42fea5d818d40113957ec954fc85f4"}, + {file = "mypy-1.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:596fae69f2bfcb7305808c75c00f81fe2829b6236eadda536f00610ac5ec2243"}, + {file = "mypy-1.5.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:32cb59609b0534f0bd67faebb6e022fe534bdb0e2ecab4290d683d248be1b275"}, + {file = "mypy-1.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:159aa9acb16086b79bbb0016145034a1a05360626046a929f84579ce1666b315"}, + {file = "mypy-1.5.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f6b0e77db9ff4fda74de7df13f30016a0a663928d669c9f2c057048ba44f09bb"}, + {file = "mypy-1.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:26f71b535dfc158a71264e6dc805a9f8d2e60b67215ca0bfa26e2e1aa4d4d373"}, + {file = "mypy-1.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fc3a600f749b1008cc75e02b6fb3d4db8dbcca2d733030fe7a3b3502902f161"}, + {file = "mypy-1.5.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:26fb32e4d4afa205b24bf645eddfbb36a1e17e995c5c99d6d00edb24b693406a"}, + {file = "mypy-1.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:82cb6193de9bbb3844bab4c7cf80e6227d5225cc7625b068a06d005d861ad5f1"}, + {file = "mypy-1.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4a465ea2ca12804d5b34bb056be3a29dc47aea5973b892d0417c6a10a40b2d65"}, + {file = "mypy-1.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9fece120dbb041771a63eb95e4896791386fe287fefb2837258925b8326d6160"}, + {file = "mypy-1.5.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d28ddc3e3dfeab553e743e532fb95b4e6afad51d4706dd22f28e1e5e664828d2"}, + {file = "mypy-1.5.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:57b10c56016adce71fba6bc6e9fd45d8083f74361f629390c556738565af8eeb"}, + {file = "mypy-1.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:ff0cedc84184115202475bbb46dd99f8dcb87fe24d5d0ddfc0fe6b8575c88d2f"}, + {file = "mypy-1.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8f772942d372c8cbac575be99f9cc9d9fb3bd95c8bc2de6c01411e2c84ebca8a"}, + {file = "mypy-1.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5d627124700b92b6bbaa99f27cbe615c8ea7b3402960f6372ea7d65faf376c14"}, + {file = "mypy-1.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:361da43c4f5a96173220eb53340ace68cda81845cd88218f8862dfb0adc8cddb"}, + {file = "mypy-1.5.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:330857f9507c24de5c5724235e66858f8364a0693894342485e543f5b07c8693"}, + {file = "mypy-1.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:c543214ffdd422623e9fedd0869166c2f16affe4ba37463975043ef7d2ea8770"}, + {file = "mypy-1.5.1-py3-none-any.whl", hash = "sha256:f757063a83970d67c444f6e01d9550a7402322af3557ce7630d3c957386fa8f5"}, + {file = "mypy-1.5.1.tar.gz", hash = "sha256:b031b9601f1060bf1281feab89697324726ba0c0bae9d7cd7ab4b690940f0b92"}, ] [package.dependencies] @@ -566,13 +571,13 @@ testutils = ["gitpython (>3)"] [[package]] name = "pyproject-api" -version = "1.5.3" +version = "1.5.4" description = "API to interact with the python pyproject.toml based projects" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pyproject_api-1.5.3-py3-none-any.whl", hash = "sha256:14cf09828670c7b08842249c1f28c8ee6581b872e893f81b62d5465bec41502f"}, - {file = "pyproject_api-1.5.3.tar.gz", hash = "sha256:ffb5b2d7cad43f5b2688ab490de7c4d3f6f15e0b819cb588c4b771567c9729eb"}, + {file = "pyproject_api-1.5.4-py3-none-any.whl", hash = "sha256:ca462d457880340ceada078678a296ac500061cef77a040e1143004470ab0046"}, + {file = "pyproject_api-1.5.4.tar.gz", hash = "sha256:8d41f3f0c04f0f6a830c27b1c425fa66699715ae06d8a054a1c5eeaaf8bfb145"}, ] [package.dependencies] @@ -580,18 +585,18 @@ packaging = ">=23.1" tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} [package.extras] -docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "importlib-metadata (>=6.6)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "setuptools (>=67.8)", "wheel (>=0.40)"] +docs = ["furo (>=2023.7.26)", "sphinx (<7.2)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "setuptools (>=68)", "wheel (>=0.41.1)"] [[package]] name = "pyright" -version = "1.1.322" +version = "1.1.323" description = "Command line wrapper for pyright" optional = false python-versions = ">=3.7" files = [ - {file = "pyright-1.1.322-py3-none-any.whl", hash = "sha256:1bcddb55c4fca5d3c86eee71db0e8aad80536527f2084284998c6cbceda10e4e"}, - {file = "pyright-1.1.322.tar.gz", hash = "sha256:c8299d8b5d8c6e6f6ea48a77bf330a6df79e23305d21d25043bba8a23c1e1ed8"}, + {file = "pyright-1.1.323-py3-none-any.whl", hash = "sha256:23ce9eca401fda311be273784ebf128850d43a17f9e87dc299ffcdc0ffe91f75"}, + {file = "pyright-1.1.323.tar.gz", hash = "sha256:f3029bfe96a3436a505464d28e3433fafe23ac5f86f52edab9a26cd66685825e"}, ] [package.dependencies] @@ -685,20 +690,31 @@ files = [ {file = "ruff-0.0.275.tar.gz", hash = "sha256:a63a0b645da699ae5c758fce19188e901b3033ec54d862d93fcd042addf7f38d"}, ] +[[package]] +name = "semver" +version = "3.0.1" +description = "Python helper for Semantic Versioning (https://semver.org)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "semver-3.0.1-py3-none-any.whl", hash = "sha256:2a23844ba1647362c7490fe3995a86e097bb590d16f0f32dfc383008f19e4cdf"}, + {file = "semver-3.0.1.tar.gz", hash = "sha256:9ec78c5447883c67b97f98c3b6212796708191d22e4ad30f4570f840171cbce1"}, +] + [[package]] name = "setuptools" -version = "68.0.0" +version = "68.1.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"}, - {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"}, + {file = "setuptools-68.1.0-py3-none-any.whl", hash = "sha256:e13e1b0bc760e9b0127eda042845999b2f913e12437046e663b833aa96d89715"}, + {file = "setuptools-68.1.0.tar.gz", hash = "sha256:d59c97e7b774979a5ccb96388efc9eb65518004537e85d52e81eaee89ab6dd91"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] @@ -749,30 +765,30 @@ files = [ [[package]] name = "tox" -version = "4.8.0" +version = "4.9.0" description = "tox is a generic virtualenv management and test command line tool" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tox-4.8.0-py3-none-any.whl", hash = "sha256:4991305a56983d750a0d848a34242be290452aa88d248f1bf976e4036ee8b213"}, - {file = "tox-4.8.0.tar.gz", hash = "sha256:2adacf435b12ccf10b9dfa9975d8ec0afd7cbae44d300463140d2117b968037b"}, + {file = "tox-4.9.0-py3-none-any.whl", hash = "sha256:c80de60fe26f9a009b0a763888bf2099ccfbef50a0279a6b9f6de40eb4eb7457"}, + {file = "tox-4.9.0.tar.gz", hash = "sha256:9b6d38fe422599d084afd89375b4803f4bc1f8f16573c77c8fd8ffcc6938f1ff"}, ] [package.dependencies] cachetools = ">=5.3.1" -chardet = ">=5.1" +chardet = ">=5.2" colorama = ">=0.4.6" filelock = ">=3.12.2" packaging = ">=23.1" -platformdirs = ">=3.9.1" +platformdirs = ">=3.10" pluggy = ">=1.2" pyproject-api = ">=1.5.3" tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} -virtualenv = ">=20.24.1" +virtualenv = ">=20.24.3" [package.extras] -docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-argparse-cli (>=1.11.1)", "sphinx-autodoc-typehints (>=1.23.3,!=1.23.4)", "sphinx-copybutton (>=0.5.2)", "sphinx-inline-tabs (>=2023.4.21)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -testing = ["build[virtualenv] (>=0.10)", "covdefaults (>=2.3)", "detect-test-pollution (>=1.1.1)", "devpi-process (>=0.3.1)", "diff-cover (>=7.7)", "distlib (>=0.3.7)", "flaky (>=3.7)", "hatch-vcs (>=0.3)", "hatchling (>=1.17.1)", "psutil (>=5.9.5)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-xdist (>=3.3.1)", "re-assert (>=1.1)", "time-machine (>=2.10)", "wheel (>=0.40)"] +docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-argparse-cli (>=1.11.1)", "sphinx-autodoc-typehints (>=1.24)", "sphinx-copybutton (>=0.5.2)", "sphinx-inline-tabs (>=2023.4.21)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +testing = ["build[virtualenv] (>=0.10)", "covdefaults (>=2.3)", "detect-test-pollution (>=1.1.1)", "devpi-process (>=0.3.1)", "diff-cover (>=7.7)", "distlib (>=0.3.7)", "flaky (>=3.7)", "hatch-vcs (>=0.3)", "hatchling (>=1.18)", "psutil (>=5.9.5)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-xdist (>=3.3.1)", "re-assert (>=1.1)", "time-machine (>=2.12)", "wheel (>=0.41.1)"] [[package]] name = "typeguard" @@ -923,4 +939,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = ">= 3.10, < 4.0" -content-hash = "b2acabf0b27b021317d8bb6738821959a817ed604b09956fcfae69269eb607db" +content-hash = "a2bd9c433a3e0e9f404e37ba749793ff3b04537abb93a4c2778632169c1577e2" diff --git a/pyproject.toml b/pyproject.toml index b4ead968..72dd7785 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,9 +1,9 @@ [tool.poetry] -version = "0.3.7" +version = "0.3.13" name = "p2g" description = "Transpile python into cnc gcode." authors = ["sac <sac@0x5ac.com>"] -readme = "README.MD" +readme = "readme.md" license = "MIT" keywords = ["cnc", "gcode", "mill", "haas", "g-code", "probe", "vf"] classifiers = [ @@ -17,10 +17,8 @@ repository = 'https://github.com/0x5ac/p2g' homepage = 'https://github.com/0x5ac/p2g' packages = [ { include = "p2g", format = "sdist"}, - ] -include = [ "p2g/docs/*"] -exclude = [ ".*got" ] +include = [ "p2g/docs/*.org","*","p2g","p2g/*","p2g/docs/*", "p2g/examples/*"] [tool.poetry.scripts] p2g = "p2g.main:main" @@ -29,8 +27,6 @@ python = ">= 3.10, < 4.0" typeguard = "^3.0.2" docopt = "^0.6.2" - - [tool.poetry.group.dev.dependencies] typeguard = "^3.0.2" docopt = "^0.6.2" @@ -49,10 +45,11 @@ tox = "^4.6.4" pytest-cov = "^4.1.0" wrapt = "^1.15.0" dill = "^0.3.6" +semver = "^3.0.1" - -[tool.deptry] -exclude = ['(examples|tests)/*'] +[[tool.poetry.source]] +name = "PyPI" +priority = "primary" [tool.pyright] @@ -78,7 +75,6 @@ ignore_missing_imports = true check_untyped_defs = true explicit_package_bases = true - [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" diff --git a/README.MD b/readme.md similarity index 75% rename from README.MD rename to readme.md index e7ef8f29..4eda97ca 100644 --- a/README.MD +++ b/readme.md @@ -1,19 +1,19 @@ # P2G -<img src="/docs/pytest.svg"><img src="/docs/mit.svg"><img src="/docs/coverage.svg"> +<img src="/docs/pytest.svg" alt=""><img src="/docs/mit.svg" alt=""><img src="/docs/coverage.svg" alt=""> +<br> +<img src="https://github.com/0x5ac/p2g/actions/workflows/make.yml/badge.svg" alt=""> -## Demo. +## Demo -<a href="https://youtu.be/PX818-iRb1Q"> -<img src="/docs/png/vicecenter1.png"> -</a> +[![img](https://github.com/0x5ac/p2g/blob/main/docs/png/vicecenter1.png)](https://youtu.be/PX818-iRb1Q) ## Introduction -### Version 0.3.7 +### Version 0.3.13 P2G makes it simple to ensure that parts are in fixtures correctly, coordinate systems are adjusted to deal with stock placement and cope with movement and rotation of workpieces through multiple operations. @@ -41,7 +41,7 @@ $ pip install p2g 1. fetch dependencies, rebuild and install with pip ``` - $ git clone https://github.com/0x5ac/attempt1 p2g + $ git clone https://github.com/0x5ac/p2g p2g $ cd p2g $ make install ``` @@ -49,7 +49,7 @@ $ pip install p2g 2. fetch dependencies and rebuild ``` - $ git clone https://github.com/0x5ac/attempt1 p2g + $ git clone https://github.com/0x5ac/p2g p2g $ cd p2g $ make ``` @@ -57,19 +57,14 @@ $ pip install p2g ## Usage -```python - -``` - ``` p2g - Turn Python into G-Code. Usage: p2g [options] <srcfile> [<dstfile>] p2g help [ all | topics | maint | version | location | <topic> ] - p2g examples <dstdir> + p2g build-examples <dstdir> - For bare p2g: p2g tram-rotary.py ~/_nc_/O{countdown}tr.nc Makes an output of the form ~/_nc_/O1234tr.nc @@ -77,9 +72,8 @@ Usage: Read from stdin, look for the 'thisone' function and write to to stdout. - Arguments: - <srcfile> Source python file. [default: stdin] + <srcfile> Source python file. <dstfile> Destination G-Code file. [default: stdout] {countdown} in file name creates a decrementing prefix for the output file which makes looking for the .nc in @@ -89,14 +83,10 @@ Arguments: <topic> [ all | topics | maint | version | location | <topic> ] all Print all readme. topics List all topics. - maint Print maintenance options. version Show version - location Show absdir of main + location Show absdir of main module. <topic> Print from readme starting at topic. - - - Options: --job=<jobname> Olabel for output code. --function=<fname> Function to be compiled, @@ -105,6 +95,7 @@ Options: makes text fit more easily into a narrow program window. --short-filenames Emit just the lsb of filenames. + ``` @@ -136,7 +127,7 @@ def simple_demo(): " ⇨ `directly` ⇨ ``` -O0001 (simple_demo: 0.3.7) +O00001 (simple_demo: 0.3.13) #100= 199. ( x = Var[199] ) #102= 0. ( for y in range[10]: ) N1000 @@ -163,7 +154,7 @@ import p2g def maxflutes(): mx_flutes = p2g.Var(p2g.haas.TOOL_TBL_FLUTES[0]) - for n_flutes in p2g.haas.TOOL_TBL_FLUTES: + for n_flutes in p2g.haas.TOOL_TBL_FLUTES[1:]: if n_flutes > mx_flutes: mx_flutes = n_flutes @@ -174,11 +165,11 @@ def maxflutes(): ⇨ `p2g maxflutes.py` ⇨ ``` -O0001 (maxflutes: 0.3.7) +O00001 (maxflutes: 0.3.13) #100= #1601 ( mx_flutes = Var[haas.TOOL_TBL_FLUTES[0]]) - #101= 1601. ( for n_flutes in haas.TOOL_TBL_FLUTES:) + #101= 1602. ( for n_flutes in haas.TOOL_TBL_FLUTES[1:]:) N1000 - IF [#101 GE 1801.] GOTO 1002 ( for n_flutes in haas.TOOL_TBL_FLUTES:) + IF [#101 GE 1801.] GOTO 1002 ( for n_flutes in haas.TOOL_TBL_FLUTES[1:]:) IF [#[#101] LE #100] GOTO 1003 ( if n_flutes > mx_flutes: ) #100= #[#101] ( mx_flutes = n_flutes ) GOTO 1004 @@ -242,7 +233,7 @@ def less_trivial(): ⇨ `p2g less_trival.py` ⇨ ``` -O0001 (less_trivial: 0.3.7) +O00001 (less_trivial: 0.3.13) #100= 2. ( cursor = Var[3][2, 3, 4] ) #101= 3. #102= 4. @@ -266,21 +257,20 @@ N1001 # Table of contents -- [Introduction](./docs/howto.md#introduction) -- [Video](./docs/howto.md#vdemo) -- [Install](./docs/howto.md#install) -- [Usage](./docs/howto.md#usage) -- [Examples](./docs/howto.md#examples) -- [Variables](./docs/howto.md#variables) -- [Coordinates](./docs/howto.md#coordinates) -- [Expressions](./docs/howto.md#expressions) -- [Goto](./docs/howto.md#goto) -- [Axes](./docs/howto.md#axes) -- [When](./docs/howto.md#when) -- [DPRNT](./docs/howto.md#dprnt) -- [Notes](./docs/howto.md#notes) -- [Authors](./docs/howto.md#authors) -- [Thanks](./docs/howto.md#thanks) -- [Video](./docs/howto.md#video) - -1. Copyright © 2023 Steve Chamberlain \ No newline at end of file +\* + +- [Introduction](https://github.com/0x5ac/p2g/blob/main/docs/howto.md#introduction) +- [Variables](https://github.com/0x5ac/p2g/blob/main/docs/howto.md#variables) +- [Coordinates](https://github.com/0x5ac/p2g/blob/main/docs/howto.md#coordinates) +- [Expressions](https://github.com/0x5ac/p2g/blob/main/docs/howto.md#expressions) +- [Goto](https://github.com/0x5ac/p2g/blob/main/docs/howto.md#goto) +- [Axes](https://github.com/0x5ac/p2g/blob/main/docs/howto.md#axes) +- [When](https://github.com/0x5ac/p2g/blob/main/docs/howto.md#when) +- [DPRNT](https://github.com/0x5ac/p2g/blob/main/docs/howto.md#dprnt) +- [Symbol Tables](https://github.com/0x5ac/p2g/blob/main/docs/howto.md#symbol-table) +- [Notes](https://github.com/0x5ac/p2g/blob/main/docs/howto.md#notes) +- [Internal Options](https://github.com/0x5ac/p2g/blob/main/docs/howto.md#maitenance-options) +- [Authors](https://github.com/0x5ac/p2g/blob/main/docs/howto.md#authors) +- [Thanks](https://github.com/0x5ac/p2g/blob/main/docs/howto.md#thanks) + +- Copyright © 2023 Steve Chamberlain \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index c3b21661..e257fb72 100755 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,6 +10,7 @@ import p2g.gbl import p2g.err import p2g.walkfunc +import p2g.abandon def pytest_addoption(parser): @@ -49,6 +50,7 @@ def prepend(txt, this, other): yield txt + echar + thisel if left != right: + yield "" yield "====+" + "=" * 60 yield from prepend("WANT", left, right) @@ -89,7 +91,7 @@ def writelines(fn, txt): path = make_file_path(fn) p2g.gbl.log(f"Ptest output {path}") - path.write_text("\n".join(txt)) + path.write_text("\n".join(txt) + "\n") # compile fn, return generated errors or text. @@ -101,7 +103,8 @@ def get_all_comp_outputs(fn): truncate.DEFAULT_MAX_CHARS = 9999 try: - outlines = p2g.walkfunc.compile2g( + + outlines = p2g.abandon.compile2g( fn.__name__, inspect.getsourcefile(fn), job_name="O00001" ) return outlines, [] @@ -111,11 +114,8 @@ def get_all_comp_outputs(fn): return [], errlines -@p2g.gbl.g2l def read_and_trim(path): - lines = path.read_text().split("\n") - for line in lines: - yield line + return [line.rstrip() for line in path.open().readlines()] @contextlib.contextmanager @@ -132,8 +132,9 @@ def check_golden__(): with save_config(narrow_output=False, no_id=True): got_std, _got_err = list(get_all_comp_outputs(fn)) + gold_path = pathlib.Path(fn.__code__.co_filename).with_suffix(".nc") - gold_data = list(read_and_trim(gold_path)) + gold_data = read_and_trim(gold_path) if "--gif" in sys.argv or got_std != gold_data: writelines(fn, got_std) @@ -214,5 +215,9 @@ def must_be__(): def pytest_sessionfinish(session, exitstatus): print() print() - print(f"{100 - (100.0 *session.testsfailed / session.testscollected):0.1f}") + try: + print(f"{100 - (100.0 *session.testsfailed / session.testscollected):0.1f}") + except ZeroDivisionError: + print("{session.testsfailed} {session.testscollected}") + print() diff --git a/tests/test_badpytest.py b/tests/test_badpytest.py index 18089a5b..1e9c1877 100644 --- a/tests/test_badpytest.py +++ b/tests/test_badpytest.py @@ -1,7 +1,7 @@ import io import sys import pathlib -from p2g.main import main +from p2g.main import main, main # can't be tested by directly pytest becase fail import. @@ -17,7 +17,6 @@ def must_fail(cap, *, src=[], want=[]): sys.stdin = io.StringIO("\n".join(src)) main(["--short-filenames", "-"]) - got = gotlines(cap) assert got == want diff --git a/tests/test_coords.py b/tests/test_coords.py index e846d4e8..f057ff69 100755 --- a/tests/test_coords.py +++ b/tests/test_coords.py @@ -129,7 +129,7 @@ def test_cerror_zeros3(): " #100= 2. ", " #101= 3. ", " ", - "( [array 100 2] ) ", + "( [array 100 2] ) ", " M30 ", "% ", ) @@ -223,7 +223,7 @@ def test_list_init3(): " #100= 2. ", " #101= 3. ", " ", - "( [array 100 2] ) ", + "( [array 100 2] ) ", " M30 ", "% ", ) diff --git a/tests/test_main.py b/tests/test_main.py index a7ba2eec..222982fa 100755 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -7,7 +7,7 @@ import p2g from conftest import want -from p2g.main import main +from p2g.main import main, main std = [ @@ -41,6 +41,25 @@ def check_version_str(vstr): assert parts[0].isdigit() +def test_native_err1(capfd): + assert main([]) == 0 + got = capfd.readouterr() + + assert "Usage:" in got.out + + +def test_native_err2(capfd): + assert main(["--verbose"]) != 0 + got = capfd.readouterr() + assert "Need" in got.err + + +def test_native_err3(capfd): + assert main(["a", "b", "c"]) != 0 + got = capfd.readouterr() + assert "Too many filenames" in got.err + + def test_bad_syntax(capfd, tmpdir): tmpfile = write_func(tmpdir, bad) @@ -56,7 +75,7 @@ def test_location(capfd): def test_native_job_capfd_tmpdir_stdout(capfd, tmpdir): tmpfile = write_func(tmpdir, std) - main(["--job=O123", "--narrow", str(tmpfile), "-"]) + main(["--job=O123", "--narrow", str(tmpfile)]) tmpdata = capfd.readouterr() assert "O123" in tmpdata.out @@ -96,10 +115,16 @@ def __init__(self): def test_native_cli_tmpdir_examples(tmpdir): - main(["examples", str(tmpdir)]) + main(["build-examples", str(tmpdir)]) assert (tmpdir / "vicecenter.py").exists() +def test_native_cli_examples_fail(capfd): + main(["build-examples"]) + res = capfd.readouterr() + assert "Need des" in res.err + + def gentwinfuncs(fnname, inout): main(["--function=" + fnname, str(inout.srcfile), str(inout.ncfile)]) @@ -161,9 +186,7 @@ def test_native_capfd_tmpdir_stdout0(capfd, tmpdir): main( [ "--job=O123", - "--no-id", str(tmpfile), - "-", ] ) tmpdata = capfd.readouterr() @@ -202,15 +225,17 @@ def test_native_capfd_help(capfd): def test_native_capfd_doc0(capfd): + main(["help", "all"]) got = capfd.readouterr() + assert "Stumpy" in got.out def test_native_capfd_doc1(capfd): main(["help", "maint"]) got = capfd.readouterr() - assert "--break" in got.out + assert "--bp" in got.out def test_native_doc_no_where(capfd): diff --git a/tools/fakeorg.py b/tools/fakeorg.py new file mode 100644 index 00000000..d69f7f40 --- /dev/null +++ b/tools/fakeorg.py @@ -0,0 +1,114 @@ +#! /usr/bin/env python + +# pretend to be emacs's org eval, but faster. + +import io +import pathlib +import re +import subprocess +import sys +import threading + + +def execute(execstr, src): + as_words = execstr.split() + execr = [word for word in as_words if word] + + if execr[0] == "poetry" and execr[1] == "run" and execr[2] == "p2g": + execr = ["python", "-m", "p2g"] + execr[3:] + + res = subprocess.run( + execr, + check=True, + capture_output=True, + input="".join(src).encode(), + ) + + return io.StringIO(res.stdout.decode()).readlines() + + +def chew_func(): + eval_src: list[str] = [] + eval_results: list[str] = [] + line = None + while True: + line = yield [line] + if eval_results and line.startswith("#+begin_example"): + line = yield [line] + while not line.startswith("#+end_example"): + line = yield [] + line = yield eval_results + [line] + eval_results = [] + continue + + found = re.match( + "#\\+begin_src\\s+python\\s+-i\\s+:results" + "\\s+output\\s+:exports both\\s+:python (.*)", + line, + ) + if found: + while not line.startswith("#+end_src"): + line = yield [line] + eval_src.append(line) + + eval_results = execute(found.group(1), eval_src) + continue + + +def write_list(file, srclist): + with pathlib.Path(file).open("w", encoding="utf-8") as outf: + outf.writelines(srclist) + + +def process_one_file(src_file): + with src_file.open(encoding="utf-8") as infile: + src_lines = infile.readlines() + + finished = [] + + chewer = chew_func() + + next(chewer) + for line in src_lines: + finished += chewer.send(line) + + chewer.close() + finished_len = len(finished) + original_len = len(src_lines) + + print( + f"{finished_len / original_len * 100.0 : 5.2f} " + f"{original_len:4} -> {finished_len:4} {src_file} " + ) + if finished_len < 0.8 * original_len: + emergency_file = src_file.with_suffix(".emergency") + print( + f"File seems to have shrunk a lot. saving {src_file} to {emergency_file}" + ) + write_list(emergency_file, src_lines) + + if finished != src_lines: + backup_file = src_file.with_suffix(".backup") + print(f"{src_file} backed up into -> {backup_file}") + write_list(backup_file, src_lines) + write_list(src_file, finished) + + +def main(): + all_targets = pathlib.Path(sys.argv[1]).glob("*.org") + + threads = [ + threading.Thread( + target=process_one_file, + args=(file,), + ) + for file in all_targets + ] + + for thread in threads: + thread.start() + for thread in threads: + thread.join() + + +main() diff --git a/tools/modversion.py b/tools/modversion.py index ceed41de..fbd75bf9 100644 --- a/tools/modversion.py +++ b/tools/modversion.py @@ -2,17 +2,17 @@ import argparse import pathlib import re -import sys -import typing +import semver -# yet another grab version from project and update tool. -# takes from the known truth and puts it everywhere else by string -# replace. If that changes something you don't want, well, you -# shouldn't have made it look like the previous version number. +# yet another grab version from project and update tool. Takes from +# the known truth and puts it everywhere else by string replace. If +# that changes something you don't want, well, you shouldn't have made +# it look like the previous version number. -def dig_out_semver(txt) -> typing.Optional[str]: + +def dig_out_semver(txt): semver_found = re.match( '^(\\d*\\.\\d*\\.\\d*[$"]?.*)', txt, re.DOTALL | re.IGNORECASE ) @@ -23,13 +23,20 @@ def dig_out_semver(txt) -> typing.Optional[str]: # look for things which look like version numbers, break them # apart and return <prev_text> <version number> <date-code> <post_text> -def find_before_version_after(path): + + +def find_before_version_after(path) -> tuple[str, str, str]: init_lines = path.read_text() semverish = "([0-9]+\\.[0-9]+\\.[-+0-9a-z\\.]+)" # special case if first line looks like version - version_found = re.match(f"^(){semverish}(.*)", init_lines, re.DOTALL | re.IGNORECASE) + + version_found = re.match( + f"^(){semverish}(.*)", + init_lines, + re.DOTALL | re.IGNORECASE, + ) # matches my doc, the toml and the stuff in init. @@ -41,19 +48,17 @@ def find_before_version_after(path): ) if not version_found: - print(f"No existing version found in {path}.") - sys.exit(1) + raise SystemExit(f"No existing version found in {path}.") - semver = dig_out_semver(version_found.group(2)) + seen_semver = dig_out_semver(version_found.group(2)) - if not semver: - print(f"Can't parse version in '{path}' '{version_found.group(2)}'.") - sys.exit(1) + if not seen_semver: + raise SystemExit(f"Can't parse version in '{path}' '{version_found.group(2)}'.") - return version_found.group(1), semver, version_found.group(3) + return version_found.group(1), seen_semver, version_found.group(3) -def main(): +def main_worker(): parser = argparse.ArgumentParser( prog="version", description="yet another way for single point pyproject.toml etc version mods.", @@ -64,19 +69,17 @@ def main(): required=False, help="source file for truth", ) + parser.add_argument( + "--verbose", + action="store_true", + help="talk a lot", + ) parser.add_argument( "--force", required=False, help="force truth version", ) - - parser.add_argument("--top", help="directory to start searching.", default="") - parser.add_argument( - "--out", - help="relative directory to place modified files. Default - in place", - default="", - ) parser.add_argument( "--stdout", action="store_true", @@ -84,18 +87,22 @@ def main(): ) parser.add_argument( - "--names", nargs="*", help="file names to modify", metavar="FILENAME", type=str + "--victims", nargs="*", help="file names to modify", metavar="FILENAME", type=str ) args = parser.parse_args() - new_truth = None + new_truth = "" if args.truth: path = pathlib.Path(args.truth) _, new_truth, _ = find_before_version_after(path) + if args.verbose: + print(f"Found {new_truth} in {path}") if args.force: new_truth = args.force + if args.verbose: + print(f"Found {new_truth} from --force.") before_text = "" after_text = "" @@ -103,16 +110,27 @@ def main(): if args.stdout: print(new_truth) - if not args.names: - return - for src_name in args.names: - src_path = pathlib.Path(args.top) / src_name - before_text, _, after_text = find_before_version_after(src_path) - dst_path = pathlib.Path(args.out) / src_name - dst_path.parent.mkdir(parents=True, exist_ok=True) - dst_path.write_text(before_text + new_truth + after_text, encoding="utf-8") + semver.Version.parse(new_truth) + + for src_name in args.victims: + target_path = pathlib.Path(src_name) + before_text, was, after_text = find_before_version_after(target_path) - sys.exit(0) + if was == new_truth: + print(f"{src_name} version {new_truth} doesn't need to change") + else: + target_path.write_text(before_text + new_truth + after_text, encoding="utf-8") + + if args.verbose: + print(f"Changed version {was} to {new_truth} in {target_path}") + + +def main(): + try: + main_worker() + except (ValueError, SystemExit, FileNotFoundError) as err: + print(f"** FAIL: {err}") + raise SystemExit(1) from err main() diff --git a/tools/org-to-x.el b/tools/org-to-x.el index 364c853f..d197c4e4 100644 --- a/tools/org-to-x.el +++ b/tools/org-to-x.el @@ -7,7 +7,12 @@ (defun sc/execute () (require 'ob-python) - (org-babel-execute-buffer)) + (message "ERRRORRR") + + ;; do the executing in fakeorg.py now + ;; + ;; (org-babel-execute-buffer) + ) (defun sc/tomd () (org-gfm-export-as-markdown)) @@ -15,6 +20,7 @@ (defun sc/fnfromext (ext) (cdr (assoc ext '(("org" . sc/execute) + ("torg" . sc/execute) ("md" . sc/tomd) ("txt" . org-ascii-export-as-ascii) ("html" . org-html-export-as-html))))) @@ -26,7 +32,11 @@ (setq org-confirm-babel-evaluate nil) (funcall (sc/fnfromext (downcase (file-name-extension dstfile)))) (delete-file (concat dstfile ".tmp")) - (write-region (point-min) (point-max) dstfile)) + (delete-file (concat dstfile ".md")) + (delete-file (concat dstfile ".md.tmp")) + (write-region (point-min) (point-max) dstfile) + + )