Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 49 additions & 8 deletions synapse/lib/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ def __init__(self, modl, name, info, opts, skipinit=False):
self.types = (self.name,) + self.info['bases'][::-1]

self.opts = dict(self._opt_defs)

for optn in opts.keys():
if optn not in self.opts:
mesg = f'Type option {optn} is not valid for type {self.name}.'
raise s_exc.BadTypeDef(mesg=mesg)

self.opts.update(opts)

self._type_norms = {} # python type to norm function map str: _norm_str
Expand Down Expand Up @@ -541,18 +547,27 @@ class Array(Type):
isarray = True
ismutable = True

_opt_defs = (
('type', None), # type: ignore
('uniq', True), # type: ignore
('split', None), # type: ignore
('sorted', True), # type: ignore
('typeopts', None), # type: ignore
)

def postTypeInit(self):

self.isuniq = self.opts.get('uniq', True)
self.issorted = self.opts.get('sorted', True)
self.splitstr = self.opts.get('split', None)
self.isuniq = self.opts.get('uniq')
self.issorted = self.opts.get('sorted')
self.splitstr = self.opts.get('split')

typename = self.opts.get('type')
if typename is None:
mesg = 'Array type requires type= option.'
raise s_exc.BadTypeDef(mesg=mesg)

typeopts = self.opts.get('typeopts', {})
if (typeopts := self.opts.get('typeopts')) is None:
typeopts = {}

basetype = self.modl.type(typename)
if basetype is None:
Expand Down Expand Up @@ -687,6 +702,11 @@ class Comp(Type):

stortype = s_layer.STOR_TYPE_MSGP

_opt_defs = (
('sepr', None), # type: ignore
('fields', ()), # type: ignore
)

def postTypeInit(self):
self.setNormFunc(list, self._normPyTuple)
self.setNormFunc(tuple, self._normPyTuple)
Expand All @@ -698,7 +718,7 @@ def postTypeInit(self):
self._checkMutability()

self.fieldtypes = {}
for fname, ftypename in self.opts.get('fields', ()):
for fname, ftypename in self.opts.get('fields'):
if isinstance(ftypename, str):
_type = self.modl.type(ftypename)
else:
Expand All @@ -713,7 +733,7 @@ def postTypeInit(self):
self.fieldtypes[fname] = _type

def _checkMutability(self):
for fname, ftypename in self.opts.get('fields', ()):
for fname, ftypename in self.opts.get('fields'):
if isinstance(ftypename, (list, tuple)):
ftypename = ftypename[0]

Expand Down Expand Up @@ -1296,6 +1316,7 @@ class Int(IntBase):
_opt_defs = (
('size', 8), # type: ignore # Set the storage size of the integer type in bytes.
('signed', True),
('enums', None),
('enums:strict', True),

('fmt', '%d'), # Set to an integer compatible format string to control repr.
Expand All @@ -1316,6 +1337,13 @@ def postTypeInit(self):
mesg = f'Invalid integer size ({self.size})'
raise s_exc.BadTypeDef(mesg=mesg)

self.ismin = self.opts.get('ismin')
self.ismax = self.opts.get('ismax')

if self.opts.get('ismin') and self.opts.get('ismax'):
mesg = f'Int type ({self.name}) has both ismin and ismax set.'
raise s_exc.BadTypeDef(mesg=mesg)

self.enumnorm = {}
self.enumrepr = {}

Expand Down Expand Up @@ -1363,10 +1391,10 @@ def postTypeInit(self):

def merge(self, oldv, newv):

if self.opts.get('ismin'):
if self.ismin:
return min(oldv, newv)

if self.opts.get('ismax'):
if self.ismax:
return max(oldv, newv)

return newv
Expand Down Expand Up @@ -1994,6 +2022,11 @@ class Ndef(Type):

stortype = s_layer.STOR_TYPE_NDEF

_opt_defs = (
('forms', None), # type: ignore
('interface', None), # type: ignore
)

def postTypeInit(self):
self.setNormFunc(list, self._normPyTuple)
self.setNormFunc(tuple, self._normPyTuple)
Expand Down Expand Up @@ -2118,6 +2151,10 @@ class Data(Type):

stortype = s_layer.STOR_TYPE_MSGP

_opt_defs = (
('schema', None), # type: ignore
)

def postTypeInit(self):
self.validator = None
schema = self.opts.get('schema')
Expand Down Expand Up @@ -2745,6 +2782,10 @@ def postTypeInit(self):
self.ismin = self.opts.get('ismin')
self.ismax = self.opts.get('ismax')

if self.ismin and self.ismax:
mesg = f'Time type ({self.name}) has both ismin and ismax set.'
raise s_exc.BadTypeDef(mesg=mesg)

precstr = self.opts.get('precision')
self.prec = s_time.precisions.get(precstr)

Expand Down
2 changes: 1 addition & 1 deletion synapse/models/economic.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
('econ:invoice', ('guid', {}), {
'doc': 'An invoice issued requesting payment.'}),

('econ:price', ('hugenum', {'norm': False}), {
('econ:price', ('hugenum', {}), {
'doc': 'The amount of money expected, required, or given in payment for something.',
'ex': '2.20'}),

Expand Down
6 changes: 5 additions & 1 deletion synapse/models/geospace.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,11 +218,15 @@

class Dist(s_types.Int):

_opt_defs = (
('baseoff', 0), # type: ignore
) + s_types.Int._opt_defs

def postTypeInit(self):
s_types.Int.postTypeInit(self)
self.setNormFunc(int, self._normPyInt)
self.setNormFunc(str, self._normPyStr)
self.baseoff = self.opts.get('baseoff', 0)
self.baseoff = self.opts.get('baseoff')

async def _normPyInt(self, valu, view=None):
return valu, {}
Expand Down
2 changes: 1 addition & 1 deletion synapse/models/gov.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
),
'doc': 'A US Social Security Number (SSN).'}),

('gov:us:zip', ('int', {'regex': '^[0-9]{5}'}), {
Copy link
Contributor Author

@Cisphyx Cisphyx Dec 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a note to the 2x-3x model mapping to figure out if this is supposed to be an int with min/max or str with regex because int with regex isn't a thing.

('gov:us:zip', ('int', {'min': 0, 'max': 99999}), {
'doc': 'A US Postal Zip Code.'}),

('gov:us:cage', ('str', {'lower': True}), {
Expand Down
13 changes: 11 additions & 2 deletions synapse/models/inet.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ class IPAddr(s_types.Type):

stortype = s_layer.STOR_TYPE_IPADDR

_opt_defs = (
('version', None), # type: ignore
)

def postTypeInit(self):

self.setCmprCtor('>=', self._ctorCmprGe)
Expand Down Expand Up @@ -370,6 +374,11 @@ async def cmpr(valu):

class SockAddr(s_types.Str):

_opt_defs = (
('defport', None), # type: ignore
('defproto', 'tcp'), # type: ignore
) + s_types.Str._opt_defs

protos = ('tcp', 'udp', 'icmp', 'gre')
noports = ('gre', 'icmp')

Expand All @@ -383,8 +392,8 @@ def postTypeInit(self):
self.porttype = self.modl.type('inet:port')
self.prototype = self.modl.type('str').clone({'lower': True})

self.defport = self.opts.get('defport', None)
self.defproto = self.opts.get('defproto', 'tcp')
self.defport = self.opts.get('defport')
self.defproto = self.opts.get('defproto')

self.virtindx |= {
'ip': 'ip',
Expand Down
2 changes: 1 addition & 1 deletion synapse/models/syn.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ async def _liftRuntSynTagProp(view, prop, cmprvalu=None):
('package', ('str', {}), {
'doc': 'Storm package which provided the command.'}),

('svciden', ('guid', {'strip': True}), {
('svciden', ('guid', {}), {
'doc': 'Storm service iden which provided the package.'}),

('deprecated', ('bool', {}), {
Expand Down
4 changes: 4 additions & 0 deletions synapse/tests/test_datamodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ async def test_datamodel_basics(self):
core.model.addFormProp('test:str', 'bar', ('newp', {}), {})
self.isin('No type named newp while declaring prop test:str:bar.', cm.exception.get('mesg'))

with self.raises(s_exc.BadTypeDef) as cm:
core.model.addType('_foo:type', 'int', {'foo': 'bar'}, {})
self.isin('Type option foo is not valid', cm.exception.get('mesg'))

async def test_datamodel_formname(self):
modl = s_datamodel.Model()
mods = (
Expand Down
10 changes: 5 additions & 5 deletions synapse/tests/test_lib_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,9 @@ async def test_int(self):
self.raises(s_exc.BadTypeDef, model.type('int').clone, {'enums': ((1, 'hehe'), (2, 'haha'), (3, 'HAHA'))})
self.raises(s_exc.BadTypeDef, model.type('int').clone, {'enums': ((1, 'hehe'), (2, 'haha'), (2, 'beep'))})

with self.raises(s_exc.BadTypeDef):
model.type('int').clone({'ismin': True, 'ismax': True})

async def test_float(self):
model = s_datamodel.Model()
t = model.type('float')
Expand Down Expand Up @@ -1827,11 +1830,8 @@ async def test_time(self):

self.gt(s_common.now(), (await ttime.norm('-1hour'))[0])

tminmax = ttime.clone({'min': True, 'max': True})
# Merge testing with tminmax
now = s_common.now()
self.eq(now + 1, tminmax.merge(now, now + 1))
self.eq(now, tminmax.merge(now + 1, now))
with self.raises(s_exc.BadTypeDef):
ttime.clone({'ismin': True, 'ismax': True})

async with self.getTestCore() as core:

Expand Down
4 changes: 2 additions & 2 deletions synapse/tests/test_model_syn.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,15 +192,15 @@ async def delExtModelConfigs(cortex):
node = nodes[0]
self.eq(('syn:type', 'comp'), node.ndef)
self.none(node.get('subof'))
self.none(node.get('opts'))
self.eq({'sepr': None, 'fields': ()}, node.get('opts'))
self.eq('synapse.lib.types.Comp', node.get('ctor'))
self.eq('The base type for compound node fields.', node.get('doc'))

nodes = await core.nodes('syn:type=test:comp')
self.len(1, nodes)
node = nodes[0]
self.eq(('syn:type', 'test:comp'), node.ndef)
self.eq({'fields': (('hehe', 'test:int'), ('haha', 'test:lower'))},
self.eq({'fields': (('hehe', 'test:int'), ('haha', 'test:lower')), 'sepr': None},
node.get('opts'))
self.eq('comp', node.get('subof'))
self.eq('synapse.lib.types.Comp', node.get('ctor'))
Expand Down
6 changes: 3 additions & 3 deletions synapse/tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ def repr(self, valu):
}),
),
'types': (
('test:type10', ('test:type', {'foo': 10}), {
('test:type10', ('test:type', {}), {
'doc': 'A fake type.'}),

('test:lower', ('str', {'lower': True}), {}),
Expand Down Expand Up @@ -377,7 +377,7 @@ def repr(self, valu):
('intprop', ('int', {'min': 20, 'max': 30}), {}),
('int2', ('int', {}), {}),
('strprop', ('str', {'lower': 1}), {}),
('guidprop', ('guid', {'lower': 1}), {}),
('guidprop', ('guid', {}), {}),
('locprop', ('loc', {}), {}),
)),

Expand Down Expand Up @@ -493,7 +493,7 @@ def repr(self, valu):
('test:zeropad', {}, ()),
('test:ival', {}, (
('interval', ('ival', {}), {}),
('daymax', ('ival', {'precision': 'day', 'maxfill': True}), {}),
('daymax', ('ival', {'precision': 'day'}), {}),
)),

('test:pivtarg', {}, (
Expand Down