fixed over-usage of assert

This commit is contained in:
Peter Boin 2017-07-09 11:32:37 +10:00
parent 0ae4e08b81
commit 988ee9db94
5 changed files with 65 additions and 27 deletions

View File

@ -2,6 +2,17 @@
# ===================== Parsing Exceptions ===================== # ===================== Parsing Exceptions =====================
class GCodeBlockFormatError(Exception): class GCodeBlockFormatError(Exception):
"""Raised when errors encountered while parsing block text""" """Raised when errors encountered while parsing block text"""
pass
# ===================== Parsing Exceptions ===================== class GCodeParameterError(Exception):
"""Raised for conflicting / invalid / badly formed parameters"""
class GCodeWordStrError(Exception):
"""Raised when issues found while parsing a word string"""
# ===================== Machine Exceptions =====================
class MachineInvalidAxis(Exception):
"""Raised if an axis is invalid"""
# For example: for axes X/Y/Z, set the value of "Q"; wtf?
class MachineInvalidState(Exception):
"""Raised if a machine state is set incorrectly, or in conflict"""

View File

@ -3,6 +3,8 @@ from copy import copy
from .words import Word from .words import Word
from .exceptions import GCodeParameterError
# Terminology of a "G-Code" # Terminology of a "G-Code"
# For the purposes of this library, so-called "G" codes do not necessarily # For the purposes of this library, so-called "G" codes do not necessarily
# use the letter "G" in their word; other letters include M, F, S, and T # use the letter "G" in their word; other letters include M, F, S, and T
@ -196,8 +198,11 @@ class GCode(object):
:param word: Word instance :param word: Word instance
""" """
assert isinstance(word, Word), "invalid parameter class: %r" % word assert isinstance(word, Word), "invalid parameter class: %r" % word
assert word.letter in self.param_letters, "invalid parameter for %s: %s" % (self.__class__.__name__, str(word)) if word.letter not in self.param_letters:
assert word.letter not in self.params, "parameter defined twice: %s -> %s" % (self.params[word.letter], word) raise GCodeParameterError("invalid parameter for %s: %s" % (self.__class__.__name__, str(word)))
if word.letter in self.params:
raise GCodeParameterError("parameter defined twice: %s -> %s" % (self.params[word.letter], word))
self.params[word.letter] = word self.params[word.letter] = word
def __getattr__(self, key): def __getattr__(self, key):
@ -243,7 +248,7 @@ class GCode(object):
:param machine: Machine instance, to change state :param machine: Machine instance, to change state
:return: GCodeEffect instance; effect the gcode just had on machine :return: GCodeEffect instance; effect the gcode just had on machine
""" """
from .machine import Machine # importing high-level state from .machine import Machine # importing up (done live to avoid dependency loop)
assert isinstance(machine, Machine), "invalid parameter" assert isinstance(machine, Machine), "invalid parameter"
# Set mode # Set mode

View File

@ -11,6 +11,7 @@ from .block import Block
from .line import Line from .line import Line
from .words import Word from .words import Word
from .exceptions import MachineInvalidAxis, MachineInvalidState
UNIT_IMPERIAL = GCodeUseInches.unit_id # G20 UNIT_IMPERIAL = GCodeUseInches.unit_id # G20
UNIT_METRIC = GCodeUseMillimeters.unit_id # G21 UNIT_METRIC = GCodeUseMillimeters.unit_id # G21
@ -37,7 +38,8 @@ class Position(object):
axes = self.__class__.default_axes axes = self.__class__.default_axes
else: else:
invalid_axes = set(axes) - self.POSSIBLE_AXES invalid_axes = set(axes) - self.POSSIBLE_AXES
assert not invalid_axes, "invalid axes proposed %s" % invalid_axes if invalid_axes:
raise MachineInvalidAxis("invalid axes proposed %s" % invalid_axes)
self.__dict__['axes'] = set(axes) & self.POSSIBLE_AXES self.__dict__['axes'] = set(axes) & self.POSSIBLE_AXES
# Unit # Unit
@ -61,7 +63,7 @@ class Position(object):
if key in self.axes: if key in self.axes:
self._value[key] = value self._value[key] = value
elif key in self.POSSIBLE_AXES: elif key in self.POSSIBLE_AXES:
raise AssertionError("'%s' axis is not defined to be set" % key) raise MachineInvalidAxis("'%s' axis is not defined to be set" % key)
else: else:
self.__dict__[key] = value self.__dict__[key] = value
@ -86,14 +88,16 @@ class Position(object):
# Arithmetic # Arithmetic
def __add__(self, other): def __add__(self, other):
assert not (self.axes ^ other.axes), "axes: %r != %r" % (self.axes, other.axes) if self.axes ^ other.axes:
raise MachineInvalidAxis("axes: %r != %r" % (self.axes, other.axes))
new_obj = copy(self) new_obj = copy(self)
for k in new_obj._value: for k in new_obj._value:
new_obj._value[k] += other._value[k] new_obj._value[k] += other._value[k]
return new_obj return new_obj
def __sub__(self, other): def __sub__(self, other):
assert not (other.axes - self.axes), "for a - b: axes in b, that are not in a: %r" % (other.axes - self.axes) if other.axes - self.axes:
raise MachineInvalidAxis("for a - b: axes in b, that are not in a: %r" % (other.axes - self.axes))
new_obj = copy(self) new_obj = copy(self)
for k in other._value: for k in other._value:
new_obj._value[k] -= other._value[k] new_obj._value[k] -= other._value[k]
@ -277,11 +281,12 @@ class Mode(object):
# clear mode group # clear mode group
self.modal_groups[MODAL_GROUP_MAP[key]] = None self.modal_groups[MODAL_GROUP_MAP[key]] = None
else: else:
# set mode group explicitly # set mode group explicitly, not advisable
# (recommended to use self.set_mode(value) instead) # (recommended to use self.set_mode(value) instead)
assert isinstance(value, GCode), "invalid value type: %r" % value if not isinstance(value, GCode):
assert value.modal_group == MODAL_GROUP_MAP[key], \ raise MachineInvalidState("invalid mode value: %r" % value)
"cannot set '%s' mode as %r, wrong group" % (key, value) if value.modal_group != MODAL_GROUP_MAP[key]:
raise MachineInvalidState("cannot set '%s' mode as %r, wrong group" % (key, value))
self.modal_groups[MODAL_GROUP_MAP[key]] = value.modal_copy() self.modal_groups[MODAL_GROUP_MAP[key]] = value.modal_copy()
else: else:
self.__dict__[key] = value self.__dict__[key] = value
@ -329,6 +334,21 @@ class Machine(object):
if coord_sys_mode: if coord_sys_mode:
self.state.cur_coord_sys = coord_sys_mode.coord_system_id self.state.cur_coord_sys = coord_sys_mode.coord_system_id
def modal_gcode(self, modal_params):
if not modal_params:
return None
if self.mode.motion is None:
raise MachineInvalidState("unable to assign modal parameters when no motion mode is set")
(modal_gcodes, unasigned_words) = words2gcodes([self.mode.motion.word] + modal_params)
if unasigned_words:
raise MachineInvalidState("modal parameters '%s' cannot be assigned when in mode: %r" % (
' '.join(str(x) for x in unasigned_words), self.mode
))
if modal_gcodes:
assert len(modal_gcodes) == 1, "more than 1 modal code found"
return modal_gcodes[0]
return None
def process(self, *gcode_list, **kwargs): def process(self, *gcode_list, **kwargs):
""" """
Process gcodes Process gcodes
@ -338,12 +358,9 @@ class Machine(object):
# Add modal gcode to list of given gcodes # Add modal gcode to list of given gcodes
modal_params = kwargs.get('modal_params', []) modal_params = kwargs.get('modal_params', [])
if modal_params: if modal_params:
assert self.mode.motion is not None, "unable to assign modal parameters when no motion mode is set" modal_gcode = self.modal_gcode(modal_params)
(modal_gcodes, unasigned_words) = words2gcodes([self.mode.motion.word] + modal_params) if modal_gcode:
assert unasigned_words == [], "modal parameters '%s' unknown when in mode: %r" % ( gcode_list.append(modal_gcode)
' '.join(str(x) for x in unasigned_words), self.mode
)
gcode_list += modal_gcodes
for gcode in sorted(gcode_list): for gcode in sorted(gcode_list):
gcode.process(self) # shifts ownership of what happens now to GCode class gcode.process(self) # shifts ownership of what happens now to GCode class

View File

@ -2,7 +2,7 @@ import re
import itertools import itertools
import six import six
from .exceptions import GCodeBlockFormatError from .exceptions import GCodeBlockFormatError, GCodeWordStrError
REGEX_FLOAT = re.compile(r'^-?(\d+\.?\d*|\.\d+)') # testcase: ..tests.test_words.WordValueMatchTests.test_float REGEX_FLOAT = re.compile(r'^-?(\d+\.?\d*|\.\d+)') # testcase: ..tests.test_words.WordValueMatchTests.test_float
REGEX_INT = re.compile(r'^-?\d+') REGEX_INT = re.compile(r'^-?\d+')
@ -201,10 +201,13 @@ WORD_MAP = {
class Word(object): class Word(object):
def __init__(self, *args): def __init__(self, *args):
assert len(args) in [1, 2], "input arguments either: (letter, value) or (word_str)" if len(args) not in (1, 2):
raise AssertionError("input arguments either: (letter, value) or (word_str)")
if len(args) == 2: if len(args) == 2:
# Word('G', 90)
(letter, value) = args (letter, value) = args
else: else:
# Word('G90')
word_str = args[0] word_str = args[0]
letter = word_str[0] # first letter letter = word_str[0] # first letter
value = word_str[1:] # rest of string value = word_str[1:] # rest of string
@ -300,7 +303,7 @@ def text2words(block_text):
value_regex = WORD_MAP[letter]['value_regex'] value_regex = WORD_MAP[letter]['value_regex']
value_match = value_regex.search(block_text[index:]) value_match = value_regex.search(block_text[index:])
if value_match is None: if value_match is None:
raise GCodeBlockFormatError("word '%s' value invalid" % letter) raise GCodeWordStrError("word '%s' value invalid" % letter)
value = value_match.group() # matched text value = value_match.group() # matched text
yield Word(letter, value) yield Word(letter, value)
@ -311,13 +314,14 @@ def text2words(block_text):
remainder = block_text[index:] remainder = block_text[index:]
if remainder and re.search(r'\S', remainder): if remainder and re.search(r'\S', remainder):
raise GCodeBlockFormatError("block code remaining '%s'" % remainder) raise GCodeWordStrError("block code remaining '%s'" % remainder)
def str2word(word_str): def str2word(word_str):
words = list(text2words(word_str)) words = list(text2words(word_str))
if words: if words:
assert len(words) <= 1, "more than one word given" if len(words) > 1:
raise GCodeWordStrError("more than one word given")
return words[0] return words[0]
return None return None

View File

@ -7,6 +7,7 @@ add_pygcode_to_path()
# Units under test # Units under test
from pygcode.machine import Position, Machine from pygcode.machine import Position, Machine
from pygcode.line import Line from pygcode.line import Line
from pygcode.exceptions import MachineInvalidAxis
class PositionTests(unittest.TestCase): class PositionTests(unittest.TestCase):
@ -56,9 +57,9 @@ class PositionTests(unittest.TestCase):
self.assertEqual(p1 + p2, Position(axes='XYZ', X=1, Y=12, Z=-20)) self.assertEqual(p1 + p2, Position(axes='XYZ', X=1, Y=12, Z=-20))
p3 = Position(axes='XYZA') p3 = Position(axes='XYZA')
with self.assertRaises(AssertionError): with self.assertRaises(MachineInvalidAxis):
p1 + p3 # mismatched axes p1 + p3 # mismatched axes
with self.assertRaises(AssertionError): with self.assertRaises(MachineInvalidAxis):
p3 + p1 # mismatched axes p3 + p1 # mismatched axes
def test_arithmetic_sub(self): def test_arithmetic_sub(self):
@ -68,7 +69,7 @@ class PositionTests(unittest.TestCase):
p3 = Position(axes='XYZA') p3 = Position(axes='XYZA')
p3 - p1 # fine p3 - p1 # fine
with self.assertRaises(AssertionError): with self.assertRaises(MachineInvalidAxis):
p1 - p3 # mismatched axes p1 - p3 # mismatched axes
def test_arithmetic_multiply(self): def test_arithmetic_multiply(self):