|
From: <kin...@us...> - 2024-11-28 06:18:03
|
Revision: 7245
http://sourceforge.net/p/teem/code/7245
Author: kindlmann
Date: 2024-11-28 06:18:02 +0000 (Thu, 28 Nov 2024)
Log Message:
-----------
synching Tenum with GLKs SciVis class python wrappers, adding TenumVal and TenumValParseAction from that
Modified Paths:
--------------
teem/trunk/python/cffi/teem.py
Modified: teem/trunk/python/cffi/teem.py
===================================================================
--- teem/trunk/python/cffi/teem.py 2024-11-28 06:13:22 UTC (rev 7244)
+++ teem/trunk/python/cffi/teem.py 2024-11-28 06:18:02 UTC (rev 7245)
@@ -32,6 +32,8 @@
import math as _math # # likely used in _BIFF_DICT, below, for testing function return values
+import argparse as _argparse
+
# halt if python2; thanks to https://stackoverflow.com/a/65407535/1465384
_x, *_y = 1, 2 # NOTE: A SyntaxError means you need Python3, not Python2
del _x, _y
@@ -52,7 +54,9 @@
def __init__(self, aenm, _name):
"""Constructor takes a Teem airEnum pointer (const airEnum *const)."""
if not str(aenm).startswith("<cdata 'airEnum *' "):
- raise TypeError(f'passed argument {aenm} does not seem to be an airEnum pointer')
+ raise TypeError(
+ f'passed argument {aenm} does not seem to be an airEnum pointer'
+ )
self.aenm = aenm
self.name = string(self.aenm.name)
self._name = _name # the variable name for the airEnum in libteem
@@ -69,6 +73,10 @@
"""Provides a way to iterate through the valid values of the enum"""
return iter(self.vals)
+ def vals(self):
+ """Provides list of valid values"""
+ return self._vals.copy()
+
def valid(self, ios) -> bool: # ios = int or string
"""Answers whether given int is a valid value of enum, or whether given string
is a valid string in enum, depending on incoming type.
@@ -80,15 +88,20 @@
# else
raise TypeError(f'Need an int or str argument (not {type(ios)})')
- def str(self, val: int, picky=False) -> str:
- """Converts from integer enum value val to string identifier
- (wraps airEnumStr())"""
+ def str(self, val: int, picky=False, excls=ValueError) -> str:
+ """Converts from integer enum value val to string identifier.
+ If picky, then failure to parse string generates an exception,
+ of class excls (defaults to ValueError) (wraps airEnumStr())"""
assert isinstance(val, int), f'Need an int argument (not {type(val)})'
if picky and not self.valid(val):
- raise ValueError(f'{val} not a valid {self._name} ("{self.name}") enum value')
+ raise excls(f'{val} not a valid {self._name} ("{self.name}") enum value')
# else
- return string(_teem.lib.airEnumStr(self.aenm, val))
+ return _teem.ffi.string(_teem.lib.airEnumStr(self.aenm, val)).decode('utf8')
+ def strs(self):
+ """Provides a list of strings for the valid values"""
+ return [self.str(v) for v in self.vals()]
+
def desc(self, val: int) -> str:
"""Converts from integer value val to description string
(wraps airEnumDesc())"""
@@ -101,7 +114,9 @@
assert isinstance(sss, str), f'Need an string argument (not {type(sss)})'
ret = _teem.lib.airEnumVal(self.aenm, sss.encode('ascii'))
if picky and ret == self.unknown():
- raise ValueError(f'"{sss}" not parsable as {self._name} ("{self.name}") enum value')
+ raise ValueError(
+ f'"{sss}" not parsable as {self._name} ("{self.name}") enum value'
+ )
# else
return ret
@@ -111,6 +126,62 @@
return _teem.lib.airEnumUnknown(self.aenm)
+class TenumVal:
+ """Represents one value in a Tenum, in a way that can be both an int and a string,
+ and that remembers which Tenum it is part of"""
+
+ def __init__(self, tenum, ios):
+ """Create enum value from Tenum and either int or string value"""
+ if not isinstance(tenum, Tenum):
+ raise ValueError(f'Given {tenum=} not actually a Tenum')
+ if not tenum.valid(ios):
+ raise ValueError(f'Given {ios=} not member of enum {tenum.name}')
+ self.tenum = tenum
+ self.val = ios if isinstance(ios, int) else tenum.val(ios)
+
+ def __str__(self):
+ """Return own value as string"""
+ return self.tenum.str(self.val)
+
+ def __int__(self):
+ """Return own value as int"""
+ return self.val
+
+ def __repr__(self):
+ """Full string representation of own value
+ (though currently nothing knows how to parse this)"""
+ return f'{self.tenum.str(self.val)}:({self.tenum.name} enum)'
+
+ def __eq__(self, other):
+ """Test equality between two things"""
+ if isinstance(other, TenumVal):
+ if self.tenum != other.tenum:
+ return False
+ # else other same kind of tenum
+ return self.val == other.val
+ # else other not a tenum
+ if not self.tenum.valid(other):
+ raise ValueError(f'Given {other=} not member of enum {self.tenum.name}')
+ oval = other if isinstance(other, int) else self.tenum.val(other)
+ return self.val == oval
+
+
+class TenumValParseAction(_argparse.Action):
+ """Custom argparse action for parsing a TenumVal from the command-line"""
+
+ def __init__(self, option_strings, dest, tenum, **kwargs):
+ super().__init__(option_strings, dest, **kwargs)
+ # Store the enum we want to parse
+ self.tenum = tenum
+
+ def __call__(self, _parser, namespace, string, _option_string=None):
+ # parse value from string
+ val = self.tenum.val(string, True, _argparse.ArgumentTypeError)
+ tval = TenumVal(self.tenum, val)
+ # Set the parsed result in the namespace
+ setattr(namespace, self.dest, tval)
+
+
def _equals_one(val): # likely used in _BIFF_DICT, below
"""Returns True iff given val equals 1"""
return val == 1
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|