Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduces is* functions for strings #3432

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
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
190 changes: 188 additions & 2 deletions synapse/lib/stormtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4398,9 +4398,135 @@ class Str(Prim):
'desc': 'Keyword values which are substituted into the string.', },
),
'returns': {'type': 'str', 'desc': 'The new string.', }}},
{'name': 'json', 'desc': 'Parse a JSON string and return the deserialized data.',
'type': {'type': 'function', '_funcname': '_methStrJson', 'args': (),
{'name': 'json', 'desc': 'Parse a JSON string and return the deserialized data.',
'type': {'type': 'function', '_funcname': '_methStrJson', 'args': (),
'returns': {'type': 'prim', 'desc': 'The JSON deserialized object.', }}},
{'name': 'isAlnum', 'desc': '''
Returns true if all chars in the string are alphanumeric, false otherwise.

Examples:
Test if string `aca123` is alphanumeric::

$foo="aca123" return ( $foo.isAlnum() ) // true
''',
'type': {'type': 'function', '_funcname': '_methStrIsAlnum',
'returns': {'type': 'bool', 'desc': 'Whether string is alphanumeric', }}},
{'name': 'isAlpha', 'desc': '''
Returns true if all chars in the string are in the alphabet, false otherwise.

Examples:
Test if string `aca` contains only letters in the alphabet::

$foo="aca" return ( $foo.isAlpha() ) // true
''',
'type': {'type': 'function', '_funcname': '_methStrIsAlpha',
'returns': {'type': 'bool', 'desc': 'Whether string only contains chars from alphabet', }}},
{'name': 'isAscii', 'desc': '''
Returns true if all chars in the string are ASCII chars, false otherwise.

Examples:
Test if string `aca` contains only letters in the alphabet::

$foo="aca" return ( $foo.isAscii() ) // true
''',
'type': {'type': 'function', '_funcname': '_methStrIsASCII',
'returns': {'type': 'bool', 'desc': 'Whether all the chars are ASCII', }}},
{'name': 'isDecimal', 'desc': '''
Returns true if all the chars are decimals (including unicode), false otherwise.

Examples:
Test if string `123` contains only decimals::

$foo="123" return ( $foo.isDecimal() ) // true
''',
'type': {'type': 'function', '_funcname': '_methStrIsDecimal',
'returns': {'type': 'bool', 'desc': 'Whether all the chars are decimals', }}},
{'name': 'isDigit', 'desc': '''
Returns true if all the chars are decimals, false otherwise.
Exponents are considered as digits.

Examples:
Test if string `123` contains only digits::

$foo="123" return ( $foo.isDigit() ) // true
''',
'type': {'type': 'function', '_funcname': '_methStrIsDigit',
'returns': {'type': 'bool', 'desc': 'Whether all the chars are digits', }}},
{'name': 'isIdentifier', 'desc': '''
Returns true if the string is a valid identifier, false otherwise.
A valid identifier only contains alphanumeric letters (a-z) and (0-9), or underscores (_).
and cannot start with a number, or contain any spaces.

Examples:
Test if string `aca_123` is a valid identifier::

$foo="aca_123" return ( $foo.isIdentifier() ) // true
''',
'type': {'type': 'function', '_funcname': '_methStrIsIdentifier',
'returns': {'type': 'bool', 'desc': 'Whether the string is a valid identifier', }}},
{'name': 'isLower', 'desc': '''
Returns true if all the chars are in lower case, false otherwise.
Numbers, symbols and spaces are not checked, only alphabet characters.

Examples:
Test if string `aca` only contains lower case chars::

$foo="aca" return ( $foo.isLower() ) // true
''',
'type': {'type': 'function', '_funcname': '_methStrIsLower',
'returns': {'type': 'bool', 'desc': 'Whether all chars are in lower case', }}},
{'name': 'isNumeric', 'desc': '''
Returns true if all the chars are numeric, false otherwise.
Unicode fractions are considered as numeric, but not decimals like `1.5`.

Examples:
Test if string `123` only contains numeric chars::

$foo="123" return ( $foo.isNumeric() ) // true
''',
'type': {'type': 'function', '_funcname': '_methStrIsNumeric',
'returns': {'type': 'bool', 'desc': 'Whether all chars are numeric', }}},
{'name': 'isPrintable', 'desc': '''
Returns true if all the chars are printable, false otherwise.

Examples:
Test if string `aca 123` only contains printable chars::

$foo="aca 123" return ( $foo.isPrintable() ) // true
''',
'type': {'type': 'function', '_funcname': '_methStrIsPrintable',
'returns': {'type': 'bool', 'desc': 'Whether all chars are printable', }}},
{'name': 'isSpace', 'desc': '''
Returns true if all the chars are whitespaces, false otherwise.

Examples:
Test if string ` ` only contains whitespaces::

$foo=" " return ( $foo.isSpace() ) // true
''',
'type': {'type': 'function', '_funcname': '_methStrIsSpace',
'returns': {'type': 'bool', 'desc': 'Whether all chars are whitespaces', }}},
{'name': 'isTitle', 'desc': '''
Returns true if all words in a text start with a upper case letter and others are lower case, false otherwise.

Examples:
Test if string `Aca Test` has words start with a upper case letter and others are lower case::

$foo="Aca Test" return ( $foo.isTitle() ) // true
''',
'type': {'type': 'function', '_funcname': '_methStrIsTitle',
'returns': {'type': 'bool', 'desc': 'Whether all words starts with an upper case', }}},
{'name': 'isUpper', 'desc': '''
Returns true if all the characters are in upper case, false otherwise.
Numbers, symbols and spaces are not checked, only alphabet characters.

Examples:
Test if string `ACA` only contains upper case chars::

$foo="ACA" return ( $foo.isUpper() ) // true
''',
'type': {'type': 'function', '_funcname': '_methStrIsUpper',
'returns': {'type': 'bool', 'desc': 'Whether all chars are upper case', }}},
)
_storm_typename = 'str'
_ismutable = False
Expand Down Expand Up @@ -4431,6 +4557,18 @@ def getObjLocals(self):
'reverse': self._methStrReverse,
'format': self._methStrFormat,
'json': self._methStrJson,
'isAlnum': self._methStrIsAlNum,
'isAlpha': self._methStrIsAlpha,
'isAscii': self._methStrIsASCII,
'isDecimal': self._methStrIsDecimal,
'isDigit': self._methStrIsDigit,
'isIdentifier': self._methStrIsIdentifier,
'isLower': self._methStrIsLower,
'isNumeric': self._methStrIsNumeric,
'isPrintable': self._methStrIsPrintable,
'isSpace': self._methStrIsSpace,
'isTitle': self._methStrIsTitle,
'isUpper': self._methStrIsUpper,
}

def __int__(self):
Expand Down Expand Up @@ -4554,6 +4692,54 @@ async def _methStrJson(self):
mesg = f'Text is not valid JSON: {self.valu}'
raise s_exc.BadJsonText(mesg=mesg)

@stormfunc(readonly=True)
async def _methStrIsAlNum(self):
return self.valu.isalnum()

@stormfunc(readonly=True)
async def _methStrIsAlpha(self):
return self.valu.isalpha()

@stormfunc(readonly=True)
async def _methStrIsASCII(self):
return self.valu.isascii()

@stormfunc(readonly=True)
async def _methStrIsDecimal(self):
return self.valu.isdecimal()

@stormfunc(readonly=True)
async def _methStrIsDigit(self):
return self.valu.isdigit()

@stormfunc(readonly=True)
async def _methStrIsIdentifier(self):
return self.valu.isidentifier()

@stormfunc(readonly=True)
async def _methStrIsLower(self):
return self.valu.islower()

@stormfunc(readonly=True)
async def _methStrIsNumeric(self):
return self.valu.isnumeric()

@stormfunc(readonly=True)
async def _methStrIsPrintable(self):
return self.valu.isprintable()

@stormfunc(readonly=True)
async def _methStrIsSpace(self):
return self.valu.isspace()

@stormfunc(readonly=True)
async def _methStrIsTitle(self):
return self.valu.istitle()

@stormfunc(readonly=True)
async def _methStrIsUpper(self):
return self.valu.isupper()

@registry.registerType
class Bytes(Prim):
'''
Expand Down
25 changes: 25 additions & 0 deletions synapse/tests/test_lib_stormtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1302,6 +1302,31 @@ async def test_storm_lib_str(self):
q = '$foo="hehe {haha} {newp}" return ( $foo.format(haha=yup, baz=faz) )'
self.eq('hehe yup {newp}', await core.callStorm(q))

self.true(await core.callStorm('$foo="aca123" return ( $foo.isAlnum() )'))
self.false(await core.callStorm('$foo="$aca 123" return ( $foo.isAlnum() )'))
self.true(await core.callStorm('$foo="aca" return ( $foo.isAlpha() )'))
self.false(await core.callStorm('$foo="123" return ( $foo.isAlpha() )'))
self.true(await core.callStorm('$foo="aca123!" return ( $foo.isAscii() )'))
self.false(await core.callStorm('$foo="é" return ( $foo.isAscii() )'))
self.true(await core.callStorm('$foo="123" return ( $foo.isDecimal() )'))
self.false(await core.callStorm('$foo="a" return ( $foo.isDecimal() )'))
self.true(await core.callStorm('$foo="123" return ( $foo.isDigit() )'))
self.false(await core.callStorm('$foo="a" return ( $foo.isDigit() )'))
self.true(await core.callStorm('$foo="aca_123" return ( $foo.isIdentifier() )'))
self.false(await core.callStorm('$foo="aca 123" return ( $foo.isIdentifier() )'))
self.true(await core.callStorm('$foo="aca" return ( $foo.isLower() )'))
self.false(await core.callStorm('$foo="ACA" return ( $foo.isLower() )'))
self.true(await core.callStorm('$foo="123" return ( $foo.isNumeric() )'))
self.false(await core.callStorm('$foo="aca123" return ( $foo.isNumeric() )'))
self.true(await core.callStorm('$foo="aca" return ( $foo.isPrintable() )'))
self.false(await core.callStorm('$foo="\x0b" return ( $foo.isPrintable() )'))
self.true(await core.callStorm('$foo=" " return ( $foo.isSpace() )'))
self.false(await core.callStorm('$foo="not_a_space" return ( $foo.isSpace() )'))
self.true(await core.callStorm('$foo="Hello" return ( $foo.isTitle() )'))
self.false(await core.callStorm('$foo="hello" return ( $foo.isTitle() )'))
self.true(await core.callStorm('$foo="ACA" return ( $foo.isUpper() )'))
self.false(await core.callStorm('$foo="aca" return ( $foo.isUpper() )'))

# tuck the regx tests in with str
self.true(await core.callStorm(r'''return($lib.regex.matches('^foo', foobar))'''))
self.true(await core.callStorm(r'''return($lib.regex.matches('foo', FOOBAR, $lib.regex.flags.i))'''))
Expand Down