Skip to content

Commit 80d89c7

Browse files
authored
Merge pull request #7 from fragmuffin/develop
0.2.1
2 parents 2680920 + 97ee873 commit 80d89c7

9 files changed

Lines changed: 219 additions & 34 deletions

File tree

dist/README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,48 @@
11
# Change History
22

3+
----
4+
## 0.2.1
5+
6+
### Improvements
7+
8+
**`pygcode-norm` script:**
9+
10+
Added "Final Machine Actions:"
11+
12+
Final Machine Actions:
13+
standardize what's done at the end of a gcode program.
14+
15+
--zero_xy, -zxy On completion, move straight up to
16+
rapid_safety_height, then across to X0 Y0.
17+
--zero_z, -zz On completion, move down to Z0 (done after zero_xy, if
18+
set).
19+
--rapid_safety_height RAPID_SAFETY_HEIGHT, -rsh RAPID_SAFETY_HEIGHT
20+
Z value to move to before traversing workpiece (if not
21+
set, max value will be attempted).
22+
--spindle_off, -so On completion, turn spindle off.
23+
24+
25+
Added ability to remove all codes & parameters that cannot be parsed.
26+
27+
--rm_invalid_modal, -rmim
28+
Simply remove everything that isn't understood. Use
29+
with caution.
30+
31+
**Library Improvements**
32+
33+
* `Machine.abs2work(<Position>)` and `Machine.work2abs(<Position>)` position
34+
converters, apply machine's offset to the given position without effecting
35+
machine's current position.
36+
* `Machine.clean_block(<Block>)` removes content from a block that's not parsable (use with caution)
37+
* `Machine.ignore_invalid_modal` bool class parameter, if set, will continue on merrily while ignoring
38+
anything not parsable (similarly to `clean_block`)
39+
* deployment version category validation in `setup.py` (ie: alpha, beta, and so on)
40+
41+
### Bugfixes
42+
43+
(none)
44+
45+
----
346
## 0.2.0
447

548
Moved to `alpha`
@@ -20,6 +63,7 @@ Improvements to read more versatile formats
2063
* [#5](https://github.com/fragmuffin/pygcode/issues/5) Line number in program
2164

2265

66+
----
2367
## 0.1.2
2468

2569
Changes to accommodate implementation of [grbl-stream](https://github.com/fragmuffin/grbl-stream)

dist/pygcode-0.2.0.tar.gz

-39.9 KB
Binary file not shown.

dist/pygcode-0.2.1.tar.gz

41.5 KB
Binary file not shown.

scripts/pygcode-norm

Lines changed: 79 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ for pygcode_lib_type in ('installed_lib', 'relative_lib'):
1818
from pygcode import Machine, Mode, Line
1919
from pygcode import GCodeArcMove, GCodeArcMoveCW, GCodeArcMoveCCW
2020
from pygcode import GCodeCannedCycle
21+
from pygcode import GCodeRapidMove, GCodeStopSpindle, GCodeAbsoluteDistanceMode
2122
from pygcode import split_gcodes
2223
from pygcode import Comment
2324
from pygcode.transform import linearize_arc, simplify_canned_cycle
2425
from pygcode.transform import ArcLinearizeInside, ArcLinearizeOutside, ArcLinearizeMid
2526
from pygcode.gcodes import _subclasses
2627
from pygcode import utils
28+
from pygcode.exceptions import MachineInvalidState
2729

2830
except ImportError:
2931
import sys, os, inspect
@@ -65,7 +67,9 @@ def arc_lin_method_type(value):
6567

6668
def word_list_type(value):
6769
"""
68-
:return: [Word('G73'), Word('G89'), ... ]
70+
Convert csv string list into Word instances.
71+
>>> word_list_type("G73,G89") == set([Word('G73'), Word('G89')])
72+
:return: set of Word instances
6973
"""
7074
canned_code_words = set()
7175
for word_str in re.split(r'\s*,\s*', value):
@@ -82,29 +86,29 @@ DEFAULT_CANNED_CODES = ','.join(str(w) for w in sorted(c.word_key for c in _subc
8286

8387
# --- Create Parser
8488
parser = argparse.ArgumentParser(
85-
description="Normalize gcode for machine consistency when using different CAM software"
89+
description="Normalize gcode for machine consistency when using different CAM software."
8690
)
8791
parser.add_argument(
8892
'infile', type=argparse.FileType('r'),
89-
help="gcode file to normalize",
93+
help="Gcode file to normalize.",
9094
)
9195

9296
parser.add_argument(
9397
'--singles', '-s', dest='singles',
9498
action='store_const', const=True, default=False,
95-
help="only output one command per gcode line",
99+
help="Only output one command per gcode line.",
96100
)
97101
parser.add_argument(
98102
'--full', '-f', dest='full',
99103
action='store_const', const=True, default=False,
100-
help="output full commands, any modal parameters will be acompanied with "
101-
"the fully qualified gcode command",
104+
help="Output full commands, any modal parameters will be acompanied with "
105+
"the fully qualified gcode command.",
102106
)
103107

104108
# Machine
105109
parser.add_argument(
106110
'--machine_mode', '-mm', dest='machine_mode', default=DEFAULT_MACHINE_MODE,
107-
help="Machine's startup mode as gcode (default: '%s')" % DEFAULT_MACHINE_MODE,
111+
help="Machine's startup mode as gcode (default: '%s')." % DEFAULT_MACHINE_MODE,
108112
)
109113

110114
# Arc Linearizing
@@ -117,20 +121,20 @@ group = parser.add_argument_group(
117121
group.add_argument(
118122
'--arc_linearize', '-al', dest='arc_linearize',
119123
action='store_const', const=True, default=False,
120-
help="convert G2,G3 commands to a series of linear interpolations (G1 codes)",
124+
help="Convert G2,G3 commands to a series of linear interpolations (G1 codes).",
121125
)
122126
group.add_argument(
123127
'--arc_lin_method', '-alm', dest='arc_lin_method',
124128
type=arc_lin_method_type, default=DEFAULT_ARC_LIN_METHOD,
125129
help="Method of linearizing arcs, i=inner, o=outer, m=mid. List 2 "
126130
"for <cw>,<ccw>, eg 'i,o'. 'i' is equivalent to 'i,i'. "
127-
"(default: '%s')" % DEFAULT_ARC_LIN_METHOD,
131+
"(default: '%s')." % DEFAULT_ARC_LIN_METHOD,
128132
metavar='{i,o,m}[,{i,o,m}]',
129133
)
130134
group.add_argument(
131135
'--arc_precision', '-alp', dest='arc_precision', type=float, default=DEFAULT_PRECISION,
132-
help="maximum positional error when creating linear interpolation codes "
133-
"(default: %g)" % DEFAULT_PRECISION,
136+
help="Maximum positional error when creating linear interpolation codes "
137+
"(default: %g)." % DEFAULT_PRECISION,
134138
)
135139

136140
#parser.add_argument(
@@ -149,41 +153,73 @@ group = parser.add_argument_group(
149153
group.add_argument(
150154
'--canned_expand', '-ce', dest='canned_expand',
151155
action='store_const', const=True, default=False,
152-
help="Expand canned cycles into basic linear movements, and pauses",
156+
help="Expand canned cycles into basic linear movements, and pauses.",
153157
)
154158
group.add_argument(
155159
'--canned_codes', '-cc', dest='canned_codes',
156160
type=word_list_type, default=DEFAULT_CANNED_CODES,
157-
help="List of canned gcodes to expand, (default is '%s')" % DEFAULT_CANNED_CODES,
161+
help="List of canned gcodes to expand, (default is '%s')." % DEFAULT_CANNED_CODES,
162+
)
163+
164+
# Finalize Code
165+
group = parser.add_argument_group(
166+
"Final Machine Actions",
167+
"standardize what's done at the end of a gcode program."
168+
)
169+
group.add_argument(
170+
'--zero_xy', '-zxy', dest="zero_xy",
171+
action='store_const', const=True, default=False,
172+
help="On completion, move straight up to rapid_safety_height, "
173+
"then across to X0 Y0.",
174+
)
175+
group.add_argument(
176+
'--zero_z', '-zz', dest="zero_z",
177+
action='store_const', const=True, default=False,
178+
help="On completion, move down to Z0 (done after zero_xy, if set).",
179+
)
180+
group.add_argument(
181+
'--rapid_safety_height', '-rsh', dest="rapid_safety_height",
182+
type=float, default=None,
183+
help="Z value to move to before traversing workpiece (if not set, max "
184+
"value will be attempted).",
185+
)
186+
group.add_argument(
187+
'--spindle_off', '-so', dest="spindle_off",
188+
action='store_const', const=True, default=False,
189+
help="On completion, turn spindle off.",
158190
)
159191

160192
# Removing non-functional content
161193
group = parser.add_argument_group(
162194
"Removing Content",
163-
"options for the removal of content"
195+
"options for the removal of content."
164196
)
165197
group.add_argument(
166198
'--rm_comments', '-rc', dest='rm_comments',
167199
action='store_const', const=True, default=False,
168-
help="remove all comments (non-functional)",
200+
help="Remove all comments (non-functional).",
169201
)
170202
group.add_argument(
171203
'--rm_blanks', '-rb', dest='rm_blanks',
172204
action='store_const', const=True, default=False,
173-
help="remove all empty lines (non-functional)",
205+
help="Remove all empty lines (non-functional).",
174206
)
175207
group.add_argument(
176208
'--rm_whitespace', '-rws', dest='rm_whitespace',
177209
action='store_const', const=True, default=False,
178-
help="remove all whitespace from gcode blocks (non-functional)",
210+
help="Remove all whitespace from gcode blocks (non-functional).",
179211
)
180212
group.add_argument(
181213
'--rm_gcodes', '-rmg', dest='rm_gcodes',
182214
type=word_list_type, default=[],
183-
help="remove gcode (and it's parameters) with words in the given list "
215+
help="Remove gcode (and it's parameters) with words in the given list "
184216
"(eg: M6,G43) (note: only works for modal params with --full)",
185217
)
186-
218+
group.add_argument(
219+
'--rm_invalid_modal', '-rmim', dest='rm_invalid_modal',
220+
action='store_const', const=True, default=False,
221+
help="Simply remove everything that isn't understood. Use with caution.",
222+
)
187223

188224
# --- Parse Arguments
189225
args = parser.parse_args()
@@ -195,6 +231,7 @@ class MyMode(Mode):
195231

196232
class MyMachine(Machine):
197233
MODE_CLASS = MyMode
234+
ignore_invalid_modal = args.rm_invalid_modal
198235

199236
machine = MyMachine()
200237

@@ -276,6 +313,9 @@ def split_and_process(gcode_list, gcode_class, comment):
276313
for line_str in args.infile.readlines():
277314
line = Line(line_str)
278315

316+
if args.rm_invalid_modal:
317+
machine.clean_block(line.block)
318+
279319
# Effective G-Codes:
280320
# fills in missing motion modal gcodes (using machine's current motion mode).
281321
effective_gcodes = machine.block_modal_gcodes(line.block)
@@ -315,3 +355,23 @@ for line_str in args.infile.readlines():
315355
else:
316356
write(line.block.gcodes, modal_params=line.block.modal_params, comment=line.comment, macro=line.macro)
317357
machine.process_block(line.block)
358+
359+
# Finalizing Motion & Spindle
360+
if any([args.spindle_off, args.zero_xy, args.zero_z]):
361+
write([], comment=Comment("pygcode-norm: finalizing"))
362+
if any([args.zero_xy, args.zero_z]) and not(isinstance(machine.mode.distance, GCodeAbsoluteDistanceMode)):
363+
write([GCodeAbsoluteDistanceMode()])
364+
if args.spindle_off:
365+
write([GCodeStopSpindle()], comment=Comment("spindle off"))
366+
367+
if args.zero_xy:
368+
rapid_safety_height = args.rapid_safety_height
369+
if rapid_safety_height is None:
370+
rapid_safety_height = machine.abs2work(machine.abs_range_max).Z
371+
372+
if args.zero_xy:
373+
write([GCodeRapidMove(Z=rapid_safety_height)], comment=Comment("move to safe height"))
374+
write([GCodeRapidMove(X=0, Y=0)], comment=Comment("move to planar origin"))
375+
376+
if args.zero_z:
377+
write([GCodeRapidMove(Z=0)], comment=Comment("move to zero height"))

setup.py

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import codecs
22
import os
33
import re
4+
from distutils.version import LooseVersion
45

56
from setuptools import setup, find_packages
67

@@ -14,7 +15,7 @@
1415
META_PATH = os.path.join("src", NAME, "__init__.py")
1516
KEYWORDS = ['gcode', 'cnc', 'parser', 'interpreter']
1617
CLASSIFIERS = [
17-
"Development Status :: 2 - Pre-Alpha", # see src/pygcode/__init__.py
18+
"Development Status :: 3 - Alpha", # see src/pygcode/__init__.py
1819
"Intended Audience :: Developers",
1920
"Intended Audience :: Manufacturing",
2021
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
@@ -65,13 +66,49 @@ def find_meta(meta):
6566
raise RuntimeError("Unable to find __{meta}__ string.".format(meta=meta))
6667

6768

69+
def assert_version_classifier(version_str):
70+
"""
71+
Verify version consistency:
72+
version number must correspond to the correct "Development Status" classifier
73+
:raises: ValueError if error found, but ideally this function does nothing
74+
"""
75+
V = lambda v: LooseVersion(v)
76+
# cast version
77+
version = V(version_str)
78+
79+
# get "Development Status" classifier
80+
dev_status_list = [x for x in CLASSIFIERS if x.startswith("Development Status ::")]
81+
if len(dev_status_list) != 1:
82+
raise ValueError("must be 1 'Development Status' in CLASSIFIERS")
83+
classifier = dev_status_list.pop()
84+
85+
version_map = [
86+
(V('0.1'), "Development Status :: 2 - Pre-Alpha"),
87+
(V('0.2'), "Development Status :: 3 - Alpha"),
88+
(V('0.3'), "Development Status :: 4 - Beta"),
89+
(V('1.0'), "Development Status :: 5 - Production/Stable"),
90+
]
91+
92+
for (test_ver, test_classifier) in reversed(sorted(version_map, key=lambda x: x[0])):
93+
if version >= test_ver:
94+
if classifier == test_classifier:
95+
return # all good, now forget any of this ever happened
96+
else:
97+
raise ValueError("for version {ver} classifier should be \n'{good}'\nnot\n'{bad}'".format(
98+
ver=str(version), good=test_classifier, bad=classifier
99+
))
100+
101+
68102
if __name__ == "__main__":
103+
version = find_meta("version")
104+
assert_version_classifier(version)
105+
69106
setup(
70107
name=NAME,
71108
description=find_meta("description"),
72109
license=find_meta("license"),
73110
url=find_meta("url"),
74-
version=find_meta("version"),
111+
version=version,
75112
author=find_meta("author"),
76113
author_email=find_meta("email"),
77114
maintainer=find_meta("author"),

src/pygcode.egg-info/PKG-INFO

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
Metadata-Version: 1.1
22
Name: pygcode
3-
Version: 0.2.0
3+
Version: 0.2.1
44
Summary: Basic g-code parser, interpreter, and encoder library.
55
Home-page: https://github.com/fragmuffin/pygcode
66
Author: Peter Boin
77
Author-email: peter.boin@gmail.com
88
License: GPLv3
9+
Description-Content-Type: UNKNOWN
910
Description: =======
1011
pygcode
1112
=======
@@ -33,7 +34,7 @@ Description: =======
3334

3435
Keywords: gcode,cnc,parser,interpreter
3536
Platform: UNKNOWN
36-
Classifier: Development Status :: 2 - Pre-Alpha
37+
Classifier: Development Status :: 3 - Alpha
3738
Classifier: Intended Audience :: Developers
3839
Classifier: Intended Audience :: Manufacturing
3940
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)

0 commit comments

Comments
 (0)