synapse 2.152.0__py311-none-any.whl → 2.154.0__py311-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of synapse might be problematic. Click here for more details.

Files changed (87) hide show
  1. synapse/axon.py +19 -16
  2. synapse/cortex.py +203 -15
  3. synapse/exc.py +0 -2
  4. synapse/lib/ast.py +42 -23
  5. synapse/lib/autodoc.py +2 -2
  6. synapse/lib/cache.py +16 -1
  7. synapse/lib/cell.py +5 -5
  8. synapse/lib/httpapi.py +198 -2
  9. synapse/lib/layer.py +5 -2
  10. synapse/lib/modelrev.py +36 -3
  11. synapse/lib/node.py +2 -5
  12. synapse/lib/parser.py +1 -1
  13. synapse/lib/schemas.py +51 -0
  14. synapse/lib/snap.py +10 -0
  15. synapse/lib/storm.lark +24 -4
  16. synapse/lib/storm.py +98 -19
  17. synapse/lib/storm_format.py +1 -1
  18. synapse/lib/stormhttp.py +11 -4
  19. synapse/lib/stormlib/auth.py +16 -2
  20. synapse/lib/stormlib/backup.py +1 -0
  21. synapse/lib/stormlib/basex.py +2 -0
  22. synapse/lib/stormlib/cell.py +7 -0
  23. synapse/lib/stormlib/compression.py +3 -0
  24. synapse/lib/stormlib/cortex.py +1168 -0
  25. synapse/lib/stormlib/ethereum.py +1 -0
  26. synapse/lib/stormlib/graph.py +2 -0
  27. synapse/lib/stormlib/hashes.py +5 -0
  28. synapse/lib/stormlib/hex.py +6 -0
  29. synapse/lib/stormlib/infosec.py +6 -1
  30. synapse/lib/stormlib/ipv6.py +1 -0
  31. synapse/lib/stormlib/iters.py +58 -1
  32. synapse/lib/stormlib/json.py +5 -0
  33. synapse/lib/stormlib/mime.py +1 -0
  34. synapse/lib/stormlib/model.py +19 -3
  35. synapse/lib/stormlib/modelext.py +1 -0
  36. synapse/lib/stormlib/notifications.py +2 -0
  37. synapse/lib/stormlib/pack.py +2 -0
  38. synapse/lib/stormlib/random.py +1 -0
  39. synapse/lib/stormlib/smtp.py +0 -7
  40. synapse/lib/stormlib/stats.py +223 -0
  41. synapse/lib/stormlib/stix.py +8 -0
  42. synapse/lib/stormlib/storm.py +1 -0
  43. synapse/lib/stormlib/version.py +3 -0
  44. synapse/lib/stormlib/xml.py +3 -0
  45. synapse/lib/stormlib/yaml.py +2 -0
  46. synapse/lib/stormtypes.py +250 -170
  47. synapse/lib/trigger.py +180 -4
  48. synapse/lib/types.py +1 -1
  49. synapse/lib/version.py +2 -2
  50. synapse/lib/view.py +55 -6
  51. synapse/models/inet.py +21 -6
  52. synapse/models/orgs.py +48 -2
  53. synapse/models/risk.py +126 -2
  54. synapse/models/syn.py +6 -0
  55. synapse/tests/files/stormpkg/badapidef.yaml +13 -0
  56. synapse/tests/files/stormpkg/storm/modules/apimod +10 -0
  57. synapse/tests/files/stormpkg/testpkg.yaml +23 -0
  58. synapse/tests/test_axon.py +7 -2
  59. synapse/tests/test_cortex.py +231 -35
  60. synapse/tests/test_lib_ast.py +138 -43
  61. synapse/tests/test_lib_autodoc.py +1 -1
  62. synapse/tests/test_lib_modelrev.py +9 -0
  63. synapse/tests/test_lib_node.py +55 -0
  64. synapse/tests/test_lib_storm.py +14 -1
  65. synapse/tests/test_lib_stormhttp.py +65 -6
  66. synapse/tests/test_lib_stormlib_auth.py +12 -3
  67. synapse/tests/test_lib_stormlib_cortex.py +1327 -0
  68. synapse/tests/test_lib_stormlib_iters.py +116 -0
  69. synapse/tests/test_lib_stormlib_stats.py +187 -0
  70. synapse/tests/test_lib_stormlib_storm.py +8 -0
  71. synapse/tests/test_lib_stormsvc.py +24 -1
  72. synapse/tests/test_lib_stormtypes.py +124 -69
  73. synapse/tests/test_lib_trigger.py +315 -0
  74. synapse/tests/test_lib_view.py +1 -2
  75. synapse/tests/test_model_base.py +26 -0
  76. synapse/tests/test_model_inet.py +22 -0
  77. synapse/tests/test_model_orgs.py +28 -0
  78. synapse/tests/test_model_risk.py +73 -0
  79. synapse/tests/test_tools_autodoc.py +25 -0
  80. synapse/tests/test_tools_genpkg.py +9 -3
  81. synapse/tests/utils.py +39 -0
  82. synapse/tools/autodoc.py +42 -2
  83. {synapse-2.152.0.dist-info → synapse-2.154.0.dist-info}/METADATA +2 -2
  84. {synapse-2.152.0.dist-info → synapse-2.154.0.dist-info}/RECORD +87 -79
  85. {synapse-2.152.0.dist-info → synapse-2.154.0.dist-info}/WHEEL +1 -1
  86. {synapse-2.152.0.dist-info → synapse-2.154.0.dist-info}/LICENSE +0 -0
  87. {synapse-2.152.0.dist-info → synapse-2.154.0.dist-info}/top_level.txt +0 -0
synapse/lib/stormtypes.py CHANGED
@@ -205,8 +205,13 @@ class StormTypesRegistry:
205
205
  for parameter, argdef in zip(callsig.parameters.values(), args):
206
206
  pdef = parameter.default # defaults to inspect._empty for undefined default values.
207
207
  adef = argdef.get('default', inspect._empty)
208
- assert pdef == adef, \
209
- f'Default value mismatch for {obj} {funcname}, defvals {pdef} != {adef} for {parameter}'
208
+ # Allow $lib.undef as a defined default to represent the undef constant.
209
+ if pdef is undef:
210
+ assert adef == '$lib.undef', \
211
+ f'Expected $lib.undef for default value {obj} {funcname}, defvals {pdef} != {adef} for {parameter}'
212
+ else:
213
+ assert pdef == adef, \
214
+ f'Default value mismatch for {obj} {funcname}, defvals {pdef} != {adef} for {parameter}'
210
215
 
211
216
  def _validateStor(self, obj, info, name):
212
217
  rtype = info.get('type')
@@ -228,9 +233,9 @@ class StormTypesRegistry:
228
233
  args = rtype.get('args')
229
234
  assert args is None, f'ctors have no defined args funcname=[{funcname}] for {obj} {info.get("name")}'
230
235
  callsig = getCallSig(locl)
231
- # Assert the callsig for a stor has one argument
236
+ # Assert the callsig for a ctor has one argument
232
237
  callsig_args = [str(v).split('=')[0] for v in callsig.parameters.values()]
233
- assert len(callsig_args) == 1, f'stor funcs must only have one argument for {obj} {info.get("name")}'
238
+ assert len(callsig_args) == 1, f'ctor funcs must only have one argument for {obj} {info.get("name")}'
234
239
 
235
240
  def _validateGtor(self, obj, info, name):
236
241
  rtype = info.get('type')
@@ -625,6 +630,7 @@ class LibPkg(Lib):
625
630
  verify = await tobool(verify)
626
631
  await self.runt.snap.core.addStormPkg(pkgdef, verify=verify)
627
632
 
633
+ @stormfunc(readonly=True)
628
634
  async def _libPkgGet(self, name):
629
635
  name = await tostr(name)
630
636
  pkgdef = await self.runt.snap.core.getStormPkg(name)
@@ -633,6 +639,7 @@ class LibPkg(Lib):
633
639
 
634
640
  return Dict(pkgdef)
635
641
 
642
+ @stormfunc(readonly=True)
636
643
  async def _libPkgHas(self, name):
637
644
  name = await tostr(name)
638
645
  pkgdef = await self.runt.snap.core.getStormPkg(name)
@@ -644,10 +651,12 @@ class LibPkg(Lib):
644
651
  self.runt.confirm(('pkg', 'del'), None)
645
652
  await self.runt.snap.core.delStormPkg(name)
646
653
 
654
+ @stormfunc(readonly=True)
647
655
  async def _libPkgList(self):
648
656
  pkgs = await self.runt.snap.core.getStormPkgs()
649
657
  return list(sorted(pkgs, key=lambda x: x.get('name')))
650
658
 
659
+ @stormfunc(readonly=True)
651
660
  async def _libPkgDeps(self, pkgdef):
652
661
  pkgdef = await toprim(pkgdef)
653
662
  return await self.runt.snap.core.verifyStormPkgDeps(pkgdef)
@@ -743,12 +752,15 @@ class LibDmon(Lib):
743
752
 
744
753
  await self.runt.snap.core.delStormDmon(iden)
745
754
 
755
+ @stormfunc(readonly=True)
746
756
  async def _libDmonGet(self, iden):
747
757
  return await self.runt.snap.core.getStormDmon(iden)
748
758
 
759
+ @stormfunc(readonly=True)
749
760
  async def _libDmonList(self):
750
761
  return await self.runt.snap.core.getStormDmons()
751
762
 
763
+ @stormfunc(readonly=True)
752
764
  async def _libDmonLog(self, iden):
753
765
  self.runt.confirm(('dmon', 'log'))
754
766
  return await self.runt.snap.core.getStormDmonLog(iden)
@@ -930,12 +942,14 @@ class LibService(Lib):
930
942
  await self._checkSvcGetPerm(ssvc)
931
943
  return Service(self.runt, ssvc)
932
944
 
945
+ @stormfunc(readonly=True)
933
946
  async def _libSvcHas(self, name):
934
947
  ssvc = self.runt.snap.core.getStormSvc(name)
935
948
  if ssvc is None:
936
949
  return False
937
950
  return True
938
951
 
952
+ @stormfunc(readonly=True)
939
953
  async def _libSvcList(self):
940
954
  self.runt.confirm(('service', 'list'))
941
955
  retn = []
@@ -949,6 +963,7 @@ class LibService(Lib):
949
963
 
950
964
  return retn
951
965
 
966
+ @stormfunc(readonly=True)
952
967
  async def _libSvcWait(self, name, timeout=None):
953
968
  name = await tostr(name)
954
969
  timeout = await toint(timeout, noneok=True)
@@ -1006,6 +1021,7 @@ class LibTags(Lib):
1006
1021
  'prefix': self.prefix,
1007
1022
  }
1008
1023
 
1024
+ @stormfunc(readonly=True)
1009
1025
  async def prefix(self, names, prefix, ispart=False):
1010
1026
 
1011
1027
  prefix = await tostr(prefix)
@@ -1375,6 +1391,7 @@ class LibBase(Lib):
1375
1391
  'trycast': self.trycast,
1376
1392
  }
1377
1393
 
1394
+ @stormfunc(readonly=True)
1378
1395
  async def _libBaseImport(self, name, debug=False, reqvers=None):
1379
1396
 
1380
1397
  name = await tostr(name)
@@ -1512,12 +1529,15 @@ class LibBase(Lib):
1512
1529
  for item in sorted(valu, reverse=reverse):
1513
1530
  yield item
1514
1531
 
1532
+ @stormfunc(readonly=True)
1515
1533
  async def _set(self, *vals):
1516
1534
  return Set(vals)
1517
1535
 
1536
+ @stormfunc(readonly=True)
1518
1537
  async def _list(self, *vals):
1519
1538
  return List(list(vals))
1520
1539
 
1540
+ @stormfunc(readonly=True)
1521
1541
  async def _text(self, *args):
1522
1542
  valu = ''.join(args)
1523
1543
  return Text(valu)
@@ -1707,6 +1727,7 @@ class LibPs(Lib):
1707
1727
  todo = s_common.todo('kill', self.runt.user, idens[0])
1708
1728
  return await self.dyncall('cell', todo)
1709
1729
 
1730
+ @stormfunc(readonly=True)
1710
1731
  async def _list(self):
1711
1732
  todo = s_common.todo('ps', self.runt.user)
1712
1733
  return await self.dyncall('cell', todo)
@@ -1766,15 +1787,18 @@ class LibStr(Lib):
1766
1787
  'format': self.format,
1767
1788
  }
1768
1789
 
1790
+ @stormfunc(readonly=True)
1769
1791
  async def concat(self, *args):
1770
1792
  strs = [await tostr(a) for a in args]
1771
1793
  return ''.join(strs)
1772
1794
 
1795
+ @stormfunc(readonly=True)
1773
1796
  async def format(self, text, **kwargs):
1774
1797
  text = await kwarg_format(text, **kwargs)
1775
1798
 
1776
1799
  return text
1777
1800
 
1801
+ @stormfunc(readonly=True)
1778
1802
  async def join(self, sepr, items):
1779
1803
  strs = [await tostr(item) async for item in toiter(items)]
1780
1804
  return sepr.join(strs)
@@ -1913,16 +1937,18 @@ class LibAxon(Lib):
1913
1937
  {'name': 'readlines', 'desc': '''
1914
1938
  Yields lines of text from a plain-text file stored in the Axon.
1915
1939
 
1916
- Example:
1917
- Get the lines for a given file::
1940
+ Examples:
1918
1941
 
1919
- for $line in $lib.axon.readlines($sha256) {
1920
- $dostuff($line)
1921
- }
1942
+ // Get the lines for a given file.
1943
+ for $line in $lib.axon.readlines($sha256) {
1944
+ $dostuff($line)
1945
+ }
1922
1946
  ''',
1923
1947
  'type': {'type': 'function', '_funcname': 'readlines',
1924
1948
  'args': (
1925
1949
  {'name': 'sha256', 'type': 'str', 'desc': 'The SHA256 hash of the file.'},
1950
+ {'name': 'errors', 'type': 'str', 'default': 'ignore',
1951
+ 'desc': 'Specify how encoding errors should handled.'},
1926
1952
  ),
1927
1953
  'returns': {'name': 'yields', 'type': 'str',
1928
1954
  'desc': 'A line of text from the file.'}}},
@@ -1940,6 +1966,8 @@ class LibAxon(Lib):
1940
1966
  'type': {'type': 'function', '_funcname': 'jsonlines',
1941
1967
  'args': (
1942
1968
  {'name': 'sha256', 'type': 'str', 'desc': 'The SHA256 hash of the file.'},
1969
+ {'name': 'errors', 'type': 'str', 'default': 'ignore',
1970
+ 'desc': 'Specify how encoding errors should handled.'},
1943
1971
  ),
1944
1972
  'returns': {'name': 'yields', 'type': 'any',
1945
1973
  'desc': 'A JSON object parsed from a line of text.'}}},
@@ -1967,6 +1995,8 @@ class LibAxon(Lib):
1967
1995
  {'name': 'sha256', 'type': 'str', 'desc': 'The SHA256 hash of the file.'},
1968
1996
  {'name': 'dialect', 'type': 'str', 'desc': 'The default CSV dialect to use.',
1969
1997
  'default': 'excel'},
1998
+ {'name': 'errors', 'type': 'str', 'default': 'ignore',
1999
+ 'desc': 'Specify how encoding errors should handled.'},
1970
2000
  {'name': '**fmtparams', 'type': 'any', 'desc': 'Format arguments.'},
1971
2001
  ),
1972
2002
  'returns': {'name': 'yields', 'type': 'list',
@@ -2018,16 +2048,18 @@ class LibAxon(Lib):
2018
2048
  return {str(k): str(v) for k, v in item.items()}
2019
2049
  return item
2020
2050
 
2021
- async def readlines(self, sha256):
2051
+ @stormfunc(readonly=True)
2052
+ async def readlines(self, sha256, errors='ignore'):
2022
2053
  if not self.runt.allowed(('axon', 'get')):
2023
2054
  self.runt.confirm(('storm', 'lib', 'axon', 'get'))
2024
2055
  await self.runt.snap.core.getAxon()
2025
2056
 
2026
2057
  sha256 = await tostr(sha256)
2027
- async for line in self.runt.snap.core.axon.readlines(sha256):
2058
+ async for line in self.runt.snap.core.axon.readlines(sha256, errors=errors):
2028
2059
  yield line
2029
2060
 
2030
- async def jsonlines(self, sha256):
2061
+ @stormfunc(readonly=True)
2062
+ async def jsonlines(self, sha256, errors='ignore'):
2031
2063
  if not self.runt.allowed(('axon', 'get')):
2032
2064
  self.runt.confirm(('storm', 'lib', 'axon', 'get'))
2033
2065
  await self.runt.snap.core.getAxon()
@@ -2071,9 +2103,6 @@ class LibAxon(Lib):
2071
2103
  if not self.runt.allowed(('axon', 'wget')):
2072
2104
  self.runt.confirm(('storm', 'lib', 'axon', 'wget'))
2073
2105
 
2074
- if proxy is not None and not self.runt.isAdmin():
2075
- raise s_exc.AuthDeny(mesg=s_exc.proxy_admin_mesg, user=self.runt.user.iden, username=self.runt.user.name)
2076
-
2077
2106
  url = await tostr(url)
2078
2107
  method = await tostr(method)
2079
2108
 
@@ -2085,6 +2114,9 @@ class LibAxon(Lib):
2085
2114
  timeout = await toprim(timeout)
2086
2115
  proxy = await toprim(proxy)
2087
2116
 
2117
+ if proxy is not None:
2118
+ self.runt.confirm(('storm', 'lib', 'inet', 'http', 'proxy'))
2119
+
2088
2120
  params = self.strify(params)
2089
2121
  headers = self.strify(headers)
2090
2122
 
@@ -2106,9 +2138,6 @@ class LibAxon(Lib):
2106
2138
  if not self.runt.allowed(('axon', 'wput')):
2107
2139
  self.runt.confirm(('storm', 'lib', 'axon', 'wput'))
2108
2140
 
2109
- if proxy is not None and not self.runt.isAdmin():
2110
- raise s_exc.AuthDeny(mesg=s_exc.proxy_admin_mesg, user=self.runt.user.iden, username=self.runt.user.name)
2111
-
2112
2141
  url = await tostr(url)
2113
2142
  sha256 = await tostr(sha256)
2114
2143
  method = await tostr(method)
@@ -2122,6 +2151,9 @@ class LibAxon(Lib):
2122
2151
  params = self.strify(params)
2123
2152
  headers = self.strify(headers)
2124
2153
 
2154
+ if proxy is not None:
2155
+ self.runt.confirm(('storm', 'lib', 'inet', 'http', 'proxy'))
2156
+
2125
2157
  axon = self.runt.snap.core.axon
2126
2158
  sha256byts = s_common.uhex(sha256)
2127
2159
 
@@ -2190,6 +2222,7 @@ class LibAxon(Lib):
2190
2222
 
2191
2223
  return urlfile
2192
2224
 
2225
+ @stormfunc(readonly=True)
2193
2226
  async def list(self, offs=0, wait=False, timeout=None):
2194
2227
  offs = await toint(offs)
2195
2228
  wait = await tobool(wait)
@@ -2204,7 +2237,8 @@ class LibAxon(Lib):
2204
2237
  async for item in axon.hashes(offs, wait=wait, timeout=timeout):
2205
2238
  yield (item[0], s_common.ehex(item[1][0]), item[1][1])
2206
2239
 
2207
- async def csvrows(self, sha256, dialect='excel', **fmtparams):
2240
+ @stormfunc(readonly=True)
2241
+ async def csvrows(self, sha256, dialect='excel', errors='ignore', **fmtparams):
2208
2242
 
2209
2243
  if not self.runt.allowed(('axon', 'get')):
2210
2244
  self.runt.confirm(('storm', 'lib', 'axon', 'get'))
@@ -2214,10 +2248,12 @@ class LibAxon(Lib):
2214
2248
  sha256 = await tostr(sha256)
2215
2249
  dialect = await tostr(dialect)
2216
2250
  fmtparams = await toprim(fmtparams)
2217
- async for item in self.runt.snap.core.axon.csvrows(s_common.uhex(sha256), dialect, **fmtparams):
2251
+ async for item in self.runt.snap.core.axon.csvrows(s_common.uhex(sha256), dialect,
2252
+ errors=errors, **fmtparams):
2218
2253
  yield item
2219
2254
  await asyncio.sleep(0)
2220
2255
 
2256
+ @stormfunc(readonly=True)
2221
2257
  async def metrics(self):
2222
2258
  if not self.runt.allowed(('axon', 'has')):
2223
2259
  self.runt.confirm(('storm', 'lib', 'axon', 'has'))
@@ -2325,6 +2361,7 @@ class LibBytes(Lib):
2325
2361
  size, sha256 = await upload.save()
2326
2362
  return size, s_common.ehex(sha256)
2327
2363
 
2364
+ @stormfunc(readonly=True)
2328
2365
  async def _libBytesHas(self, sha256):
2329
2366
  sha256 = await tostr(sha256, noneok=True)
2330
2367
  if sha256 is None:
@@ -2335,6 +2372,7 @@ class LibBytes(Lib):
2335
2372
  ret = await self.dyncall('axon', todo)
2336
2373
  return ret
2337
2374
 
2375
+ @stormfunc(readonly=True)
2338
2376
  async def _libBytesSize(self, sha256):
2339
2377
  sha256 = await tostr(sha256)
2340
2378
  await self.runt.snap.core.getAxon()
@@ -2353,6 +2391,7 @@ class LibBytes(Lib):
2353
2391
 
2354
2392
  return (size, s_common.ehex(sha2))
2355
2393
 
2394
+ @stormfunc(readonly=True)
2356
2395
  async def _libBytesHashset(self, sha256):
2357
2396
  sha256 = await tostr(sha256)
2358
2397
  await self.runt.snap.core.getAxon()
@@ -2382,6 +2421,7 @@ class LibLift(Lib):
2382
2421
  'byNodeData': self._byNodeData,
2383
2422
  }
2384
2423
 
2424
+ @stormfunc(readonly=True)
2385
2425
  async def _byNodeData(self, name):
2386
2426
  async for node in self.runt.snap.nodesByDataName(name):
2387
2427
  yield node
@@ -2598,6 +2638,7 @@ class LibTime(Lib):
2598
2638
  'monthofyear': self.monthofyear,
2599
2639
  }
2600
2640
 
2641
+ @stormfunc(readonly=True)
2601
2642
  async def toUTC(self, tick, timezone):
2602
2643
 
2603
2644
  tick = await toprim(tick)
@@ -2611,69 +2652,81 @@ class LibTime(Lib):
2611
2652
  except s_exc.BadArg as e:
2612
2653
  return (False, s_common.excinfo(e))
2613
2654
 
2655
+ @stormfunc(readonly=True)
2614
2656
  def _now(self):
2615
2657
  return s_common.now()
2616
2658
 
2659
+ @stormfunc(readonly=True)
2617
2660
  async def day(self, tick):
2618
2661
  tick = await toprim(tick)
2619
2662
  timetype = self.runt.snap.core.model.type('time')
2620
2663
  norm, info = timetype.norm(tick)
2621
2664
  return s_time.day(norm)
2622
2665
 
2666
+ @stormfunc(readonly=True)
2623
2667
  async def hour(self, tick):
2624
2668
  tick = await toprim(tick)
2625
2669
  timetype = self.runt.snap.core.model.type('time')
2626
2670
  norm, info = timetype.norm(tick)
2627
2671
  return s_time.hour(norm)
2628
2672
 
2673
+ @stormfunc(readonly=True)
2629
2674
  async def year(self, tick):
2630
2675
  tick = await toprim(tick)
2631
2676
  timetype = self.runt.snap.core.model.type('time')
2632
2677
  norm, info = timetype.norm(tick)
2633
2678
  return s_time.year(norm)
2634
2679
 
2680
+ @stormfunc(readonly=True)
2635
2681
  async def month(self, tick):
2636
2682
  tick = await toprim(tick)
2637
2683
  timetype = self.runt.snap.core.model.type('time')
2638
2684
  norm, info = timetype.norm(tick)
2639
2685
  return s_time.month(norm)
2640
2686
 
2687
+ @stormfunc(readonly=True)
2641
2688
  async def minute(self, tick):
2642
2689
  tick = await toprim(tick)
2643
2690
  timetype = self.runt.snap.core.model.type('time')
2644
2691
  norm, info = timetype.norm(tick)
2645
2692
  return s_time.minute(norm)
2646
2693
 
2694
+ @stormfunc(readonly=True)
2647
2695
  async def second(self, tick):
2648
2696
  tick = await toprim(tick)
2649
2697
  timetype = self.runt.snap.core.model.type('time')
2650
2698
  norm, info = timetype.norm(tick)
2651
2699
  return s_time.second(norm)
2652
2700
 
2701
+ @stormfunc(readonly=True)
2653
2702
  async def dayofweek(self, tick):
2654
2703
  tick = await toprim(tick)
2655
2704
  timetype = self.runt.snap.core.model.type('time')
2656
2705
  norm, info = timetype.norm(tick)
2657
2706
  return s_time.dayofweek(norm)
2658
2707
 
2708
+ @stormfunc(readonly=True)
2659
2709
  async def dayofyear(self, tick):
2660
2710
  tick = await toprim(tick)
2661
2711
  timetype = self.runt.snap.core.model.type('time')
2662
2712
  norm, info = timetype.norm(tick)
2663
2713
  return s_time.dayofyear(norm)
2664
2714
 
2715
+ @stormfunc(readonly=True)
2665
2716
  async def dayofmonth(self, tick):
2666
2717
  tick = await toprim(tick)
2667
2718
  timetype = self.runt.snap.core.model.type('time')
2668
2719
  norm, info = timetype.norm(tick)
2669
2720
  return s_time.dayofmonth(norm)
2670
2721
 
2722
+ @stormfunc(readonly=True)
2671
2723
  async def monthofyear(self, tick):
2672
2724
  tick = await toprim(tick)
2673
2725
  timetype = self.runt.snap.core.model.type('time')
2674
2726
  norm, info = timetype.norm(tick)
2675
2727
  return s_time.month(norm) - 1
2676
2728
 
2729
+ @stormfunc(readonly=True)
2677
2730
  async def _format(self, valu, format):
2678
2731
  timetype = self.runt.snap.core.model.type('time')
2679
2732
  # Give a times string a shot at being normed prior to formatting.
@@ -2697,6 +2750,7 @@ class LibTime(Lib):
2697
2750
  format=format) from None
2698
2751
  return ret
2699
2752
 
2753
+ @stormfunc(readonly=True)
2700
2754
  async def _parse(self, valu, format, errok=False):
2701
2755
  valu = await tostr(valu)
2702
2756
  errok = await tobool(errok)
@@ -2713,6 +2767,7 @@ class LibTime(Lib):
2713
2767
  dt = dt.astimezone(datetime.timezone.utc).replace(tzinfo=None)
2714
2768
  return int((dt - s_time.EPOCH).total_seconds() * 1000)
2715
2769
 
2770
+ @stormfunc(readonly=True)
2716
2771
  async def _sleep(self, valu):
2717
2772
  await self.runt.snap.waitfini(timeout=float(valu))
2718
2773
  await self.runt.snap.clearCache()
@@ -2858,6 +2913,7 @@ class LibRegx(Lib):
2858
2913
  regx = self.compiled[lkey] = regex.compile(pattern, flags=flags)
2859
2914
  return regx
2860
2915
 
2916
+ @stormfunc(readonly=True)
2861
2917
  async def replace(self, pattern, replace, text, flags=0):
2862
2918
  text = await tostr(text)
2863
2919
  flags = await toint(flags)
@@ -2866,6 +2922,7 @@ class LibRegx(Lib):
2866
2922
  regx = await self._getRegx(pattern, flags)
2867
2923
  return regx.sub(replace, text)
2868
2924
 
2925
+ @stormfunc(readonly=True)
2869
2926
  async def matches(self, pattern, text, flags=0):
2870
2927
  text = await tostr(text)
2871
2928
  flags = await toint(flags)
@@ -2873,6 +2930,7 @@ class LibRegx(Lib):
2873
2930
  regx = await self._getRegx(pattern, flags)
2874
2931
  return regx.match(text) is not None
2875
2932
 
2933
+ @stormfunc(readonly=True)
2876
2934
  async def search(self, pattern, text, flags=0):
2877
2935
  text = await tostr(text)
2878
2936
  flags = await toint(flags)
@@ -2885,6 +2943,7 @@ class LibRegx(Lib):
2885
2943
 
2886
2944
  return m.groups()
2887
2945
 
2946
+ @stormfunc(readonly=True)
2888
2947
  async def findall(self, pattern, text, flags=0):
2889
2948
  text = await tostr(text)
2890
2949
  flags = await toint(flags)
@@ -2914,6 +2973,7 @@ class LibCsv(Lib):
2914
2973
  'emit': self._libCsvEmit,
2915
2974
  }
2916
2975
 
2976
+ @stormfunc(readonly=True)
2917
2977
  async def _libCsvEmit(self, *args, table=None):
2918
2978
  row = [await toprim(a) for a in args]
2919
2979
  await self.runt.snap.fire('csv:row', row=row, table=table)
@@ -3040,6 +3100,7 @@ class LibFeed(Lib):
3040
3100
  return
3041
3101
  await self.runt.snap.addFeedData(name, data)
3042
3102
 
3103
+ @stormfunc(readonly=True)
3043
3104
  async def _libList(self):
3044
3105
  todo = ('getFeedFuncs', (), {})
3045
3106
  return await self.runt.dyncall('cortex', todo)
@@ -3094,6 +3155,7 @@ class LibPipe(Lib):
3094
3155
  'gen': self._methPipeGen,
3095
3156
  }
3096
3157
 
3158
+ @stormfunc(readonly=True)
3097
3159
  async def _methPipeGen(self, filler, size=10000):
3098
3160
  size = await toint(size)
3099
3161
  text = await tostr(filler)
@@ -3196,10 +3258,12 @@ class Pipe(StormType):
3196
3258
  'size': self._methPipeSize,
3197
3259
  }
3198
3260
 
3261
+ @stormfunc(readonly=True)
3199
3262
  async def _methPipePuts(self, items):
3200
3263
  items = await toprim(items)
3201
3264
  return await self.queue.puts(items)
3202
3265
 
3266
+ @stormfunc(readonly=True)
3203
3267
  async def _methPipePut(self, item):
3204
3268
  item = await toprim(item)
3205
3269
  return await self.queue.put(item)
@@ -3211,9 +3275,11 @@ class Pipe(StormType):
3211
3275
  '''
3212
3276
  await self.queue.close()
3213
3277
 
3278
+ @stormfunc(readonly=True)
3214
3279
  async def _methPipeSize(self):
3215
3280
  return await self.queue.size()
3216
3281
 
3282
+ @stormfunc(readonly=True)
3217
3283
  async def _methPipeSlice(self, size=1000):
3218
3284
 
3219
3285
  size = await toint(size)
@@ -3227,6 +3293,7 @@ class Pipe(StormType):
3227
3293
 
3228
3294
  return List(items)
3229
3295
 
3296
+ @stormfunc(readonly=True)
3230
3297
  async def _methPipeSlices(self, size=1000):
3231
3298
  size = await toint(size)
3232
3299
  if size < 1 or size > 10000:
@@ -3295,6 +3362,7 @@ class LibQueue(Lib):
3295
3362
 
3296
3363
  return Queue(self.runt, name, info)
3297
3364
 
3365
+ @stormfunc(readonly=True)
3298
3366
  async def _methQueueGet(self, name):
3299
3367
  todo = s_common.todo('getCoreQueue', name)
3300
3368
  gatekeys = ((self.runt.user.iden, ('queue', 'get'), f'queue:{name}'),)
@@ -3313,6 +3381,7 @@ class LibQueue(Lib):
3313
3381
  gatekeys = ((self.runt.user.iden, ('queue', 'del',), f'queue:{name}'), )
3314
3382
  await self.dyncall('cortex', todo, gatekeys=gatekeys)
3315
3383
 
3384
+ @stormfunc(readonly=True)
3316
3385
  async def _methQueueList(self):
3317
3386
  retn = []
3318
3387
 
@@ -3432,6 +3501,7 @@ class Queue(StormType):
3432
3501
  await self.runt.reqGateKeys(gatekeys)
3433
3502
  await self.runt.snap.core.coreQueueCull(self.name, offs)
3434
3503
 
3504
+ @stormfunc(readonly=True)
3435
3505
  async def _methQueueSize(self):
3436
3506
  gatekeys = self._getGateKeys('get')
3437
3507
  await self.runt.reqGateKeys(gatekeys)
@@ -3685,6 +3755,7 @@ class LibBase64(Lib):
3685
3755
  'decode': self._decode
3686
3756
  }
3687
3757
 
3758
+ @stormfunc(readonly=True)
3688
3759
  async def _encode(self, valu, urlsafe=True):
3689
3760
  try:
3690
3761
  if urlsafe:
@@ -3694,6 +3765,7 @@ class LibBase64(Lib):
3694
3765
  mesg = f'Error during base64 encoding - {str(e)}: {repr(valu)[:256]}'
3695
3766
  raise s_exc.StormRuntimeError(mesg=mesg, urlsafe=urlsafe) from None
3696
3767
 
3768
+ @stormfunc(readonly=True)
3697
3769
  async def _decode(self, valu, urlsafe=True):
3698
3770
  try:
3699
3771
  if urlsafe:
@@ -4196,7 +4268,7 @@ class Bytes(Prim):
4196
4268
 
4197
4269
  $subbyts = $byts.slice(3)
4198
4270
  ''',
4199
- 'type': {'type': 'function', '_funcname': 'slice',
4271
+ 'type': {'type': 'function', '_funcname': '_methSlice',
4200
4272
  'args': (
4201
4273
  {'name': 'start', 'type': 'int', 'desc': 'The starting byte index.'},
4202
4274
  {'name': 'end', 'type': 'int', 'default': None,
@@ -4212,7 +4284,7 @@ class Bytes(Prim):
4212
4284
 
4213
4285
  ($x, $y, $z) = $byts.unpack("<HHH")
4214
4286
  ''',
4215
- 'type': {'type': 'function', '_funcname': 'unpack',
4287
+ 'type': {'type': 'function', '_funcname': '_methUnpack',
4216
4288
  'args': (
4217
4289
  {'name': 'fmt', 'type': 'str', 'desc': 'A python struck.pack format string.'},
4218
4290
  {'name': 'offset', 'type': 'int', 'desc': 'An offset to begin unpacking from.', 'default': 0},
@@ -4234,8 +4306,8 @@ class Bytes(Prim):
4234
4306
  'bzip': self._methBzip,
4235
4307
  'gzip': self._methGzip,
4236
4308
  'json': self._methJsonLoad,
4237
- 'slice': self.slice,
4238
- 'unpack': self.unpack,
4309
+ 'slice': self._methSlice,
4310
+ 'unpack': self._methUnpack,
4239
4311
  }
4240
4312
 
4241
4313
  def __len__(self):
@@ -4256,7 +4328,8 @@ class Bytes(Prim):
4256
4328
  item = await s_coro.ornot(self.value)
4257
4329
  return s_msgpack.deepcopy(item, use_list=True)
4258
4330
 
4259
- async def slice(self, start, end=None):
4331
+ @stormfunc(readonly=True)
4332
+ async def _methSlice(self, start, end=None):
4260
4333
  start = await toint(start)
4261
4334
  if end is None:
4262
4335
  return self.valu[start:]
@@ -4264,7 +4337,8 @@ class Bytes(Prim):
4264
4337
  end = await toint(end)
4265
4338
  return self.valu[start:end]
4266
4339
 
4267
- async def unpack(self, fmt, offset=0):
4340
+ @stormfunc(readonly=True)
4341
+ async def _methUnpack(self, fmt, offset=0):
4268
4342
  fmt = await tostr(fmt)
4269
4343
  offset = await toint(offset)
4270
4344
  try:
@@ -4272,6 +4346,7 @@ class Bytes(Prim):
4272
4346
  except struct.error as e:
4273
4347
  raise s_exc.BadArg(mesg=f'unpack() error: {e}')
4274
4348
 
4349
+ @stormfunc(readonly=True)
4275
4350
  async def _methDecode(self, encoding='utf8', errors='surrogatepass'):
4276
4351
  encoding = await tostr(encoding)
4277
4352
  errors = await tostr(errors)
@@ -4283,15 +4358,18 @@ class Bytes(Prim):
4283
4358
  async def _methBunzip(self):
4284
4359
  return bz2.decompress(self.valu)
4285
4360
 
4361
+ @stormfunc(readonly=True)
4286
4362
  async def _methBzip(self):
4287
4363
  return bz2.compress(self.valu)
4288
4364
 
4289
4365
  async def _methGunzip(self):
4290
4366
  return gzip.decompress(self.valu)
4291
4367
 
4368
+ @stormfunc(readonly=True)
4292
4369
  async def _methGzip(self):
4293
4370
  return gzip.compress(self.valu)
4294
4371
 
4372
+ @stormfunc(readonly=True)
4295
4373
  async def _methJsonLoad(self, encoding=None, errors='surrogatepass'):
4296
4374
  try:
4297
4375
  valu = self.valu
@@ -4477,9 +4555,11 @@ class Set(Prim):
4477
4555
  async def _methSetSize(self):
4478
4556
  return len(self)
4479
4557
 
4558
+ @stormfunc(readonly=True)
4480
4559
  async def _methSetHas(self, item):
4481
4560
  return item in self.valu
4482
4561
 
4562
+ @stormfunc(readonly=True)
4483
4563
  async def _methSetAdd(self, *items):
4484
4564
  for i in items:
4485
4565
  if ismutable(i):
@@ -4487,6 +4567,7 @@ class Set(Prim):
4487
4567
  raise s_exc.StormRuntimeError(mesg=mesg)
4488
4568
  self.valu.add(i)
4489
4569
 
4570
+ @stormfunc(readonly=True)
4490
4571
  async def _methSetAdds(self, *items):
4491
4572
  for item in items:
4492
4573
  async for i in toiter(item):
@@ -4495,13 +4576,16 @@ class Set(Prim):
4495
4576
  raise s_exc.StormRuntimeError(mesg=mesg)
4496
4577
  self.valu.add(i)
4497
4578
 
4579
+ @stormfunc(readonly=True)
4498
4580
  async def _methSetRem(self, *items):
4499
4581
  [self.valu.discard(i) for i in items]
4500
4582
 
4583
+ @stormfunc(readonly=True)
4501
4584
  async def _methSetRems(self, *items):
4502
4585
  for item in items:
4503
4586
  [self.valu.discard(i) async for i in toiter(item)]
4504
4587
 
4588
+ @stormfunc(readonly=True)
4505
4589
  async def _methSetList(self):
4506
4590
  return list(self.valu)
4507
4591
 
@@ -4516,7 +4600,7 @@ class List(Prim):
4516
4600
  Implements the Storm API for a List instance.
4517
4601
  '''
4518
4602
  _storm_locals = (
4519
- {'name': 'has', 'desc': 'Check it a value is in the list.',
4603
+ {'name': 'has', 'desc': 'Check if a value is in the list.',
4520
4604
  'type': {'type': 'function', '_funcname': '_methListHas',
4521
4605
  'args': (
4522
4606
  {'name': 'valu', 'type': 'any', 'desc': 'The value to check.', },
@@ -4566,7 +4650,7 @@ class List(Prim):
4566
4650
 
4567
4651
  $y=$x.slice(3) // (b, a, r)
4568
4652
  ''',
4569
- 'type': {'type': 'function', '_funcname': 'slice',
4653
+ 'type': {'type': 'function', '_funcname': '_methListSlice',
4570
4654
  'args': (
4571
4655
  {'name': 'start', 'type': 'int', 'desc': 'The starting index.'},
4572
4656
  {'name': 'end', 'type': 'int', 'default': None,
@@ -4590,11 +4674,14 @@ class List(Prim):
4590
4674
 
4591
4675
  // $list is now (f, o, o, b, a, r)
4592
4676
  ''',
4593
- 'type': {'type': 'function', '_funcname': 'extend',
4677
+ 'type': {'type': 'function', '_funcname': '_methListExtend',
4594
4678
  'args': (
4595
4679
  {'name': 'valu', 'type': 'list', 'desc': 'A list or other iterable.'},
4596
4680
  ),
4597
4681
  'returns': {'type': 'null'}}},
4682
+ {'name': 'unique', 'desc': 'Get a copy of the list containing unique items.',
4683
+ 'type': {'type': 'function', '_funcname': '_methListUnique',
4684
+ 'returns': {'type': 'list'}}},
4598
4685
  )
4599
4686
  _storm_typename = 'list'
4600
4687
  _ismutable = True
@@ -4613,9 +4700,9 @@ class List(Prim):
4613
4700
  'length': self._methListLength,
4614
4701
  'append': self._methListAppend,
4615
4702
  'reverse': self._methListReverse,
4616
-
4617
- 'slice': self.slice,
4618
- 'extend': self.extend,
4703
+ 'slice': self._methListSlice,
4704
+ 'extend': self._methListExtend,
4705
+ 'unique': self._methListUnique,
4619
4706
  }
4620
4707
 
4621
4708
  @stormfunc(readonly=True)
@@ -4642,6 +4729,7 @@ class List(Prim):
4642
4729
  def __len__(self):
4643
4730
  return len(self.valu)
4644
4731
 
4732
+ @stormfunc(readonly=True)
4645
4733
  async def _methListHas(self, valu):
4646
4734
  if valu in self.valu:
4647
4735
  return True
@@ -4652,6 +4740,7 @@ class List(Prim):
4652
4740
 
4653
4741
  return prim in self.valu
4654
4742
 
4743
+ @stormfunc(readonly=True)
4655
4744
  async def _methListPop(self):
4656
4745
  try:
4657
4746
  return self.valu.pop()
@@ -4659,11 +4748,13 @@ class List(Prim):
4659
4748
  mesg = 'The list is empty. Nothing to pop.'
4660
4749
  raise s_exc.StormRuntimeError(mesg=mesg)
4661
4750
 
4751
+ @stormfunc(readonly=True)
4662
4752
  async def _methListAppend(self, valu):
4663
4753
  '''
4664
4754
  '''
4665
4755
  self.valu.append(valu)
4666
4756
 
4757
+ @stormfunc(readonly=True)
4667
4758
  async def _methListIndex(self, valu):
4668
4759
  indx = await toint(valu)
4669
4760
  try:
@@ -4672,9 +4763,11 @@ class List(Prim):
4672
4763
  raise s_exc.StormRuntimeError(mesg=str(e), valurepr=await self.stormrepr(),
4673
4764
  len=len(self.valu), indx=indx) from None
4674
4765
 
4766
+ @stormfunc(readonly=True)
4675
4767
  async def _methListReverse(self):
4676
4768
  self.valu.reverse()
4677
4769
 
4770
+ @stormfunc(readonly=True)
4678
4771
  async def _methListLength(self):
4679
4772
  s_common.deprecated('StormType List.length()')
4680
4773
  runt = s_scope.get('runt')
@@ -4682,6 +4775,7 @@ class List(Prim):
4682
4775
  await runt.snap.warnonce('StormType List.length() is deprecated. Use the size() method.')
4683
4776
  return len(self)
4684
4777
 
4778
+ @stormfunc(readonly=True)
4685
4779
  async def _methListSort(self, reverse=False):
4686
4780
  reverse = await tobool(reverse, noneok=True)
4687
4781
  try:
@@ -4690,10 +4784,11 @@ class List(Prim):
4690
4784
  raise s_exc.StormRuntimeError(mesg=f'Error sorting list: {str(e)}',
4691
4785
  valurepr=await self.stormrepr()) from None
4692
4786
 
4787
+ @stormfunc(readonly=True)
4693
4788
  async def _methListSize(self):
4694
4789
  return len(self)
4695
4790
 
4696
- async def slice(self, start, end=None):
4791
+ async def _methListSlice(self, start, end=None):
4697
4792
  start = await toint(start)
4698
4793
 
4699
4794
  if end is None:
@@ -4702,7 +4797,8 @@ class List(Prim):
4702
4797
  end = await toint(end)
4703
4798
  return self.valu[start:end]
4704
4799
 
4705
- async def extend(self, valu):
4800
+ @stormfunc(readonly=True)
4801
+ async def _methListExtend(self, valu):
4706
4802
  async for item in toiter(valu):
4707
4803
  self.valu.append(item)
4708
4804
 
@@ -4713,6 +4809,22 @@ class List(Prim):
4713
4809
  for item in self.valu:
4714
4810
  yield item
4715
4811
 
4812
+ @stormfunc(readonly=True)
4813
+ async def _methListUnique(self):
4814
+ ret = []
4815
+ checkret = []
4816
+
4817
+ for val in self.valu:
4818
+ try:
4819
+ _cval = await toprim(val)
4820
+ except s_exc.NoSuchType:
4821
+ _cval = val
4822
+ if _cval in checkret:
4823
+ continue
4824
+ checkret.append(_cval)
4825
+ ret.append(val)
4826
+ return ret
4827
+
4716
4828
  async def stormrepr(self):
4717
4829
  reprs = [await torepr(k) for k in self.valu]
4718
4830
  rval = ', '.join(reprs)
@@ -4801,10 +4913,12 @@ class Number(Prim):
4801
4913
  'scaleb': self._methScaleb,
4802
4914
  }
4803
4915
 
4916
+ @stormfunc(readonly=True)
4804
4917
  async def _methScaleb(self, other):
4805
4918
  newv = s_common.hugescaleb(self.value(), await toint(other))
4806
4919
  return Number(newv)
4807
4920
 
4921
+ @stormfunc(readonly=True)
4808
4922
  async def _methToInt(self, rounding=None):
4809
4923
  if rounding is None:
4810
4924
  return int(self.valu)
@@ -4815,9 +4929,11 @@ class Number(Prim):
4815
4929
  raise s_exc.StormRuntimeError(mesg=f'Error rounding number: {str(e)}',
4816
4930
  valurepr=await self.stormrepr()) from None
4817
4931
 
4932
+ @stormfunc(readonly=True)
4818
4933
  async def _methToStr(self):
4819
4934
  return str(self.valu)
4820
4935
 
4936
+ @stormfunc(readonly=True)
4821
4937
  async def _methToFloat(self):
4822
4938
  return float(self.valu)
4823
4939
 
@@ -4991,9 +5107,11 @@ class LibUser(Lib):
4991
5107
  'profile': StormHiveDict(self.runt, self.runt.user.profile),
4992
5108
  })
4993
5109
 
5110
+ @stormfunc(readonly=True)
4994
5111
  async def _libUserName(self):
4995
5112
  return self.runt.user.name
4996
5113
 
5114
+ @stormfunc(readonly=True)
4997
5115
  async def _libUserAllowed(self, permname, gateiden=None, default=False):
4998
5116
  permname = await toprim(permname)
4999
5117
  gateiden = await tostr(gateiden, noneok=True)
@@ -5073,6 +5191,7 @@ class LibGlobals(Lib):
5073
5191
  mesg = 'The name of a persistent variable must be a string.'
5074
5192
  raise s_exc.StormRuntimeError(mesg=mesg, name=name)
5075
5193
 
5194
+ @stormfunc(readonly=True)
5076
5195
  async def _methGet(self, name, default=None):
5077
5196
  self._reqStr(name)
5078
5197
 
@@ -5096,6 +5215,7 @@ class LibGlobals(Lib):
5096
5215
  todo = s_common.todo('setStormVar', name, valu)
5097
5216
  return await self.runt.dyncall('cortex', todo, gatekeys=gatekeys)
5098
5217
 
5218
+ @stormfunc(readonly=True)
5099
5219
  async def _methList(self):
5100
5220
  ret = []
5101
5221
 
@@ -5157,6 +5277,7 @@ class StormHiveDict(Prim):
5157
5277
  'list': self._list,
5158
5278
  }
5159
5279
 
5280
+ @stormfunc(readonly=True)
5160
5281
  async def _get(self, name, default=None):
5161
5282
  return self.info.get(name, default)
5162
5283
 
@@ -5172,6 +5293,7 @@ class StormHiveDict(Prim):
5172
5293
 
5173
5294
  return await self.info.set(name, valu)
5174
5295
 
5296
+ @stormfunc(readonly=True)
5175
5297
  def _list(self):
5176
5298
  return list(self.info.items())
5177
5299
 
@@ -5231,18 +5353,23 @@ class LibVars(Lib):
5231
5353
  'type': self._libVarsType,
5232
5354
  }
5233
5355
 
5356
+ @stormfunc(readonly=True)
5234
5357
  async def _libVarsGet(self, name, defv=None):
5235
5358
  return self.runt.getVar(name, defv=defv)
5236
5359
 
5360
+ @stormfunc(readonly=True)
5237
5361
  async def _libVarsSet(self, name, valu):
5238
5362
  await self.runt.setVar(name, valu)
5239
5363
 
5364
+ @stormfunc(readonly=True)
5240
5365
  async def _libVarsDel(self, name):
5241
5366
  await self.runt.popVar(name)
5242
5367
 
5368
+ @stormfunc(readonly=True)
5243
5369
  async def _libVarsList(self):
5244
5370
  return list(self.runt.vars.items())
5245
5371
 
5372
+ @stormfunc(readonly=True)
5246
5373
  async def _libVarsType(self, valu):
5247
5374
  return await totype(valu)
5248
5375
 
@@ -5309,6 +5436,7 @@ class Query(Prim):
5309
5436
  async for node, path in self._getRuntGenr():
5310
5437
  yield Node(node)
5311
5438
 
5439
+ @stormfunc(readonly=True)
5312
5440
  async def _methQueryExec(self):
5313
5441
  logger.info(f'Executing storm query via exec() {{{self.text}}} as [{self.runt.user.name}]')
5314
5442
  try:
@@ -5319,6 +5447,7 @@ class Query(Prim):
5319
5447
  except asyncio.CancelledError: # pragma: no cover
5320
5448
  raise
5321
5449
 
5450
+ @stormfunc(readonly=True)
5322
5451
  async def _methQuerySize(self, limit=1000):
5323
5452
  limit = await toint(limit)
5324
5453
 
@@ -5667,11 +5796,11 @@ class Node(Prim):
5667
5796
  'type': {'type': 'function', '_funcname': '_methNodeValue',
5668
5797
  'returns': {'type': 'prim', 'desc': 'The primary property.', }}},
5669
5798
  {'name': 'getByLayer', 'desc': 'Return a dict you can use to lookup which props/tags came from which layers.',
5670
- 'type': {'type': 'function', '_funcname': 'getByLayer',
5799
+ 'type': {'type': 'function', '_funcname': '_methGetByLayer',
5671
5800
  'returns': {'type': 'dict', 'desc': 'property / tag lookup dictionary.', }}},
5672
5801
  {'name': 'getStorNodes',
5673
5802
  'desc': 'Return a list of "storage nodes" which were fused from the layers to make this node.',
5674
- 'type': {'type': 'function', '_funcname': 'getStorNodes',
5803
+ 'type': {'type': 'function', '_funcname': '_methGetStorNodes',
5675
5804
  'returns': {'type': 'list', 'desc': 'List of storage node objects.', }}},
5676
5805
  )
5677
5806
  _storm_typename = 'node'
@@ -5703,14 +5832,16 @@ class Node(Prim):
5703
5832
  'globtags': self._methNodeGlobTags,
5704
5833
  'difftags': self._methNodeDiffTags,
5705
5834
  'isform': self._methNodeIsForm,
5706
- 'getByLayer': self.getByLayer,
5707
- 'getStorNodes': self.getStorNodes,
5835
+ 'getByLayer': self._methGetByLayer,
5836
+ 'getStorNodes': self._methGetStorNodes,
5708
5837
  }
5709
5838
 
5710
- async def getStorNodes(self):
5839
+ @stormfunc(readonly=True)
5840
+ async def _methGetStorNodes(self):
5711
5841
  return await self.valu.getStorNodes()
5712
5842
 
5713
- def getByLayer(self):
5843
+ @stormfunc(readonly=True)
5844
+ def _methGetByLayer(self):
5714
5845
  return self.valu.getByLayer()
5715
5846
 
5716
5847
  def _ctorNodeData(self, path=None):
@@ -5955,9 +6086,11 @@ class Path(Prim):
5955
6086
  'listvars': self._methPathListVars,
5956
6087
  }
5957
6088
 
6089
+ @stormfunc(readonly=True)
5958
6090
  async def _methPathIdens(self):
5959
6091
  return [n.iden() for n in self.valu.nodes]
5960
6092
 
6093
+ @stormfunc(readonly=True)
5961
6094
  async def _methPathListVars(self):
5962
6095
  return list(self.path.vars.items())
5963
6096
 
@@ -5994,117 +6127,15 @@ class Text(Prim):
5994
6127
  def __len__(self):
5995
6128
  return len(self.valu)
5996
6129
 
6130
+ @stormfunc(readonly=True)
5997
6131
  async def _methTextAdd(self, text, **kwargs):
5998
6132
  text = await kwarg_format(text, **kwargs)
5999
6133
  self.valu += text
6000
6134
 
6135
+ @stormfunc(readonly=True)
6001
6136
  async def _methTextStr(self):
6002
6137
  return self.valu
6003
6138
 
6004
- @registry.registerLib
6005
- class LibStats(Lib):
6006
- '''
6007
- A Storm Library for statistics related functionality.
6008
- '''
6009
- _storm_locals = (
6010
- {'name': 'tally', 'desc': 'Get a Tally object.',
6011
- 'type': {'type': 'function', '_funcname': 'tally',
6012
- 'returns': {'type': 'stat:tally', 'desc': 'A new tally object.', }}},
6013
- )
6014
- _storm_lib_path = ('stats',)
6015
-
6016
- def getObjLocals(self):
6017
- return {
6018
- 'tally': self.tally,
6019
- }
6020
-
6021
- async def tally(self):
6022
- return StatTally(path=self.path)
6023
-
6024
- @registry.registerType
6025
- class StatTally(Prim):
6026
- '''
6027
- A tally object.
6028
-
6029
- An example of using it::
6030
-
6031
- $tally = $lib.stats.tally()
6032
-
6033
- $tally.inc(foo)
6034
-
6035
- for $name, $total in $tally {
6036
- $doStuff($name, $total)
6037
- }
6038
-
6039
- '''
6040
- _storm_typename = 'stat:tally'
6041
- _storm_locals = (
6042
- {'name': 'inc', 'desc': 'Increment a given counter.',
6043
- 'type': {'type': 'function', '_funcname': 'inc',
6044
- 'args': (
6045
- {'name': 'name', 'desc': 'The name of the counter to increment.', 'type': 'str', },
6046
- {'name': 'valu', 'desc': 'The value to increment the counter by.', 'type': 'int', 'default': 1, },
6047
- ),
6048
- 'returns': {'type': 'null', }}},
6049
- {'name': 'get', 'desc': 'Get the value of a given counter.',
6050
- 'type': {'type': 'function', '_funcname': 'get',
6051
- 'args': (
6052
- {'name': 'name', 'type': 'str', 'desc': 'The name of the counter to get.', },
6053
- ),
6054
- 'returns': {'type': 'int',
6055
- 'desc': 'The value of the counter, or 0 if the counter does not exist.', }}},
6056
- {'name': 'sorted', 'desc': 'Get a list of (counter, value) tuples in sorted order.',
6057
- 'type': {'type': 'function', '_funcname': 'sorted',
6058
- 'args': (
6059
- {'name': 'byname', 'desc': 'Sort by counter name instead of value.',
6060
- 'type': 'bool', 'default': False},
6061
- {'name': 'reverse', 'desc': 'Sort in descending order instead of ascending order.',
6062
- 'type': 'bool', 'default': False},
6063
- ),
6064
- 'returns': {'type': 'list',
6065
- 'desc': 'List of (counter, value) tuples in sorted order.'}}},
6066
- )
6067
- _ismutable = True
6068
-
6069
- def __init__(self, path=None):
6070
- Prim.__init__(self, {}, path=path)
6071
- self.counters = collections.defaultdict(int)
6072
- self.locls.update(self.getObjLocals())
6073
-
6074
- def getObjLocals(self):
6075
- return {
6076
- 'inc': self.inc,
6077
- 'get': self.get,
6078
- 'sorted': self.sorted,
6079
- }
6080
-
6081
- async def __aiter__(self):
6082
- for name, valu in self.counters.items():
6083
- yield name, valu
6084
-
6085
- def __len__(self):
6086
- return len(self.counters)
6087
-
6088
- async def inc(self, name, valu=1):
6089
- valu = await toint(valu)
6090
- self.counters[name] += valu
6091
-
6092
- async def get(self, name):
6093
- return self.counters.get(name, 0)
6094
-
6095
- def value(self):
6096
- return dict(self.counters)
6097
-
6098
- async def iter(self):
6099
- for item in tuple(self.counters.items()):
6100
- yield item
6101
-
6102
- async def sorted(self, byname=False, reverse=False):
6103
- if byname:
6104
- return list(sorted(self.counters.items(), reverse=reverse))
6105
- else:
6106
- return list(sorted(self.counters.items(), key=lambda x: x[1], reverse=reverse))
6107
-
6108
6139
  @registry.registerLib
6109
6140
  class LibLayer(Lib):
6110
6141
  '''
@@ -6177,6 +6208,7 @@ class LibLayer(Lib):
6177
6208
  todo = ('delLayer', (layriden,), {})
6178
6209
  return await self.runt.dyncall('cortex', todo, gatekeys=gatekeys)
6179
6210
 
6211
+ @stormfunc(readonly=True)
6180
6212
  async def _libLayerGet(self, iden=None):
6181
6213
 
6182
6214
  iden = await tostr(iden, noneok=True)
@@ -6190,6 +6222,7 @@ class LibLayer(Lib):
6190
6222
 
6191
6223
  return Layer(self.runt, ldef, path=self.path)
6192
6224
 
6225
+ @stormfunc(readonly=True)
6193
6226
  async def _libLayerList(self):
6194
6227
  todo = s_common.todo('getLayerDefs')
6195
6228
  defs = await self.runt.dyncall('cortex', todo)
@@ -6489,6 +6522,7 @@ class Layer(Prim):
6489
6522
  'getMirrorStatus': self.getMirrorStatus,
6490
6523
  }
6491
6524
 
6525
+ @stormfunc(readonly=True)
6492
6526
  async def liftByTag(self, tagname, formname=None):
6493
6527
  tagname = await tostr(tagname)
6494
6528
  formname = await tostr(formname, noneok=True)
@@ -6503,6 +6537,7 @@ class Layer(Prim):
6503
6537
  async for _, buid, sode in layr.liftByTag(tagname, form=formname):
6504
6538
  yield await self.runt.snap._joinStorNode(buid, {iden: sode})
6505
6539
 
6540
+ @stormfunc(readonly=True)
6506
6541
  async def liftByProp(self, propname, propvalu=None, propcmpr='='):
6507
6542
 
6508
6543
  propname = await tostr(propname)
@@ -6539,6 +6574,7 @@ class Layer(Prim):
6539
6574
  async for _, buid, sode in layr.liftByPropValu(liftform, liftprop, cmprvals):
6540
6575
  yield await self.runt.snap._joinStorNode(buid, {iden: sode})
6541
6576
 
6577
+ @stormfunc(readonly=True)
6542
6578
  async def getMirrorStatus(self):
6543
6579
  iden = self.valu.get('iden')
6544
6580
  layr = self.runt.snap.core.getLayer(iden)
@@ -6632,6 +6668,7 @@ class Layer(Prim):
6632
6668
  layr = self.runt.snap.core.getLayer(layriden)
6633
6669
  return await layr.getFormCounts()
6634
6670
 
6671
+ @stormfunc(readonly=True)
6635
6672
  async def _methGetTagCount(self, tagname, formname=None):
6636
6673
  tagname = await tostr(tagname)
6637
6674
  formname = await tostr(formname, noneok=True)
@@ -6640,6 +6677,7 @@ class Layer(Prim):
6640
6677
  layr = self.runt.snap.core.getLayer(layriden)
6641
6678
  return await layr.getTagCount(tagname, formname=formname)
6642
6679
 
6680
+ @stormfunc(readonly=True)
6643
6681
  async def _methGetPropCount(self, propname, maxsize=None):
6644
6682
  propname = await tostr(propname)
6645
6683
  maxsize = await toint(maxsize, noneok=True)
@@ -6661,6 +6699,7 @@ class Layer(Prim):
6661
6699
 
6662
6700
  return await layr.getPropCount(prop.form.name, prop.name, maxsize=maxsize)
6663
6701
 
6702
+ @stormfunc(readonly=True)
6664
6703
  async def _methLayerEdits(self, offs=0, wait=True, size=None):
6665
6704
  offs = await toint(offs)
6666
6705
  wait = await tobool(wait)
@@ -6677,6 +6716,7 @@ class Layer(Prim):
6677
6716
  if size is not None and size == count:
6678
6717
  break
6679
6718
 
6719
+ @stormfunc(readonly=True)
6680
6720
  async def getStorNode(self, nodeid):
6681
6721
  nodeid = await tostr(nodeid)
6682
6722
  layriden = self.valu.get('iden')
@@ -6684,6 +6724,7 @@ class Layer(Prim):
6684
6724
  layr = self.runt.snap.core.getLayer(layriden)
6685
6725
  return await layr.getStorNode(s_common.uhex(nodeid))
6686
6726
 
6727
+ @stormfunc(readonly=True)
6687
6728
  async def getStorNodes(self):
6688
6729
  layriden = self.valu.get('iden')
6689
6730
  await self.runt.reqUserCanReadLayer(layriden)
@@ -6691,6 +6732,7 @@ class Layer(Prim):
6691
6732
  async for item in layr.getStorNodes():
6692
6733
  yield item
6693
6734
 
6735
+ @stormfunc(readonly=True)
6694
6736
  async def getEdges(self):
6695
6737
  layriden = self.valu.get('iden')
6696
6738
  await self.runt.reqUserCanReadLayer(layriden)
@@ -6698,6 +6740,7 @@ class Layer(Prim):
6698
6740
  async for item in layr.getEdges():
6699
6741
  yield item
6700
6742
 
6743
+ @stormfunc(readonly=True)
6701
6744
  async def getEdgesByN1(self, nodeid):
6702
6745
  nodeid = await tostr(nodeid)
6703
6746
  layriden = self.valu.get('iden')
@@ -6706,6 +6749,7 @@ class Layer(Prim):
6706
6749
  async for item in layr.iterNodeEdgesN1(s_common.uhex(nodeid)):
6707
6750
  yield item
6708
6751
 
6752
+ @stormfunc(readonly=True)
6709
6753
  async def getEdgesByN2(self, nodeid):
6710
6754
  nodeid = await tostr(nodeid)
6711
6755
  layriden = self.valu.get('iden')
@@ -6714,6 +6758,7 @@ class Layer(Prim):
6714
6758
  async for item in layr.iterNodeEdgesN2(s_common.uhex(nodeid)):
6715
6759
  yield item
6716
6760
 
6761
+ @stormfunc(readonly=True)
6717
6762
  async def _methLayerGet(self, name, defv=None):
6718
6763
  return self.valu.get(name, defv)
6719
6764
 
@@ -6740,6 +6785,7 @@ class Layer(Prim):
6740
6785
  valu = await self.runt.dyncall(layriden, todo, gatekeys=gatekeys)
6741
6786
  self.valu[name] = valu
6742
6787
 
6788
+ @stormfunc(readonly=True)
6743
6789
  async def _methLayerPack(self):
6744
6790
  ldef = copy.deepcopy(self.valu)
6745
6791
  pushs = ldef.get('pushs')
@@ -6756,6 +6802,7 @@ class Layer(Prim):
6756
6802
 
6757
6803
  return ldef
6758
6804
 
6805
+ @stormfunc(readonly=True)
6759
6806
  async def _methLayerRepr(self):
6760
6807
  iden = self.valu.get('iden')
6761
6808
  name = self.valu.get('name', 'unnamed')
@@ -6852,10 +6899,9 @@ class LibView(Lib):
6852
6899
  async def _methViewGet(self, iden=None):
6853
6900
  if iden is None:
6854
6901
  iden = self.runt.snap.view.iden
6855
- todo = s_common.todo('getViewDef', iden)
6856
- vdef = await self.runt.dyncall('cortex', todo)
6902
+ vdef = await self.runt.snap.core.getViewDef(iden)
6857
6903
  if vdef is None:
6858
- raise s_exc.NoSuchView(mesg=iden)
6904
+ raise s_exc.NoSuchView(mesg=f'No view with {iden=}', iden=iden)
6859
6905
 
6860
6906
  return View(self.runt, vdef, path=self.path)
6861
6907
 
@@ -7098,7 +7144,7 @@ class View(Prim):
7098
7144
  view = self.runt.snap.core.getView(self.valu.get('iden'))
7099
7145
  if view is None: # pragma: no cover
7100
7146
  mesg = f'No view with iden: {self.valu.get("iden")}'
7101
- raise s_exc.NoSuchView(mesg=mesg)
7147
+ raise s_exc.NoSuchView(mesg=mesg, iden=self.valu.get('iden'))
7102
7148
 
7103
7149
  layers = await toprim(valu)
7104
7150
  layers = tuple(str(x) for x in layers)
@@ -7351,6 +7397,14 @@ class LibTrigger(Lib):
7351
7397
  if prop is not None:
7352
7398
  tdef['prop'] = prop
7353
7399
 
7400
+ verb = tdef.pop('verb', None)
7401
+ if verb is not None:
7402
+ tdef['verb'] = verb
7403
+
7404
+ n2form = tdef.pop('n2form', None)
7405
+ if n2form is not None:
7406
+ tdef['n2form'] = n2form
7407
+
7354
7408
  gatekeys = ((useriden, ('trigger', 'add'), viewiden),)
7355
7409
  todo = ('addTrigger', (tdef,), {})
7356
7410
  tdef = await self.dyncall(viewiden, todo, gatekeys=gatekeys)
@@ -7379,6 +7433,7 @@ class LibTrigger(Lib):
7379
7433
 
7380
7434
  return iden
7381
7435
 
7436
+ @stormfunc(readonly=True)
7382
7437
  async def _methTriggerList(self, all=False):
7383
7438
  if all:
7384
7439
  views = self.runt.snap.core.listViews()
@@ -7397,6 +7452,7 @@ class LibTrigger(Lib):
7397
7452
 
7398
7453
  return triggers
7399
7454
 
7455
+ @stormfunc(readonly=True)
7400
7456
  async def _methTriggerGet(self, iden):
7401
7457
  trigger = None
7402
7458
  try:
@@ -7479,6 +7535,7 @@ class Trigger(Prim):
7479
7535
  'pack': self.pack,
7480
7536
  }
7481
7537
 
7538
+ @stormfunc(readonly=True)
7482
7539
  async def pack(self):
7483
7540
  return copy.deepcopy(self.valu)
7484
7541
 
@@ -7519,7 +7576,7 @@ class Trigger(Prim):
7519
7576
  todo = s_common.todo('getViewDef', viewiden)
7520
7577
  vdef = await self.runt.dyncall('cortex', todo)
7521
7578
  if vdef is None:
7522
- raise s_exc.NoSuchView(mesg=viewiden)
7579
+ raise s_exc.NoSuchView(mesg=f'No view with iden={viewiden}', iden=viewiden)
7523
7580
 
7524
7581
  trigview = self.valu.get('view')
7525
7582
  self.runt.confirm(('view', 'read'), gateiden=viewiden)
@@ -7981,6 +8038,7 @@ class LibJsonStor(Lib):
7981
8038
  'cachedel': self.cachedel,
7982
8039
  })
7983
8040
 
8041
+ @stormfunc(readonly=True)
7984
8042
  async def has(self, path):
7985
8043
 
7986
8044
  if not self.runt.isAdmin():
@@ -7994,6 +8052,7 @@ class LibJsonStor(Lib):
7994
8052
  fullpath = ('cells', self.runt.snap.core.iden) + path
7995
8053
  return await self.runt.snap.core.hasJsonObj(fullpath)
7996
8054
 
8055
+ @stormfunc(readonly=True)
7997
8056
  async def get(self, path, prop=None):
7998
8057
 
7999
8058
  if not self.runt.isAdmin():
@@ -8054,6 +8113,7 @@ class LibJsonStor(Lib):
8054
8113
 
8055
8114
  return await self.runt.snap.core.delJsonObjProp(fullpath, prop=prop)
8056
8115
 
8116
+ @stormfunc(readonly=True)
8057
8117
  async def iter(self, path=None):
8058
8118
 
8059
8119
  if not self.runt.isAdmin():
@@ -8071,6 +8131,7 @@ class LibJsonStor(Lib):
8071
8131
  async for path, item in self.runt.snap.core.getJsonObjs(fullpath):
8072
8132
  yield path, item
8073
8133
 
8134
+ @stormfunc(readonly=True)
8074
8135
  async def cacheget(self, path, key, asof='now', envl=False):
8075
8136
 
8076
8137
  if not self.runt.isAdmin():
@@ -8238,6 +8299,7 @@ class UserJson(Prim):
8238
8299
  'iter': self.iter,
8239
8300
  })
8240
8301
 
8302
+ @stormfunc(readonly=True)
8241
8303
  async def has(self, path):
8242
8304
 
8243
8305
  path = await toprim(path)
@@ -8250,6 +8312,7 @@ class UserJson(Prim):
8250
8312
 
8251
8313
  return await self.runt.snap.core.hasJsonObj(fullpath)
8252
8314
 
8315
+ @stormfunc(readonly=True)
8253
8316
  async def get(self, path, prop=None):
8254
8317
  path = await toprim(path)
8255
8318
  prop = await toprim(prop)
@@ -8304,6 +8367,7 @@ class UserJson(Prim):
8304
8367
 
8305
8368
  return await self.runt.snap.core.delJsonObjProp(fullpath, prop=prop)
8306
8369
 
8370
+ @stormfunc(readonly=True)
8307
8371
  async def iter(self, path=None):
8308
8372
 
8309
8373
  path = await toprim(path)
@@ -8380,7 +8444,7 @@ class User(Prim):
8380
8444
  ),
8381
8445
  'returns': {'type': 'boolean', 'desc': 'True if the rule is allowed, False otherwise.', }}},
8382
8446
  {'name': 'getAllowedReason', 'desc': 'Return an allowed status and reason for the given perm.',
8383
- 'type': {'type': 'function', '_funcname': 'getAllowedReason',
8447
+ 'type': {'type': 'function', '_funcname': '_methGetAllowedReason',
8384
8448
  'args': (
8385
8449
  {'name': 'permname', 'type': 'str', 'desc': 'The permission string to check.', },
8386
8450
  {'name': 'gateiden', 'type': 'str', 'desc': 'The authgate iden.', 'default': None, },
@@ -8459,7 +8523,7 @@ class User(Prim):
8459
8523
  ),
8460
8524
  'returns': {'type': 'null', }}},
8461
8525
  {'name': 'getRules', 'desc': 'Get the rules for the user and optional auth gate.',
8462
- 'type': {'type': 'function', '_funcname': 'getRules',
8526
+ 'type': {'type': 'function', '_funcname': '_methGetRules',
8463
8527
  'args': (
8464
8528
  {'name': 'gateiden', 'type': 'str',
8465
8529
  'desc': 'The gate iden used for the rules.', 'default': None},
@@ -8494,7 +8558,7 @@ class User(Prim):
8494
8558
  ),
8495
8559
  'returns': {'type': 'null', }}},
8496
8560
  {'name': 'gates', 'desc': 'Return a list of auth gates that the user has rules for.',
8497
- 'type': {'type': 'function', '_funcname': 'gates',
8561
+ 'type': {'type': 'function', '_funcname': '_methGates',
8498
8562
  'args': (),
8499
8563
  'returns': {'type': 'list',
8500
8564
  'desc': 'A list of ``auth:gates`` that the user has rules for.', }}},
@@ -8577,7 +8641,7 @@ class User(Prim):
8577
8641
  'get': self._methUserGet,
8578
8642
  'pack': self._methUserPack,
8579
8643
  'tell': self._methUserTell,
8580
- 'gates': self.gates,
8644
+ 'gates': self._methGates,
8581
8645
  'notify': self._methUserNotify,
8582
8646
  'roles': self._methUserRoles,
8583
8647
  'allowed': self._methUserAllowed,
@@ -8587,15 +8651,16 @@ class User(Prim):
8587
8651
  'delRule': self._methUserDelRule,
8588
8652
  'popRule': self._methUserPopRule,
8589
8653
  'setRoles': self._methUserSetRoles,
8590
- 'getRules': self.getRules,
8654
+ 'getRules': self._methGetRules,
8591
8655
  'setRules': self._methUserSetRules,
8592
8656
  'setAdmin': self._methUserSetAdmin,
8593
8657
  'setEmail': self._methUserSetEmail,
8594
8658
  'setLocked': self._methUserSetLocked,
8595
8659
  'setPasswd': self._methUserSetPasswd,
8596
- 'getAllowedReason': self.getAllowedReason,
8660
+ 'getAllowedReason': self._methGetAllowedReason,
8597
8661
  }
8598
8662
 
8663
+ @stormfunc(readonly=True)
8599
8664
  async def _methUserPack(self):
8600
8665
  return await self.value()
8601
8666
 
@@ -8634,7 +8699,8 @@ class User(Prim):
8634
8699
  udef = await self.runt.snap.core.getUserDef(self.valu)
8635
8700
  return udef.get(name)
8636
8701
 
8637
- async def gates(self):
8702
+ @stormfunc(readonly=True)
8703
+ async def _methGates(self):
8638
8704
  user = self.runt.snap.core.auth.user(self.valu)
8639
8705
  retn = []
8640
8706
  for gateiden in user.authgates.keys():
@@ -8642,10 +8708,12 @@ class User(Prim):
8642
8708
  retn.append(Gate(self.runt, gate))
8643
8709
  return retn
8644
8710
 
8711
+ @stormfunc(readonly=True)
8645
8712
  async def _methUserRoles(self):
8646
8713
  udef = await self.runt.snap.core.getUserDef(self.valu)
8647
8714
  return [Role(self.runt, rdef['iden']) for rdef in udef.get('roles')]
8648
8715
 
8716
+ @stormfunc(readonly=True)
8649
8717
  async def _methUserAllowed(self, permname, gateiden=None, default=False):
8650
8718
  permname = await tostr(permname)
8651
8719
  gateiden = await tostr(gateiden)
@@ -8655,7 +8723,8 @@ class User(Prim):
8655
8723
  user = await self.runt.snap.core.auth.reqUser(self.valu)
8656
8724
  return user.allowed(perm, gateiden=gateiden, default=default)
8657
8725
 
8658
- async def getAllowedReason(self, permname, gateiden=None, default=False):
8726
+ @stormfunc(readonly=True)
8727
+ async def _methGetAllowedReason(self, permname, gateiden=None, default=False):
8659
8728
  permname = await tostr(permname)
8660
8729
  gateiden = await tostr(gateiden)
8661
8730
  default = await tobool(default)
@@ -8685,7 +8754,8 @@ class User(Prim):
8685
8754
  self.runt.confirm(('auth', 'user', 'set', 'rules'), gateiden=gateiden)
8686
8755
  await self.runt.snap.core.setUserRules(self.valu, rules, gateiden=gateiden)
8687
8756
 
8688
- async def getRules(self, gateiden=None):
8757
+ @stormfunc(readonly=True)
8758
+ async def _methGetRules(self, gateiden=None):
8689
8759
  gateiden = await tostr(gateiden, noneok=True)
8690
8760
  user = self.runt.snap.core.auth.user(self.valu)
8691
8761
  return user.getRules(gateiden=gateiden)
@@ -8709,7 +8779,7 @@ class User(Prim):
8709
8779
  self.runt.confirm(('auth', 'user', 'set', 'rules'), gateiden=gateiden)
8710
8780
 
8711
8781
  indx = await toint(indx)
8712
- rules = list(await self.getRules(gateiden=gateiden))
8782
+ rules = list(await self._methGetRules(gateiden=gateiden))
8713
8783
 
8714
8784
  if len(rules) <= indx:
8715
8785
  mesg = f'User {self.valu} only has {len(rules)} rules.'
@@ -8772,7 +8842,7 @@ class Role(Prim):
8772
8842
  'type': {'type': 'function', '_funcname': '_methRolePack', 'args': (),
8773
8843
  'returns': {'type': 'dict', 'desc': 'The packed Role definition.', }}},
8774
8844
  {'name': 'gates', 'desc': 'Return a list of auth gates that the role has rules for.',
8775
- 'type': {'type': 'function', '_funcname': 'gates',
8845
+ 'type': {'type': 'function', '_funcname': '_methGates',
8776
8846
  'args': (),
8777
8847
  'returns': {'type': 'list',
8778
8848
  'desc': 'A list of ``auth:gates`` that the role has rules for.', }}},
@@ -8803,7 +8873,7 @@ class Role(Prim):
8803
8873
  ),
8804
8874
  'returns': {'type': 'list', 'desc': 'The rule which was removed.'}}},
8805
8875
  {'name': 'getRules', 'desc': 'Get the rules for the role and optional auth gate.',
8806
- 'type': {'type': 'function', '_funcname': 'getRules',
8876
+ 'type': {'type': 'function', '_funcname': '_methGetRules',
8807
8877
  'args': (
8808
8878
  {'name': 'gateiden', 'type': 'str',
8809
8879
  'desc': 'The gate iden used for the rules.', 'default': None},
@@ -8848,12 +8918,12 @@ class Role(Prim):
8848
8918
  return {
8849
8919
  'get': self._methRoleGet,
8850
8920
  'pack': self._methRolePack,
8851
- 'gates': self.gates,
8921
+ 'gates': self._methGates,
8852
8922
  'addRule': self._methRoleAddRule,
8853
8923
  'delRule': self._methRoleDelRule,
8854
8924
  'popRule': self._methRolePopRule,
8855
8925
  'setRules': self._methRoleSetRules,
8856
- 'getRules': self.getRules,
8926
+ 'getRules': self._methGetRules,
8857
8927
  }
8858
8928
 
8859
8929
  async def _derefGet(self, name):
@@ -8865,14 +8935,17 @@ class Role(Prim):
8865
8935
  name = await tostr(name)
8866
8936
  await self.runt.snap.core.setRoleName(self.valu, name)
8867
8937
 
8938
+ @stormfunc(readonly=True)
8868
8939
  async def _methRoleGet(self, name):
8869
8940
  rdef = await self.runt.snap.core.getRoleDef(self.valu)
8870
8941
  return rdef.get(name)
8871
8942
 
8943
+ @stormfunc(readonly=True)
8872
8944
  async def _methRolePack(self):
8873
8945
  return await self.value()
8874
8946
 
8875
- async def gates(self):
8947
+ @stormfunc(readonly=True)
8948
+ async def _methGates(self):
8876
8949
  role = self.runt.snap.core.auth.role(self.valu)
8877
8950
  retn = []
8878
8951
  for gateiden in role.authgates.keys():
@@ -8880,7 +8953,8 @@ class Role(Prim):
8880
8953
  retn.append(Gate(self.runt, gate))
8881
8954
  return retn
8882
8955
 
8883
- async def getRules(self, gateiden=None):
8956
+ @stormfunc(readonly=True)
8957
+ async def _methGetRules(self, gateiden=None):
8884
8958
  gateiden = await tostr(gateiden, noneok=True)
8885
8959
  role = self.runt.snap.core.auth.role(self.valu)
8886
8960
  return role.getRules(gateiden=gateiden)
@@ -8911,7 +8985,7 @@ class Role(Prim):
8911
8985
 
8912
8986
  indx = await toint(indx)
8913
8987
 
8914
- rules = list(await self.getRules(gateiden=gateiden))
8988
+ rules = list(await self._methGetRules(gateiden=gateiden))
8915
8989
 
8916
8990
  if len(rules) <= indx:
8917
8991
  mesg = f'Role {self.valu} only has {len(rules)} rules.'
@@ -9404,6 +9478,7 @@ class LibCron(Lib):
9404
9478
  self.runt.confirm(('cron', 'set'), gateiden=iden)
9405
9479
  return await self.runt.snap.core.moveCronJob(self.runt.user.iden, iden, view)
9406
9480
 
9481
+ @stormfunc(readonly=True)
9407
9482
  async def _methCronList(self):
9408
9483
  todo = s_common.todo('listCronJobs')
9409
9484
  gatekeys = ((self.runt.user.iden, ('cron', 'get'), None),)
@@ -9411,6 +9486,7 @@ class LibCron(Lib):
9411
9486
 
9412
9487
  return [CronJob(self.runt, cdef, path=self.path) for cdef in defs]
9413
9488
 
9489
+ @stormfunc(readonly=True)
9414
9490
  async def _methCronGet(self, prefix):
9415
9491
  cdef = await self._matchIdens(prefix, ('cron', 'get'))
9416
9492
 
@@ -9498,6 +9574,7 @@ class CronJob(Prim):
9498
9574
 
9499
9575
  return self
9500
9576
 
9577
+ @stormfunc(readonly=True)
9501
9578
  async def _methCronJobPack(self):
9502
9579
  return copy.deepcopy(self.valu)
9503
9580
 
@@ -9505,6 +9582,7 @@ class CronJob(Prim):
9505
9582
  def _formatTimestamp(ts):
9506
9583
  return datetime.datetime.fromtimestamp(ts, datetime.UTC).strftime('%Y-%m-%dT%H:%M')
9507
9584
 
9585
+ @stormfunc(readonly=True)
9508
9586
  async def _methCronJobPprint(self):
9509
9587
  user = self.valu.get('username')
9510
9588
  view = self.valu.get('view')
@@ -9748,13 +9826,15 @@ async def toiter(valu, noneok=False):
9748
9826
  return
9749
9827
 
9750
9828
  if isinstance(valu, Prim):
9751
- async for item in valu.iter():
9752
- yield item
9829
+ async with contextlib.aclosing(valu.iter()) as agen:
9830
+ async for item in agen:
9831
+ yield item
9753
9832
  return
9754
9833
 
9755
9834
  try:
9756
- async for item in s_coro.agen(valu):
9757
- yield item
9835
+ async with contextlib.aclosing(s_coro.agen(valu)) as agen:
9836
+ async for item in agen:
9837
+ yield item
9758
9838
  except TypeError as e:
9759
9839
  mesg = f'Value is not iterable: {valu!r}'
9760
9840
  raise s_exc.StormRuntimeError(mesg=mesg) from e