"""Parses Nastran fields"""
import re
from typing import Union, Optional, Any
from pyNastran.bdf.bdf_interface.bdf_card import BDFCard
from pyNastran.utils.numpy_utils import (
integer_types, integer_float_types, float_types)
from pyNastran.bdf.field_writer import print_card
#^ - start of string
#[-+]? - an optional (this is what ? means) minus or plus sign
#[0-9]+ - one or more digits (the plus means "one or more" and [0-9] is another way to say \d)
#$ - end of string
RE_INT = re.compile('^[-+]?[0-9]+$', flags=0)
#[-+]? - an optional (this is what ? means) minus or plus sign
# \. - period
# [-|+?] - required negative sign or optional plus sign
# [-|+] - required negative sign or plus sign
# [[0-9]+]? - optional N integers
#
# 1.032
# +1.032
# -1.032
#RE_FLOAT = re.compile('^[-+]?[0-9]+ \. [[0-9]+]$', flags=0)
# 1.032E+02
# +1.032E-02
# -1.032e+2
#RE_FLOAT_E = re.compile('^[-+]?[0-9]+ .[[0-9]+] [e|E] [-|+?] [0-9]+$', flags=0)
# 1.032D+02
# +1.032D-02
# -1.032d+02
#RE_FLOAT_D = re.compile('^[-+]?[0-9]+ .[[0-9]+] [d|D] [-|+?] [0-9]+$', flags=0)
#%e, %E, %f, %g [-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?
# 1.032+2
# +1.032-2
# -1.032+2
#RE_FLOAT_SHORT = re.compile('^[-+]?[0-9]+ \. [[0-9]+]? [-+] [0-9]+$', flags=0)
[docs]
def parse_components(card: BDFCard, ifield: int, fieldname: str) -> str:
"""
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
Returns
-------
components : str
a string of the dofs '0' or '123456' (not all are required)
"""
assert isinstance(card, BDFCard), type(card)
assert isinstance(ifield, int), type(ifield)
assert isinstance(fieldname, str), type(fieldname)
svalue = card.field(ifield)
if isinstance(svalue, integer_types):
pass
elif svalue is None or '.' in svalue:
dtype = _get_dtype(svalue)
msg = ('%s = %r (field #%s) on card must be an integer (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
raise SyntaxError(msg)
try:
value = int(svalue)
except ValueError:
dtype = _get_dtype(svalue)
msg = ('%s = %r (field #%s) on card must be an integer (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
raise SyntaxError(msg)
if value > 0 and isinstance(svalue, str):
if '0' in svalue:
value2 = str(svalue).replace('0', '')
msg = ('%s = %r (field #%s) on card must contain 0 or %s (not both).\n'
'card=%s' % (fieldname, svalue, ifield, value2, card))
raise SyntaxError(msg)
svalue2 = str(value)
svalue3 = ''.join(sorted(svalue2))
for i, component in enumerate(svalue3):
if component not in '0123456':
msg = ('%s = %r (field #%s) on card contains an invalid component %r.\n'
'card=%s' % (fieldname, svalue, ifield, component, card))
raise SyntaxError(msg)
if component in svalue3[i + 1:]:
msg = ('%s = %r (field #%s) on card must not contain duplicate entries.\n'
'card=%s' % (fieldname, svalue, ifield, card))
raise SyntaxError(msg)
return svalue3
[docs]
def parse_components_or_blank(card: BDFCard,
ifield: int, fieldname: str,
default: str='0') -> str:
"""
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
Returns
-------
components : str
a string of the dofs '0' or '123456' (not all are required)
"""
assert isinstance(card, BDFCard), type(card)
assert isinstance(ifield, int), type(ifield)
assert isinstance(fieldname, str), type(fieldname)
svalue = card.field(ifield)
if isinstance(svalue, integer_types):
pass
elif svalue is None:
return default
elif '.' in svalue:
dtype = _get_dtype(svalue)
msg = ('%s = %r (field #%s) on card must be an integer or blank (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
raise SyntaxError(msg)
try:
value = int(svalue)
except ValueError:
dtype = _get_dtype(svalue)
msg = ('%s = %r (field #%s) on card must be an integer or blank (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
raise SyntaxError(msg)
if value > 0 and isinstance(svalue, str):
if '0' in svalue:
value2 = str(svalue).replace('0', '')
msg = ('%s = %r (field #%s) on card must contain 0 or %s (not both).\n'
'card=%s' % (fieldname, svalue, ifield, value2, card))
raise SyntaxError(msg)
svalue2 = str(value)
svalue3 = ''.join(sorted(svalue2))
for i, component in enumerate(svalue3):
if component not in '0123456':
msg = ('%s = %r (field #%s) on card contains an invalid component %r.\n'
'card=%s' % (fieldname, svalue, ifield, component, card))
raise SyntaxError(msg)
if component in svalue3[i + 1:]:
msg = ('%s = %r (field #%s) on card must not contain duplicate entries.\n'
'card=%s' % (fieldname, svalue, ifield, card))
raise SyntaxError(msg)
return svalue3
[docs]
def components_or_blank(card: BDFCard,
ifield: int,
fieldname: str,
default: Optional[str]=None) -> Optional[str]:
"""
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
default : str, None
the default value for the field (default=None)
Returns
-------
components : str
a string of the dofs '0' or '123456' (not all are required)
"""
#assert isinstance(card, BDFCard), type(card)
assert isinstance(ifield, int), type(ifield)
assert isinstance(fieldname, str), type(fieldname)
#if default is not None:
#assert isinstance(default, str), f'component default={default!r} and must be a string'
svalue = card.field(ifield)
if svalue is None:
return default
elif isinstance(svalue, integer_types):
svalue = str(svalue)
else:
svalue = svalue.strip()
if svalue:
return parse_components(card, ifield, fieldname)
return default
[docs]
def blank(card: BDFCard, ifield: int, fieldname: str, default=None) -> None:
"""
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
default : None
the default value for the field (default=None)
"""
assert isinstance(card, BDFCard), type(card)
assert isinstance(ifield, int), type(ifield)
assert isinstance(fieldname, str), type(fieldname)
svalue = card.field(ifield)
if svalue is None:
return default
if isinstance(svalue, str):
svalue = svalue.strip().upper()
if len(svalue) == 0:
return default
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be blank (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
#def field(card: BDFCard, ifield: int, fieldname: str) -> Optional[Union[int, float, str]]:
#"""
#Parameters
#----------
#card : BDFCard()
#BDF card as a list
#ifield : int
#field number
#fieldname : str
#name of field
#Returns
#-------
#value : int, float, str, None
#the field value
#"""
#assert isinstance(card, BDFCard), type(card)
#assert isinstance(ifield, int), type(ifield)
#assert isinstance(fieldname, str), type(fieldname)
#return integer_double_string_or_blank(card, ifield, fieldname, default=None)
[docs]
def integer_double_string_or_blank(card: BDFCard, ifield: int, fieldname: str, default=None):
# type (BDFCard, int, str, Union[int, float, str]) -> Optional[Union[int, float, str]]
"""
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
default : int, float, str, None (default=None)
the default value for the field
Returns
-------
value : int, float, str, None
the field value
"""
svalue = card.field(ifield)
if isinstance(svalue, integer_float_types):
return svalue
elif svalue is None:
return default
svalue = svalue.strip().upper()
if svalue:
# integer/float/string
if '.' in svalue or '-' in svalue[1:] or '+' in svalue[1:]:
# float
try:
value = double(card, ifield, fieldname)
except SyntaxError:
value = interpret_value(card[ifield], card)
elif RE_INT.match(svalue): # svalue[0].isdigit() or svalue[1:].isdigit():
# int
try:
value = int(svalue)
except ValueError:
dtype = _get_dtype(svalue)
msg = ('%s = %r (field #%s) on card must be an integer, float, '
'or string (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
raise SyntaxError(msg)
elif ' ' in svalue:
raise SyntaxError('%s = %r (field #%s) on card must be an integer, float or string '
'(without a blank space).\n'
'card=%s' % (fieldname, svalue, ifield, card))
else:
value = svalue
return value
return default
#def assert_int_bounded_range(card, ifield, fieldname, lower=None, upper=None):
[docs]
def fields(func, card, fieldname, i, j=None) -> list[Any]:
"""
.. todo:: improve fieldname
"""
assert isinstance(card, BDFCard), type(card)
assert isinstance(fieldname, str), type(fieldname)
function_values = []
if j is None:
j = len(card)
for ii in range(i, j):
function_values.append(func(card, ii, fieldname + str(ii)))
return function_values
[docs]
def modal_components(card: BDFCard, ifield: int, fieldname: str) -> int:
"""
Gets the modal components (allows a -1 value); used by TIC
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
"""
value = integer(card, ifield, fieldname)
if not(-1 <= value <= 6):
raise SyntaxError('%s=%s (field #%s) on card must be an integer '
'(-1 <= val <= 6).\n'
'card=%s' % (fieldname, value, ifield, card))
return value
[docs]
def modal_components_or_blank(card: BDFCard, ifield: int, fieldname: str,
default: int) -> int:
"""
Gets the modal components (allows a -1 value); used by TIC
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
"""
value = integer_or_blank(card, ifield, fieldname, default=default)
if not(-1 <= value <= 6):
raise SyntaxError('%s=%s (field #%s) on card must be an integer '
'(-1 <= val <= 6).\n'
'card=%s' % (fieldname, value, ifield, card))
return value
[docs]
def integer(card: BDFCard, ifield: int, fieldname: str) -> int:
"""
Casts a value to an integer
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
"""
svalue = card.field(ifield)
if isinstance(svalue, float_types):
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an integer (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
try:
return int(svalue)
except(ValueError, TypeError):
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an integer (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
[docs]
def integer_or_blank(card: BDFCard, ifield: int, fieldname: str,
default: Optional[int]=None) -> int:
"""
Casts a value to an integer
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
default : int, None
the default value for the field (default=None)
"""
svalue = card.field(ifield)
if isinstance(svalue, integer_types):
return svalue
elif svalue is None:
return default
elif isinstance(svalue, str):
svalue = svalue.strip()
if len(svalue) == 0:
return default
elif '.' in svalue or '-' in svalue[1:] or '+' in svalue[1:]:
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an integer or blank (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
try:
return int(svalue)
except(ValueError, TypeError):
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an integer or blank (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an integer (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
[docs]
def double(card: BDFCard, ifield: int, fieldname: str, end: str='') -> float:
"""
Casts a value to a double
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
Returns
-------
value : float
the value from the desired field
"""
svalue = card.field(ifield)
if isinstance(svalue, float_types):
return svalue
elif isinstance(svalue, integer_types):
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be a float (not %s).\n'
'card=%s\n%s%s' % (fieldname, svalue, ifield, dtype, card, print_card(card), end))
elif svalue is None or len(svalue) == 0: ## None
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be a float (not %s).\n'
'card=%s\n%s%s' % (fieldname, svalue, ifield, dtype, card, print_card(card), end))
if svalue.isdigit(): # 1, not +1, or -1
# if only int
raise SyntaxError('%s = %r (field #%s) on card must be a float (not an integer).\n'
'card=%s\n%s%s' % (fieldname, svalue, ifield, card, print_card(card), end))
try:
# 1.0, 1.0E+3, 1.0E-3
value = float(svalue)
except TypeError:
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be a float (not %s).\n'
'card=%s\n%s%s' % (fieldname, svalue, ifield, dtype, card, print_card(card), end))
except ValueError:
# 1D+3, 1D-3, 1-3
try:
svalue = svalue.upper()
if 'D' in svalue:
# 1.0D+3, 1.0D-3
svalue2 = svalue.replace('D', 'E')
return float(svalue2)
# 1.0+3, 1.0-3
sign = ''
if svalue[0] in ('+', '-'):
sign = svalue[0]
svalue = svalue[1:]
if '+' in svalue:
svalue = sign + svalue.replace('+', 'E+')
elif '-' in svalue:
svalue = sign + svalue.replace('-', 'E-')
value = float(svalue)
except ValueError:
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be a float (not %s).\n'
'card=%s\n%s' % (fieldname, svalue, ifield, dtype, card, print_card(card)))
return value
[docs]
def double_from_str(svalue: str) -> float:
"""
Casts a value to a double
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
Returns
-------
value : float
the value from the desired field
"""
try:
# 1.0, 1.0E+3, 1.0E-3
value = float(svalue)
except TypeError:
dtype = _get_dtype(svalue)
raise SyntaxError(f'field = {svalue} on card must be a float (not {dtype}).')
except ValueError:
# 1D+3, 1D-3, 1-3
try:
svalue = svalue.upper()
if 'D' in svalue:
# 1.0D+3, 1.0D-3
svalue2 = svalue.replace('D', 'E')
return float(svalue2)
# 1.0+3, 1.0-3
sign = ''
if svalue[0] in ('+', '-'):
sign = svalue[0]
svalue = svalue[1:]
if '+' in svalue:
svalue = sign + svalue.replace('+', 'E+')
elif '-' in svalue:
svalue = sign + svalue.replace('-', 'E-')
value = float(svalue)
except ValueError:
dtype = _get_dtype(svalue)
raise SyntaxError(f'field = {svalue} on card must be a float (not {dtype}).')
return value
[docs]
def double_or_blank(card: BDFCard, ifield: int, fieldname: str,
default: Optional[float]=None,
end: str='') -> float:
"""
Casts a value to a double/blank
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
default : double, None
the default value for the field (default=None)
"""
svalue = card.field(ifield)
if isinstance(svalue, float_types):
return svalue
elif isinstance(svalue, integer_types):
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be a float or blank (not %s).\n'
'card=%s%s' % (fieldname, svalue, ifield, dtype, card, end))
elif isinstance(svalue, str):
svalue = svalue.strip().upper()
if not svalue:
return default
try:
return double(card, ifield, fieldname, end)
except Exception:
if svalue == '.':
return 0.
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be a float or blank (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
return default
[docs]
def double_or_string(card: BDFCard, ifield: int, fieldname: str) -> Union[float, str]:
"""
Casts a value to a double/string
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
"""
svalue = card.field(ifield)
if isinstance(svalue, float_types):
return svalue
elif svalue is None or isinstance(svalue, integer_types):
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an float or string (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
elif isinstance(svalue, str):
svalue = svalue.strip().upper()
if '.' in svalue or '-' in svalue[1:] or '+' in svalue[1:]:
# float
try:
return double(card, ifield, fieldname)
except Exception:
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an float or string (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
elif svalue.isdigit(): # 1, not +1, or -1
# fail
pass
elif svalue:
# string
if ' ' in svalue:
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an float or '
'string (without a blank space; not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
elif svalue[0].isdigit() or '.' in svalue or '+' in svalue or '-' in svalue:
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an float or '
'string (without a blank space; not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
return str(svalue)
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an float or string (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
[docs]
def double_string_or_blank(card: BDFCard, ifield: int, fieldname: str, default=None):
"""
Casts a value to an double/string/blank
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
default : double, None
the default value for the field (default=None)
Returns
-------
value : float / str / None
the typed value
:raises SyntaxError: if there is an invalid type
"""
svalue = card.field(ifield)
if isinstance(svalue, float_types):
return svalue
elif svalue is None:
return default
elif isinstance(svalue, str):
svalue = svalue.strip().upper()
elif isinstance(svalue, integer_types):
dtype = _get_dtype(svalue)
msg = ('%s = %r (field #%s) on card must be an float, string, or blank (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
raise SyntaxError(msg)
if '.' in svalue or '-' in svalue[1:] or '+' in svalue[1:]:
try:
return double(card, ifield, fieldname)
except Exception:
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be a float, string '
'or blank (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
elif svalue.isdigit(): # 1, not +1, or -1
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be a float, string or blank (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
elif svalue == '':
return default
if ' ' in svalue:
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an float, '
'string (without a blank space) or blank (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
return svalue
[docs]
def integer_or_double(card: BDFCard, ifield: int, fieldname: str) -> Union[int, float]:
"""
Casts a value to an integer/double
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
Returns
-------
value : int/float
the value with the proper type
:raises SyntaxError: if there's an invalid type
"""
svalue = card.field(ifield)
if isinstance(svalue, integer_float_types):
return svalue
elif svalue is None:
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an integer or float (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
if '.' in svalue or '-' in svalue[1:] or '+' in svalue[1:]:
# float/exponent
try:
value = double(card, ifield, fieldname)
except ValueError:
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be a integer or a float (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
else:
# int
try:
value = int(svalue)
except(ValueError, TypeError):
value = interpret_value(svalue, card)
if isinstance(value, (int, float)):
return value
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an integer or a '
'float (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
return value
[docs]
def integer_double_or_blank(card: BDFCard, ifield: int, fieldname: str, default=None):
"""
Casts a value to an integer/double/blank
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
default : int / float / None
the default value for the field (default=None)
"""
svalue = card.field(ifield)
if isinstance(svalue, integer_float_types):
return svalue
elif svalue is None:
return default
if svalue:
svalue = svalue.strip()
if svalue == '':
return default
# integer/float
try:
return integer_or_double(card, ifield, fieldname)
except Exception:
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an integer, float, or '
'blank (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
return default
[docs]
def integer_or_string(card: BDFCard, ifield: int, fieldname: str) -> Union[int, str]:
"""
Casts a value to an integer/string
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
default : int / str
the default value for the field (default=None)
"""
svalue = card.field(ifield)
if isinstance(svalue, integer_types):
return svalue
elif isinstance(svalue, float_types):
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an integer or string (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
elif svalue is None:
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an integer or string (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
try:
value = int(svalue)
return value
except ValueError:
pass
svalue = svalue.strip()
if svalue[0].isdigit():
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an integer or string (not %s; '
'strings must start with a character).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
elif ' ' in svalue:
raise SyntaxError('%s = %r (field #%s) on card must be an integer or string '
'(without a blank space).\n'
'card=%s' % (fieldname, svalue, ifield, card))
# string
try:
value = double_from_str(svalue)
except SyntaxError:
return str(svalue.upper())
if isinstance(value, float_types):
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an integer or string (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
raise RuntimeError(f'unhandled integer_or_string; value={svalue}')
[docs]
def integer_string_or_blank(card: BDFCard, ifield: int, fieldname: str, default=None):
"""
Casts a value to an integer/string/blank
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
default : int, str, None
the default value for the field (default=None)
"""
svalue = card.field(ifield)
if isinstance(svalue, integer_types):
return svalue
elif svalue is None:
return default
elif isinstance(svalue, float_types):
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an integer or string (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
svalue = svalue.strip()
if svalue:
# integer/string
try:
return integer_or_string(card, ifield, fieldname)
except Exception:
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an integer, '
'string (without a blank space), or blank (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
return default
def _get_dtype(value):
"""
Get the type of the input value in a form that is clear.
Parameters
----------
value : int/float/str/None
the value to get the type of
Returns
-------
dtype : str
the type of the value
"""
try:
value = interpret_value(value)
except Exception:
pass
if value is None:
dtype = 'blank'
elif isinstance(value, integer_types):
dtype = 'an integer'
elif isinstance(value, float):
dtype = 'a double value=%r' % value
elif isinstance(value, str):
dtype = 'a string'
else:
dtype = str(type(value))
return dtype
[docs]
def integer_double_or_string(card: BDFCard, ifield: int, fieldname: str) -> Union[int, float, str]:
"""
Casts a value to an integer/double/string
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
Returns
-------
value : varies
the value of the field
"""
svalue = card.field(ifield)
if isinstance(svalue, integer_float_types):
return svalue
elif svalue is None:
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an integer or float (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
svalue = str(svalue.strip())
if svalue: # integer/float/string
if '.' in svalue or '-' in svalue or '+' in svalue:
# float
value = double(card, ifield, fieldname)
elif svalue.isdigit(): # 1, not +1, or -1
# int
try:
value = int(svalue)
except(ValueError, TypeError):
raise SyntaxError('%s = %r (field #%s) on card must be an integer, float, '
'or string (not blank).\n'
'card=%s' % (fieldname, svalue, ifield, card))
elif ' ' in svalue:
raise SyntaxError('%s = %r (field #%s) on card must be an integer, float, or string '
'(not a string with a blank).\n'
'card=%s' % (fieldname, svalue, ifield, card))
elif svalue[0].isdigit():
raise SyntaxError('%s = %r (field #%s) on card must be an integer, float, or string '
'(not a string with a leading integer).\n'
'card=%s' % (fieldname, svalue, ifield, card))
else:
value = interpret_value(svalue, card)
return value
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be an integer, float, or string (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
[docs]
def string(card: BDFCard, ifield: int, fieldname: str) -> str:
"""
Casts a value to a string
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
Returns
-------
value : str
the value of the field
"""
svalue = card.field(ifield)
if isinstance(svalue, str):
svalue = svalue.strip()
if ' ' in svalue:
raise SyntaxError('%s = %r (field #%s) on card must be a string without a space.\n'
'card=%s' % (fieldname, svalue, ifield, card))
else:
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be a string (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
if svalue[0].isdigit() or '.' in svalue or '+' in svalue or '-' in svalue[0]:
value = integer_or_double(card, ifield, fieldname)
dtype = _get_dtype(value)
raise SyntaxError('%s = %r (field #%s) on card must be a '
'string with a character (not %s).\n'
'card=%s' % (fieldname, value, ifield, dtype, card))
if svalue: # string
return str(svalue.upper())
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be a string (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
[docs]
def check_string(svalue: str, ifield: int, fieldname: str) -> str:
"""
strings can't have the following characters: ' '
strings can't have the following characters in the 0th position: '.', '+', '-', 1-9
"""
if isinstance(svalue, str):
svalue = svalue.strip()
if ' ' in svalue:
raise SyntaxError('%s = %r (field #%s) on card must be a string without a space.\n' % (
fieldname, svalue, ifield))
else:
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be a string (not %s).\n' % (
fieldname, svalue, ifield, dtype))
if svalue[0].isdigit() or '.' in svalue or '+' in svalue or '-' in svalue[0]:
#value = integer_or_double(card, ifield, fieldname)
#dtype = _get_dtype(value)
raise SyntaxError('%s = %s (field #%s) on card must be a '
'string with a character.\n' % (
fieldname, svalue, ifield))
if svalue: # string
return str(svalue.upper())
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be a string (not %s).\n' % (
fieldname, svalue, ifield, dtype))
[docs]
def string_or_blank(card: BDFCard, ifield: int, fieldname: str, default=None):
"""
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
default : str, None
the default value for the field (default=None)
Returns
-------
value : varies
the value of the field
"""
svalue = card.field(ifield)
if svalue is None:
return default
elif isinstance(svalue, str):
svalue = svalue.strip().upper()
if ' ' in svalue:
raise SyntaxError('%s = %r (field #%s) on card must be a string without a space.\n'
'card=%s' % (fieldname, svalue, ifield, card))
if len(svalue) and (svalue[0].isdigit() or '.' in svalue or '+' in svalue or '-' in svalue[0]):
chars = ''.join(list(set('%s.+-' % svalue[0] if svalue[0].isdigit() else '')))
raise SyntaxError('%s = %r (field #%s) on card must not have the '
'following characters %s\n'
'card=%s' % (fieldname, svalue, ifield, chars, card))
else:
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be a string (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
svalue = svalue.strip()
if len(svalue) and (svalue.isdigit() or '.' in svalue or '+' in svalue or '-' in svalue[0]):
# integer or float
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be a string or blank (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
if svalue: # string
return str(svalue.upper())
return default
[docs]
def string_choice_or_blank(card: BDFCard, ifield: int, fieldname: str, choices: tuple[str], default=None):
"""
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
default : str, None
the default value for the field (default=None)
Returns
-------
value : varies
the value of the field
"""
svalue = card.field(ifield)
if svalue is None:
return default
elif isinstance(svalue, str):
svalue = svalue.strip().upper()
else:
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be a string (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
if svalue: # string
svalue = svalue.upper()
if svalue not in choices:
raise RuntimeError(f'{fieldname} = {svalue} (field #{ifield}) on card is a string, but must be {choices}.\n'
f'card={card}')
return svalue
return default
[docs]
def filename_or_blank(card: BDFCard, ifield: int, fieldname: str, default=None):
"""
Used by the MKAEROZ to read a filename
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
default : str, None
the default value for the field (default=None)
Returns
-------
value : varies
the value of the field
"""
svalue = card.field(ifield)
if svalue is None:
return default
elif isinstance(svalue, str):
svalue = svalue.strip().upper()
if ' ' in svalue:
raise SyntaxError('%s = %r (field #%s) on card must be a string without a space.\n'
'card=%s' % (fieldname, svalue, ifield, card))
if svalue[0].isdigit() or '+' in svalue or '-' in svalue[0]:
chars = ''.join(list(set('%s+-' % svalue[0] if svalue[0].isdigit() else '')))
raise SyntaxError('%s = %r (field #%s) on card must not have the '
'following characters %s\n'
'card=%s' % (fieldname, svalue, ifield, chars, card))
else:
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be a string (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
svalue = svalue.strip()
if svalue.isdigit() or '+' in svalue or '-' in svalue[0]:
# integer or float
dtype = _get_dtype(svalue)
raise SyntaxError('%s = %r (field #%s) on card must be a string or blank (not %s).\n'
'card=%s' % (fieldname, svalue, ifield, dtype, card))
if svalue: # string
return str(svalue.upper())
return default
[docs]
def loose_string(card: BDFCard, ifield: int, fieldname: str, default=None):
"""
The most lenient of string checks:
Matches X, X1, 1X, 111, 1.0
Doesn't matches X, X1, 1X, 111, 1.0
Things that might be incorrect:
No embedded blanks (not enforced now)
Used for LABELs on DRESP1. This will be tightened up as necessary.
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
Returns
-------
value : varies
the value of the field
"""
svalue = card.field(ifield)
#elif isinstance(svalue, str):
#svalue = svalue.strip().upper()
#if ' ' in svalue:
#raise SyntaxError('%s = %r (field #%s) on card must be a string without a space.\n'
#'card=%s' % (fieldname, svalue, ifield, card))
#if svalue[0].isdigit() or '+' in svalue or '-' in svalue[0]:
#chars = ''.join(list(set('%s+-' % svalue[0] if svalue[0].isdigit() else '')))
#raise SyntaxError('%s = %r (field #%s) on card must not have the '
#'following characters %s\n'
#'card=%s' % (fieldname, svalue, ifield, chars, card))
#else:
#dtype = _get_dtype(svalue)
#raise SyntaxError('%s = %r (field #%s) on card must be a string (not %s).\n'
#'card=%s' % (fieldname, svalue, ifield, dtype, card))
#svalue = svalue.strip()
#if svalue.isdigit() or '+' in svalue or '-' in svalue[0]:
## integer or float
#dtype = _get_dtype(svalue)
#raise SyntaxError('%s = %r (field #%s) on card must be a string or blank (not %s).\n'
#'card=%s' % (fieldname, svalue, ifield, dtype, card))
svalue = str(svalue.upper())
if svalue[0].isdigit():
raise SyntaxError('%s = %r (field #%s) on card must not have an integer as the first character.\n'
'card=%s' % (fieldname, svalue, ifield, card))
return default
[docs]
def exact_string_or_blank(card: BDFCard, ifield: int, fieldname: str, default=None):
"""
Parameters
----------
card : BDFCard()
BDF card as a list
ifield : int
field number
fieldname : str
name of field
default : str, None
the default value for the field (default=None)
Returns
-------
value : varies
the value of the field
"""
svalue = card.field(ifield)
if svalue is None:
return default
svalue = '%-8s' % svalue
if svalue == '':
return default
return svalue
# int - done
# int/blank - done
# int/float - done
# int/float/blank - done
# int/float/string - done
# int/float/string/blank - done
# int/string - done
# int/string/blank - done
# float - done
# float/blank - done
# float/string - done
# float/string/blank - done
# string - done
# string/blank - done
[docs]
def interpret_value(value_raw: Optional[str],
card: Union[str, BDFCard]='') -> Union[int, float, str, None]:
"""
Converts a value from nastran format into python format.
Parameters
----------
raw_value : str
a string representation of a value
card : str
???
Returns
-------
value : varies
the Nastran reprentation of the value
"""
if value_raw is None:
return None
try:
value_in = value_raw.lstrip().rstrip(' *').upper()
except AttributeError:
# it's already an int/float
msg = 'value_raw=%s type=%s' % (value_raw, type(value_raw))
assert isinstance(value_raw, integer_float_types), msg
return value_raw
if len(value_in) == 0:
# blank / None
return None
if value_in[0].isalpha():
# string
return value_in
if '=' in value_in or '(' in value_in or '*' in value_raw:
return value_raw.strip()
# int, float, string, exponent
value_positive = value_in.strip('+-')
if value_positive.isdigit():
# int
return int(value_in)
try:
value = float(value_in)
# float
return value
except ValueError:
pass
#if('=' in value_in or '(' in value_in or ')' in value_in):
#print("=()!")
#return value_in
# if there are non-floats/scientific notation -> string
no_ed = list(set(value_in) - set('ED 1234567890+-'))
word = ''.join(no_ed)
if word.isalpha():
# word
return value_in
val0 = value_in[0]
if val0 in ('+', '-'):
# truncate the sign for now
value_left = value_in[1:]
else:
# inplied positive value
val0 = '+'
value_left = value_in
if val0 == '-':
factor = -1.
elif val0 == '+' or val0.isdigit():
factor = 1.
else:
raise SyntaxError('the only 2 cases for a float/scientific are +/- for v0...'
'value_raw=%r val0=%r card=%s' % (value_raw, val0, card))
# dont include the 1st character, find the exponent
val_minus = value_in.find('-', 1)
val_plus = value_in.find('+', 1)
if val_minus > 0:
sline = value_left.split('-')
exp_factor = -1.
elif val_plus > 0:
sline = value_left.split('+')
exp_factor = 1.
else:
card_msg = ''
if card:
card_msg = 'card = %s\n' % card
msg = ("I thought this was in scientific notation, but I can't find "
"the exponent sign...\n"
"value_raw=%r value_left=%r\n%s"
"You also might have mixed tabs/spaces/commas or misaligned fields."
% (value_raw, value_left, card_msg))
raise SyntaxError(msg)
if sline[0][-1] == 'D':
sline[0] = sline[0][:-1]
try:
sci0 = factor * float(sline[0])
sci1 = exp_factor * int(sline[1])
except ValueError:
msg = "val_minus=%s val_plus=%s value_raw=%r" % (val_minus, val_plus, value_raw)
raise SyntaxError("cannot parse '%s' into a float and '%s' "
'into an integer\n%s\nYou HAVE mixed '
'tabs/spaces/commas!' % (sline[0], sline[1], msg))
value = sci0 * 10 ** sci1
# scientific
return value