kaqing 2.0.186__py3-none-any.whl → 2.0.188__py3-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 kaqing might be problematic. Click here for more details.

adam/app_session.py CHANGED
@@ -8,7 +8,7 @@ from adam.log import Log
8
8
  from adam.sso.idp import Idp
9
9
  from adam.sso.idp_login import IdpLogin
10
10
  from adam.config import Config
11
- from adam.utils import debug, debug_trace, json_to_csv, tabulize, log, log2, log_exc
11
+ from adam.utils import debug, debug_trace, json_to_csv, tabulize, log2, log_exc
12
12
  from adam.apps import Apps
13
13
 
14
14
  class AppLogin:
adam/embedded_params.py CHANGED
@@ -1,2 +1,2 @@
1
1
  def config():
2
- return {'app': {'console-endpoint': 'https://{host}/{env}/{app}/static/console/index.html', 'container-name': 'c3-server', 'cr': {'cluster-regex': '(.*?-.*?)-.*', 'group': 'ops.c3.ai', 'v': 'v2', 'plural': 'c3cassandras'}, 'label': 'c3__app_id-0', 'login': {'admin-group': '{host}/C3.ClusterAdmin', 'ingress': '{app_id}-k8singr-appleader-001', 'timeout': 5, 'session-check-url': 'https://{host}/{env}/{app}/api/8/C3/userSessionToken', 'cache-creds': True, 'cache-username': True, 'url': 'https://{host}/{env}/{app}', 'another': "You're logged in to {has}. However, for this app, you need to log in to {need}.", 'token-server-url': 'http://localhost:{port}', 'password-max-length': 128}, 'strip': '0'}, 'audit': {'endpoint': 'https://4psvtaxlcb.execute-api.us-west-2.amazonaws.com/prod/', 'workers': 3, 'timeout': 10, 'log-audit-queries': False, 'athena': {'auto-repair': {'elapsed_hours': 12}, 'region': 'us-west-2', 'catalog': 'AwsDataCatalog', 'database': 'audit', 'repair-partition-tables': 'audit', 'output': 's3://s3.ops--audit/ddl/results', 'repair-cluster-tables': 'cluster'}, 'queries': {'last10': "SELECT * FROM audit\nWHERE drive <> 'z' and ({date_condition})\nORDER BY ts DESC LIMIT {limit}", 'slow10': "SELECT * FROM audit\nWHERE drive <> 'z' and ({date_condition})\nORDER BY CAST(duration AS REAL) DESC LIMIT {limit}", 'top10': "SELECT min(c) AS cluster, line, COUNT(*) AS cnt, avg(CAST(duration AS REAL)) AS duration\nFROM audit WHERE drive <> 'z' and ({date_condition})\nGROUP BY line ORDER BY cnt DESC LIMIT {limit}"}}, 'bash': {'workers': 32}, 'cassandra': {'service-name': 'all-pods-service'}, 'cql': {'workers': 32, 'samples': 3, 'secret': {'cluster-regex': '(.*?-.*?)-.*', 'name': '{cluster}-superuser', 'password-item': 'password'}, 'alter-tables': {'excludes': 'system_auth,system_traces,reaper_db,system_distributed,system_views,system,system_schema,system_virtual_schema', 'gc-grace-periods': '3600,86400,864000,7776000', 'batching': True}}, 'checks': {'compactions-threshold': 250, 'cpu-busy-threshold': 98.0, 'cpu-threshold': 0.0, 'cassandra-data-path': '/c3/cassandra', 'root-disk-threshold': 50, 'cassandra-disk-threshold': 50, 'snapshot-size-cmd': "ls /c3/cassandra/data/data/*/*/snapshots | grep snapshots | sed 's/:$//g' | xargs -I {} du -sk {} | awk '{print $1}' | awk '{s+=$1} END {print s}'", 'snapshot-size-threshold': '40G', 'table-sizes-cmd': "ls -Al /c3/cassandra/data/data/ | awk '{print $9}' | sed 's/\\^r//g' | xargs -I {} du -sk /c3/cassandra/data/data/{}"}, 'download': {'workers': 8}, 'export': {'workers': 8, 'csv_dir': '/c3/cassandra/tmp', 'column_counts_query': 'select id, count(id) as columns from {table} group by id order by columns desc limit 10', 'default-importer': 'sqlite', 'sqlite': {'workers': 8, 'columns': '<row-key>', 'local-db-dir': '/tmp/qing-db'}, 'athena': {'workers': 8, 'columns': '<keys>', 'bucket': 'c3.ops--qing'}, 'csv': {'workers': 8, 'columns': '<row-key>'}, 'log-prefix': '/tmp/qing'}, 'get-host-id': {'workers': 32}, 'idps': {'ad': {'email-pattern': '.*@c3.ai', 'uri': 'https://login.microsoftonline.com/53ad779a-93e7-485c-ba20-ac8290d7252b/oauth2/v2.0/authorize?response_type=id_token&response_mode=form_post&client_id=00ff94a8-6b0a-4715-98e0-95490012d818&scope=openid+email+profile&redirect_uri=https%3A%2F%2Fplat.c3ci.cloud%2Fc3%2Fc3%2Foidc%2Flogin&nonce={nonce}&state=EMPTY', 'jwks-uri': 'https://login.microsoftonline.com/common/discovery/keys', 'contact': 'Please contact ted.tran@c3.ai.', 'whitelist-file': '/kaqing/members'}, 'okta': {'default': True, 'email-pattern': '.*@c3iot.com', 'uri': 'https://c3energy.okta.com/oauth2/v1/authorize?response_type=id_token&response_mode=form_post&client_id={client_id}&scope=openid+email+profile+groups&redirect_uri=https%3A%2F%2F{host}%2Fc3%2Fc3%2Foidc%2Flogin&nonce={nonce}&state=EMPTY', 'jwks-uri': 'https://c3energy.okta.com/oauth2/v1/keys'}}, 'issues': {'workers': 32}, 'local-tmp-dir': '/tmp/qing-db', 'logs': {'path': '/c3/cassandra/logs/system.log'}, 'log-prefix': '/tmp/qing', 'nodetool': {'workers': 96, 'commands_in_line': 40, 'status': {'workers': 32, 'samples': 3, 'commands_in_line': 40}}, 'pg': {'name-pattern': '^{namespace}.*-k8spg-.*', 'excludes': '.helm., -admin-secret', 'agent': {'name': 'ops-pg-agent', 'just-in-time': False, 'timeout': 86400, 'image': 'seanahnsf/kaqing'}, 'default-db': 'postgres', 'default-schema': 'postgres', 'secret': {'endpoint-key': 'postgres-db-endpoint', 'port-key': 'postgres-db-port', 'username-key': 'postgres-admin-username', 'password-key': 'postgres-admin-password'}}, 'pod': {'name': 'ops', 'image': 'seanahnsf/kaqing-cloud', 'sa': {'name': 'ops', 'proto': 'c3', 'additional-cluster-roles': 'c3aiops-k8ssandra-operator'}, 'label-selector': 'run=ops'}, 'preview': {'rows': 10}, 'processes': {'columns': 'pod,cpu-metrics,mem', 'header': 'POD_NAME,M_CPU(USAGE/LIMIT),MEM/LIMIT'}, 'processes-qing': {'columns': 'pod,cpu,mem', 'header': 'POD_NAME,Q_CPU/TOTAL,MEM/LIMIT'}, 'reaper': {'service-name': 'reaper-service', 'port-forward': {'timeout': 86400, 'local-port': 9001}, 'abort-runs-batch': 10, 'show-runs-batch': 100, 'pod': {'cluster-regex': '(.*?-.*?-.*?-.*?)-.*', 'label-selector': 'k8ssandra.io/reaper={cluster}-reaper'}, 'secret': {'cluster-regex': '(.*?-.*?)-.*', 'name': '{cluster}-reaper-ui', 'password-item': 'password'}}, 'repair': {'log-path': '/home/cassrepair/logs/', 'image': 'ci-registry.c3iot.io/cloudops/cassrepair:2.0.14', 'secret': 'ciregistryc3iotio', 'env': {'interval': 24, 'timeout': 60, 'pr': False, 'runs': 1}}, 'repl': {'start-drive': 'c', 'a': {'auto-enter': 'c3/c3/*'}, 'c': {'auto-enter': 'cluster'}, 'x': {'auto-enter': 'latest'}, 'history': {'push-cat-log-file': True, 'push-cat-remote-log-file': True}, 'background-process': {'auto-nohup': True}}, 'status': {'columns': 'status,address,load,tokens,owns,host_id,gossip,compactions', 'header': '--,Address,Load,Tokens,Owns,Host ID,GOSSIP,COMPACTIONS'}, 'storage': {'columns': 'pod,volume_root,volume_cassandra,snapshots,data,compactions', 'header': 'POD_NAME,VOLUME /,VOLUME CASS,SNAPSHOTS,DATA,COMPACTIONS'}, 'watch': {'auto': 'rollout', 'timeout': 3600, 'interval': 10}, 'auto-complete': {'c': {'tables': 'lazy'}, 'x': {'tables': 'lazy'}, 'cli': {'cp': 'jit'}, 'export': {'databases': 'jit'}, 'medusa': {'backups': 'jit'}, 'reaper': {'schedules': 'lazy'}}, 'debug': False, 'debugs': {'timings': False, 'exit-on-error': False, 'show-parallelism': False}}
2
+ return {'app': {'console-endpoint': 'https://{host}/{env}/{app}/static/console/index.html', 'container-name': 'c3-server', 'cr': {'cluster-regex': '(.*?-.*?)-.*', 'group': 'ops.c3.ai', 'v': 'v2', 'plural': 'c3cassandras'}, 'label': 'c3__app_id-0', 'login': {'admin-group': '{host}/C3.ClusterAdmin', 'ingress': '{app_id}-k8singr-appleader-001', 'timeout': 5, 'session-check-url': 'https://{host}/{env}/{app}/api/8/C3/userSessionToken', 'cache-creds': True, 'cache-username': True, 'url': 'https://{host}/{env}/{app}', 'another': "You're logged in to {has}. However, for this app, you need to log in to {need}.", 'token-server-url': 'http://localhost:{port}', 'password-max-length': 128}, 'strip': '0'}, 'audit': {'endpoint': 'https://4psvtaxlcb.execute-api.us-west-2.amazonaws.com/prod/', 'workers': 3, 'timeout': 10, 'log-audit-queries': False, 'athena': {'auto-repair': {'elapsed_hours': 12}, 'region': 'us-west-2', 'catalog': 'AwsDataCatalog', 'database': 'audit', 'repair-partition-tables': 'audit', 'output': 's3://s3.ops--audit/ddl/results', 'repair-cluster-tables': 'cluster'}, 'queries': {'last10': "SELECT * FROM audit\nWHERE drive <> 'z' and ({date_condition})\nORDER BY ts DESC LIMIT {limit}", 'slow10': "SELECT * FROM audit\nWHERE drive <> 'z' and ({date_condition})\nORDER BY CAST(duration AS REAL) DESC LIMIT {limit}", 'top10': "SELECT min(c) AS cluster, line, COUNT(*) AS cnt, avg(CAST(duration AS REAL)) AS duration\nFROM audit WHERE drive <> 'z' and ({date_condition})\nGROUP BY line ORDER BY cnt DESC LIMIT {limit}"}}, 'bash': {'workers': 32}, 'cassandra': {'service-name': 'all-pods-service'}, 'cql': {'workers': 32, 'samples': 3, 'secret': {'cluster-regex': '(.*?-.*?)-.*', 'name': '{cluster}-superuser', 'password-item': 'password'}, 'alter-tables': {'excludes': 'system_auth,system_traces,reaper_db,system_distributed,system_views,system,system_schema,system_virtual_schema', 'gc-grace-periods': '3600,86400,864000,7776000', 'batching': True}}, 'checks': {'compactions-threshold': 250, 'cpu-busy-threshold': 98.0, 'cpu-threshold': 0.0, 'cassandra-data-path': '/c3/cassandra', 'root-disk-threshold': 50, 'cassandra-disk-threshold': 50, 'snapshot-size-cmd': "ls /c3/cassandra/data/data/*/*/snapshots | grep snapshots | sed 's/:$//g' | xargs -I {} du -sk {} | awk '{print $1}' | awk '{s+=$1} END {print s}'", 'snapshot-size-threshold': '40G', 'table-sizes-cmd': "ls -Al /c3/cassandra/data/data/ | awk '{print $9}' | sed 's/\\^r//g' | xargs -I {} du -sk /c3/cassandra/data/data/{}"}, 'download': {'workers': 8}, 'export': {'workers': 8, 'csv_dir': '/c3/cassandra/tmp', 'column_counts_query': 'select id, count(id) as columns from {table} group by id order by columns desc limit 10', 'default-importer': 'sqlite', 'sqlite': {'workers': 8, 'columns': '<row-key>', 'local-db-dir': '/tmp/qing-db'}, 'athena': {'workers': 8, 'columns': '<keys>', 'bucket': 'c3.ops--qing'}, 'csv': {'workers': 8, 'columns': '<row-key>'}, 'log-prefix': '/tmp/qing'}, 'get-host-id': {'workers': 32}, 'idps': {'ad': {'email-pattern': '.*@c3.ai', 'uri': 'https://login.microsoftonline.com/53ad779a-93e7-485c-ba20-ac8290d7252b/oauth2/v2.0/authorize?response_type=id_token&response_mode=form_post&client_id=00ff94a8-6b0a-4715-98e0-95490012d818&scope=openid+email+profile&redirect_uri=https%3A%2F%2Fplat.c3ci.cloud%2Fc3%2Fc3%2Foidc%2Flogin&nonce={nonce}&state=EMPTY', 'jwks-uri': 'https://login.microsoftonline.com/common/discovery/keys', 'contact': 'Please contact ted.tran@c3.ai.', 'whitelist-file': '/kaqing/members'}, 'okta': {'default': True, 'email-pattern': '.*@c3iot.com', 'uri': 'https://c3energy.okta.com/oauth2/v1/authorize?response_type=id_token&response_mode=form_post&client_id={client_id}&scope=openid+email+profile+groups&redirect_uri=https%3A%2F%2F{host}%2Fc3%2Fc3%2Foidc%2Flogin&nonce={nonce}&state=EMPTY', 'jwks-uri': 'https://c3energy.okta.com/oauth2/v1/keys'}}, 'issues': {'workers': 32}, 'local-tmp-dir': '/tmp/qing-db', 'logs': {'path': '/c3/cassandra/logs/system.log'}, 'log-prefix': '/tmp/qing', 'nodetool': {'workers': 96, 'commands_in_line': 40, 'status': {'workers': 32, 'samples': 3, 'commands_in_line': 40}}, 'pg': {'name-pattern': '^{namespace}.*-k8spg-.*', 'excludes': '.helm., -admin-secret', 'agent': {'name': 'ops-pg-agent', 'just-in-time': False, 'timeout': 86400, 'image': 'seanahnsf/kaqing'}, 'default-db': 'postgres', 'default-schema': 'postgres', 'secret': {'endpoint-key': 'postgres-db-endpoint', 'port-key': 'postgres-db-port', 'username-key': 'postgres-admin-username', 'password-key': 'postgres-admin-password'}}, 'pod': {'name': 'ops', 'image': 'seanahnsf/kaqing-cloud', 'sa': {'name': 'ops', 'proto': 'c3', 'additional-cluster-roles': 'c3aiops-k8ssandra-operator'}, 'label-selector': 'run=ops'}, 'preview': {'rows': 10}, 'processes': {'columns': 'pod,cpu-metrics,mem', 'header': 'POD_NAME,M_CPU(USAGE/LIMIT),MEM/LIMIT'}, 'processes-qing': {'columns': 'pod,cpu,mem', 'header': 'POD_NAME,Q_CPU/TOTAL,MEM/LIMIT'}, 'reaper': {'service-name': 'reaper-service', 'port-forward': {'timeout': 86400, 'local-port': 9001}, 'abort-runs-batch': 10, 'show-runs-batch': 100, 'pod': {'cluster-regex': '(.*?-.*?-.*?-.*?)-.*', 'label-selector': 'k8ssandra.io/reaper={cluster}-reaper'}, 'secret': {'cluster-regex': '(.*?-.*?)-.*', 'name': '{cluster}-reaper-ui', 'password-item': 'password'}}, 'repair': {'log-path': '/home/cassrepair/logs/', 'image': 'ci-registry.c3iot.io/cloudops/cassrepair:2.0.14', 'secret': 'ciregistryc3iotio', 'env': {'interval': 24, 'timeout': 60, 'pr': False, 'runs': 1}}, 'repl': {'start-drive': 'c', 'a': {'auto-enter': 'c3/c3'}, 'c': {'auto-enter': 'cluster'}, 'x': {'auto-enter': 'latest'}, 'history': {'push-cat-log-file': True, 'push-cat-remote-log-file': True}, 'background-process': {'auto-nohup': True}}, 'status': {'columns': 'status,address,load,tokens,owns,host_id,gossip,compactions', 'header': '--,Address,Load,Tokens,Owns,Host ID,GOSSIP,COMPACTIONS'}, 'storage': {'columns': 'pod,volume_root,volume_cassandra,snapshots,data,compactions', 'header': 'POD_NAME,VOLUME /,VOLUME CASS,SNAPSHOTS,DATA,COMPACTIONS'}, 'watch': {'auto': 'rollout', 'timeout': 3600, 'interval': 10}, 'auto-complete': {'c': {'tables': 'lazy'}, 'x': {'tables': 'lazy'}, 'cli': {'cp': 'jit'}, 'export': {'databases': 'jit'}, 'medusa': {'backups': 'jit'}, 'reaper': {'schedules': 'lazy'}}, 'debug': False, 'debugs': {'timings': False, 'exit-on-error': False, 'show-parallelism': False}}
@@ -176,6 +176,8 @@ class LarkCompleter(Completer, AppendableCompleter):
176
176
  # for lazy completions
177
177
  self.nested = NestedCompleter.from_nested_dict(self.options_lambda())
178
178
 
179
+ nested_words = set()
180
+
179
181
  if self.nested:
180
182
  # from NestedCompleter
181
183
 
@@ -200,6 +202,7 @@ class LarkCompleter(Completer, AppendableCompleter):
200
202
  )
201
203
 
202
204
  for c in completer.get_completions(new_document, complete_event):
205
+ nested_words.add(c.text)
203
206
  yield c
204
207
 
205
208
  # No space in the input: behave exactly like `WordCompleter`.
@@ -208,6 +211,7 @@ class LarkCompleter(Completer, AppendableCompleter):
208
211
  list(self.nested.options.keys()), ignore_case=self.nested.ignore_case
209
212
  )
210
213
  for c in completer.get_completions(document, complete_event):
214
+ nested_words.add(c.text)
211
215
  yield c
212
216
 
213
217
  if self.parser:
@@ -244,12 +248,12 @@ class LarkCompleter(Completer, AppendableCompleter):
244
248
  def word_matches(word: str) -> bool:
245
249
  return word.lower().startswith(word_before_cursor)
246
250
 
247
- for a in words:
248
- if word_matches(a):
249
- display = self.display_dict.get(a, a)
250
- display_meta = self.meta_dict.get(a, "")
251
+ for word in words:
252
+ if word_matches(word) and word not in nested_words:
253
+ display = self.display_dict.get(word, word)
254
+ display_meta = self.meta_dict.get(word, "")
251
255
  yield Completion(
252
- a,
256
+ word,
253
257
  -len(word_before_cursor),
254
258
  display=display,
255
259
  display_meta=display_meta,
adam/version.py CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
- __version__ = "2.0.186" #: the working version
4
+ __version__ = "2.0.188" #: the working version
5
5
  __release__ = "1.0.0" #: the release version
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kaqing
3
- Version: 2.0.186
3
+ Version: 2.0.188
4
4
  Summary: UNKNOWN
5
5
  Home-page: UNKNOWN
6
6
  License: UNKNOWN
@@ -1,12 +1,12 @@
1
1
  adam/__init__.py,sha256=is7iqn2nhRzPymhTEajITEFVyvROZ9GWfNsZX3L5g_o,45
2
- adam/app_session.py,sha256=4bRs1uYvaFWnWlTyQctSeR3BE2Dk0bVe509LbqvX9iE,6841
2
+ adam/app_session.py,sha256=I2EX7eNRCP6T9u1BTVLs-5SB1ypyhSwNvVmi4nwoU-0,6836
3
3
  adam/apps.py,sha256=f1qsIOYjn4fdpCvMfOBns5YEiA5fMm7yZu3cQrK6z2M,7049
4
4
  adam/batch.py,sha256=c1FgH3-glAqBdAXMEGBe9MTHnqGFUXfsgLB1Mw9LV60,24041
5
5
  adam/cli.py,sha256=03pIZdomAu7IL-GSP6Eun_PKwwISShRAmfx6eVRPGC0,458
6
6
  adam/cli_group.py,sha256=W3zy1BghCtVcEXizq8fBH-93ZRVVwgAyGPzy0sHno1Y,593
7
7
  adam/config.py,sha256=snozVzu-jaws8PFMNH489Iv-43ptYa5pp4aGeTKRQnw,2778
8
8
  adam/embedded_apps.py,sha256=lKPx63mKzJbNmwz0rgL4gF76M9fDGxraYTtNAIGnZ_s,419
9
- adam/embedded_params.py,sha256=hHFebMjFpWuviGC6n6AsLDxm4nC8fsqEcCg1mvyUa8c,6429
9
+ adam/embedded_params.py,sha256=NaD3Oc5LGfT2QRK_S3bOv9O4Ii8kb2JMU1pGxztmW2Q,6427
10
10
  adam/log.py,sha256=vcJ1Q8LLnt3NSXqpVcKjAI2OZE6KaD3PEi1kfu_D8qs,1156
11
11
  adam/pod_exec_result.py,sha256=85jy_5dS6TEEk5ijU0B62YfUycxmD3dG8mhIHFPipc8,1260
12
12
  adam/repl.py,sha256=_GVboHyXRcpr0l0gQAgiQ5LNTXgH3cXSvvC_aNxQmDw,7574
@@ -20,7 +20,7 @@ adam/utils_issues.py,sha256=nWhzUXmD2IfbT8MzjdyvuvpKrtUoieF74O2joaWFpUU,1438
20
20
  adam/utils_local.py,sha256=3RIvP5ZluJhOl-z9qi5U4bLFP5_vuYGnjcY-koO40lE,109
21
21
  adam/utils_net.py,sha256=byEtNVr8iG9UaD7dM77dN2WEBClB7YNKult7LKFTCOc,428
22
22
  adam/utils_sqlite.py,sha256=z34AxQL1HZBcv704NXZsMerWt-BPtnCUUw1rZHQB9Bw,4330
23
- adam/version.py,sha256=hUfNKxhSPSB0USqdoJrnbKI5GTxNGYyhIVYwoyw1oSE,140
23
+ adam/version.py,sha256=BINgYFo4SHBKqDKm610CdGiykSH7P1Tcc7tYM9JtmmY,140
24
24
  adam/checks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
25
  adam/checks/check.py,sha256=Qopr3huYcMu2bzQgb99dEUYjFzkjKHRI76S6KA9b9Rk,702
26
26
  adam/checks/check_context.py,sha256=FEHkQ32jY1EDopQ2uYWqy9v7aEEX1orLpJWhopwAlh4,402
@@ -205,7 +205,7 @@ adam/commands/show/show_params.py,sha256=6rM9IgHusa5MrqLdHOBzBMOh1mOnlkFDbZeFGdX
205
205
  adam/commands/show/show_processes.py,sha256=bkdFF8fvnNCZ1YTe1ucxtKDTt40w1lLOHbx8FcshyEI,2378
206
206
  adam/commands/show/show_storage.py,sha256=AfqOn9ypo4G762aN8a5ZWW4IUpPDehM6R3QByGCpMFk,1734
207
207
  adam/sql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
208
- adam/sql/lark_completer.py,sha256=X8ZzYHzUy8ATsA6a4c84t9D_Jya1BGKKpvOxtKr5pvk,12309
208
+ adam/sql/lark_completer.py,sha256=RrL4OK_3pmYXPMxWO29xikSlt1v1Z3bAWsTv9e9Wu_c,12480
209
209
  adam/sql/lark_parser.py,sha256=oNuPKfVTS1QBJ0wB3OXhBydmzgdCDED3LAheRM5cbiM,21378
210
210
  adam/sql/sql_completer.py,sha256=RO-S4OiBuDPUL8EWiymB8JexIwgwNXx1QzErDxuL3y4,3939
211
211
  adam/sql/sql_state_machine.py,sha256=3m8JsIg_tojwaHY5AdPl6UEE4ZnB5hbhOOApFfozhVo,39144
@@ -243,8 +243,11 @@ adam/utils_repl/appendable_completer.py,sha256=byLO9pZXExi13i6-fKY6gNzK-v0RtxIQt
243
243
  adam/utils_repl/automata_completer.py,sha256=LJP_2WHHR7AtjX00MJ59VGQEL3t0XS-qYnDmMaZe-Tk,1641
244
244
  adam/utils_repl/repl_completer.py,sha256=Zrs3RVVP7k6zacj1pKpYpSF6LOpziEA15yIuc5Nj3_4,6544
245
245
  adam/utils_repl/state_machine.py,sha256=kO4_oSi_M53f3QQjINzzb2VFptjbnqX3KRC0G8LqqeA,5426
246
- kaqing-2.0.186.dist-info/METADATA,sha256=_75gW9xjpD0_DaYD6-_9W2LYI-U4N6QOGlc1mRU8hiY,133
247
- kaqing-2.0.186.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
248
- kaqing-2.0.186.dist-info/entry_points.txt,sha256=SkzhuQJUWsXOzHeZ5TgQ2c3_g53UGK23zzJU_JTZOZI,39
249
- kaqing-2.0.186.dist-info/top_level.txt,sha256=8_2PZkwBb-xDcnc8a2rAbQeJhXKXskc7zTP7pSPa1fw,5
250
- kaqing-2.0.186.dist-info/RECORD,,
246
+ teddy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
247
+ teddy/lark_parser.py,sha256=1ZasiCM94C0nOA4HFJX7uMj0h2TReCMqLd1Wx9C50uA,14701
248
+ teddy/lark_parser2.py,sha256=tXM6D8BimgG4FK5ANYS2K8MoATdcYed5QOKXivbPQHw,21499
249
+ kaqing-2.0.188.dist-info/METADATA,sha256=QG9vHSpDDVhqBqKybXo3hiyXNIzrBhfU_IX-Kb6ZMdI,133
250
+ kaqing-2.0.188.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
251
+ kaqing-2.0.188.dist-info/entry_points.txt,sha256=SkzhuQJUWsXOzHeZ5TgQ2c3_g53UGK23zzJU_JTZOZI,39
252
+ kaqing-2.0.188.dist-info/top_level.txt,sha256=spQlE6mz0lPv3DfQLw8FenXyU0O-P8pi_FUCjdI2H9s,11
253
+ kaqing-2.0.188.dist-info/RECORD,,
@@ -0,0 +1,2 @@
1
+ adam
2
+ teddy
teddy/__init__.py ADDED
File without changes
teddy/lark_parser.py ADDED
@@ -0,0 +1,436 @@
1
+ from copy import copy
2
+ import re
3
+ from typing import Union, cast
4
+ from lark import Lark, Token, Tree
5
+ from lark.lexer import TerminalDef
6
+ from lark.grammar import NonTerminal, Terminal
7
+
8
+ def log(msg: str = None, debug: bool = False, depth: int = 0):
9
+ if not msg:
10
+ print()
11
+ return
12
+
13
+ if debug:
14
+ print(depth * ' ' + msg)
15
+
16
+ class GNode:
17
+ def __init__(self, name: str, token: Token = None, choices: list[int] = []):
18
+ self.name = name
19
+ self.token = token
20
+ self.choices = choices
21
+
22
+ def __eq__(self, other: 'GNode'):
23
+ return self.__repr__() == other.__repr__()
24
+
25
+ def __hash__(self):
26
+ return hash(self.__repr__())
27
+
28
+ def __repr__(self):
29
+ n = self.name if self.name else f'{self.token}'
30
+ if self.choices:
31
+ n = f'{n}-{"-".join([f"{c}" for c in self.choices])}'
32
+
33
+ return n
34
+
35
+ def pname(self):
36
+ return self.name if self.name else f'{self.token}'
37
+
38
+ def choice(self, depth: int):
39
+ if depth < len(self.choices):
40
+ return self.choices[depth]
41
+
42
+ return -1
43
+
44
+ def drop_last_choice(self):
45
+ new_node = copy(self)
46
+ new_node.choices = self.choices[:-1]
47
+
48
+ return new_node
49
+
50
+ def parse(s: str):
51
+ name_n_choices = s.split('-')
52
+ choices = []
53
+ if len(name_n_choices) > 1:
54
+ choices = {int(k) for k in name_n_choices[1:]}
55
+
56
+ return GNode(name_n_choices[0], choices=choices)
57
+
58
+ def add_choice(self, choice: int):
59
+ self.choices.append(choice)
60
+
61
+ class GPath:
62
+ def __init__(self, nodes: list[GNode], complete: bool):
63
+ self.nodes = nodes
64
+ self.complete = complete
65
+
66
+ def __eq__(self, other: 'GPath'):
67
+ return self.__repr__() == other.__repr__()
68
+
69
+ def __hash__(self):
70
+ return hash(self.__repr__())
71
+
72
+ def __repr__(self):
73
+ r = '.'.join([f'{p}' for p in self.nodes])
74
+
75
+ return r
76
+
77
+ def token(self):
78
+ return self.nodes[-1] if self.nodes else GNode(None, choices={})
79
+
80
+ def append(self, node):
81
+ new_path = copy(self)
82
+ nodes = []
83
+ for n in self.nodes:
84
+ n1 = copy(n)
85
+ ss = []
86
+ for k in n.choices:
87
+ ss.append(k)
88
+ n1.choices = ss
89
+ nodes.append(n1)
90
+ nodes.append(node)
91
+ new_path.nodes = nodes
92
+
93
+ return new_path
94
+
95
+ def drop_last(self):
96
+ new_path = copy(self)
97
+ nodes = []
98
+ for n in self.nodes[:-1]:
99
+ nodes.append(n)
100
+
101
+ new_path.nodes = nodes
102
+
103
+ return new_path
104
+
105
+ def clone(self):
106
+ new_path = copy(self)
107
+ nodes = []
108
+ for n in self.nodes:
109
+ n1 = copy(n)
110
+ ss = []
111
+ for k in n.choices:
112
+ ss.append(k)
113
+ n1.choices = ss
114
+ nodes.append(n1)
115
+ new_path.nodes = nodes
116
+
117
+ return new_path
118
+
119
+ def terminal(self):
120
+ last_node = self.nodes[-1]
121
+ return last_node.pname()
122
+
123
+ def terminals(paths: set['GPath']):
124
+ return ','.join(p.terminal() for p in list(paths))
125
+
126
+ def with_new_choice(self, choice: int):
127
+ new_path = self.clone()
128
+ new_path.nodes[-1].add_choice(choice)
129
+
130
+ return new_path
131
+
132
+ def with_next_choice(self):
133
+ new_path = self.clone()
134
+ new_path.nodes[-1].choices[-1] += 1
135
+
136
+ return new_path
137
+
138
+ def drop_last_choice(self):
139
+ new_path = self.clone()
140
+ new_path.nodes[-1] = new_path.nodes[-1].drop_last_choice()
141
+
142
+ return new_path
143
+
144
+ class LarkParser:
145
+ show_returns = False
146
+
147
+ def __init__(self, grammar: str = None):
148
+ if not grammar:
149
+ grammar = """
150
+ start: expression
151
+ expression: term (("+" | "-") term)*
152
+ term: factor (("*" | "/") factor)*
153
+ factor: NUMBER | "(" expression ")"
154
+ NUMBER: /[0-9]+/
155
+ %ignore " "
156
+ """
157
+
158
+ parser = Lark(grammar, start='start')
159
+ self.parser = parser
160
+
161
+ self.rules = {rule_def[0]: rule_def[2] for rule_def in parser.grammar.rule_defs}
162
+ self.terminals = {rule_def[0]: rule_def[1] for rule_def in parser.grammar.term_defs}
163
+ self.rules_by_name1 = {rule_def[0]: rule_def[1] for rule_def in parser.grammar.rule_defs}
164
+ self.rules_by_name2 = {rule_def[0]: rule_def[3] for rule_def in parser.grammar.rule_defs}
165
+
166
+ self.trees: dict[str, Tree] = {}
167
+
168
+ def find_next_terminals(self, path: GPath, debug=False):
169
+ if path == 'start':
170
+ return self.visit_current(LarkParser.build_path(path), debug=debug)
171
+
172
+ if isinstance(path, set):
173
+ paths = set()
174
+
175
+ for p in list(path):
176
+ paths |= self.visit_next(p, debug=debug)
177
+
178
+ return paths
179
+ elif isinstance(path, str):
180
+ path = LarkParser.build_path(path)
181
+
182
+ if debug: print(f'find_next_terminals({path}, {path.token().token})')
183
+
184
+ return self.visit_next(path, debug=debug)
185
+
186
+ def visit_current(self, path: GPath, tree: Tree = None, debug=False):
187
+ paths: set[GPath] = set()
188
+
189
+ if debug: print(f'visit_expansion({path}, {path.token().token}), {path.nodes[-1].choices}')
190
+ if not tree:
191
+ tree, _ = self.tree_by_choices(path, debug=debug)
192
+
193
+ if isinstance(tree, Token):
194
+ if debug: print('token', tree)
195
+ if path.nodes[-1].token:
196
+ path = path.drop_last()
197
+
198
+ p = path.append(GNode(name=self.token_name_from_raw(f'{tree}'), token=tree, choices=[]))
199
+ if LarkParser.show_returns: print('<- ', tree.value, '\t\t', p)
200
+ paths.add(p)
201
+ elif isinstance(tree, Terminal):
202
+ if debug: print('terminal', tree.name)
203
+ p = path.append(GNode(tree.name, choices=[]))
204
+ if LarkParser.show_returns: print('<- ', tree.name, '\t\t', p)
205
+ paths.add(p)
206
+ elif isinstance(tree, NonTerminal):
207
+ if debug: print('non-termial', tree.name, tree)
208
+ paths |= self.visit_current(path.append(GNode(tree.name, choices=[])), debug=debug)
209
+ elif isinstance(tree, tuple):
210
+ paths |= self.visit_current(path, tree=tree[0], debug=debug)
211
+ elif not tree:
212
+ raise Exception(f'null tree at {path}')
213
+ elif tree.data == 'expr':
214
+ paths |= self.visit_current(path.with_new_choice(0), tree=tree.children[0], debug=debug)
215
+
216
+ if cast(Token, tree.children[1]).value in ['*', '?']:
217
+ paths |= self.visit_next(path, debug=debug)
218
+ elif tree.data == 'value':
219
+ # print('value')
220
+ for child in tree.children:
221
+ paths |= self.visit_current(path, tree=child, debug=debug)
222
+ elif tree.data == 'range':
223
+ # print('range')
224
+ token0: Token = tree.children[0]
225
+ token1: Token = tree.children[1]
226
+ if token0.value == '"0"' and token1.value == '"9"':
227
+ p = path.append(GNode(name=self.token_name_from_raw(f'{token0}'), token=token0, choices=[]))
228
+ if LarkParser.show_returns: print('<- ', 0, '\t\t', p)
229
+ paths.add(p)
230
+ else:
231
+ raise Exception('not implented')
232
+ for i in range(ord(token0.value.strip('"')), ord(token1.value.strip('"')) + 1):
233
+ ch = chr(i)
234
+ p = path.append(GNode(name=self.token_name_from_raw(f'{token0}'), token=token0, choices=[]))
235
+ # p = path.append(GNode(name=self.token_name_from_raw(f'{tree}'), token=tree, choices=[]))
236
+ if LarkParser.show_returns: print('<- ', ch, '\t\t', p)
237
+ paths.add(p)
238
+ elif tree.data == 'literal':
239
+ # print('literal')
240
+ for child in tree.children:
241
+ paths |= self.visit_current(path, tree=child, debug=debug)
242
+ elif tree.data == 'expansions':
243
+ for i, child in enumerate(tree.children):
244
+ paths |= self.visit_current(path.with_new_choice(i), tree=child, debug=debug)
245
+ elif tree.data == 'expansion':
246
+ paths |= self.visit_current(path.with_new_choice(0), tree=tree.children[0], debug=debug)
247
+
248
+ return paths
249
+
250
+ def visit_next(self, path: GPath, debug=False):
251
+ paths: set[GPath] = set()
252
+
253
+ if not path.nodes:
254
+ return paths
255
+
256
+ path = self.strip_terminal_nodes(path)
257
+ node = path.nodes[-1]
258
+
259
+ me: Tree
260
+ parent: Tree
261
+ me, parent = self.tree_by_choices(path)
262
+
263
+ check_parent = True
264
+ if isinstance(me, Tree) and me.data == 'expr' and me.children[1] == '*':
265
+ if debug: print(' add expr repeat ', path)
266
+ paths |= self.visit_current(path.with_new_choice(0), debug=debug)
267
+
268
+ if isinstance(parent, Tree) and parent.data == 'expansion' and (node.choices[-1] + 1) < len(parent.children):
269
+ np = path.with_next_choice()
270
+ if debug: print(' move to next sibling ', np)
271
+ paths |= self.visit_current(np, debug=debug)
272
+ check_parent = False
273
+
274
+ if check_parent:
275
+ if len(node.choices) > 0:
276
+ p = path.drop_last_choice()
277
+ if debug: print(' move up to parent tree', p)
278
+ paths |= self.visit_next(p, debug=debug)
279
+ else:
280
+ path = path.drop_last()
281
+ if debug: print(' move up to parent node', path)
282
+ paths |= self.visit_next(path, debug=debug)
283
+
284
+ return paths
285
+
286
+ def tree_by_choices(self, path: GPath, debug=False):
287
+ debug = False
288
+
289
+ c = f'{path.nodes[-1]}'
290
+ p = f'{path.nodes[-1].drop_last_choice()}'
291
+ if c not in self.trees:
292
+ for key, value in self.trees_by_choices(path, debug=debug).items():
293
+ if not key:
294
+ self.trees[f'{path.token().name}'] = value
295
+ else:
296
+ self.trees[f'{path.token().name}-{key}'] = value
297
+
298
+ return self.trees[c], self.trees[p]
299
+
300
+ def trees_by_choices(self, path_or_tree: Union[GPath, Tree], choices: list[int] = [], depth: int = 0, debug=False):
301
+ if debug: print(f'trees_by_choices({path_or_tree}, {choices})')
302
+
303
+ if isinstance(path_or_tree, GPath):
304
+ n = self.find_last_rule(path_or_tree)
305
+ tree = self.rules[n.name]
306
+ else:
307
+ tree = path_or_tree
308
+
309
+ trees: dict[str, Tree] = {}
310
+
311
+ if isinstance(tree, Token):
312
+ if debug: log('tree', debug, depth)
313
+ pass
314
+ elif isinstance(tree, Terminal):
315
+ if debug: log('terminal', debug, depth)
316
+
317
+ choices_str = '-'.join([f"{c}" for c in choices])
318
+ trees[choices_str] = tree
319
+
320
+ pass
321
+ elif isinstance(tree, NonTerminal):
322
+ if debug: log('non-terminal', debug, depth)
323
+ pass
324
+ elif isinstance(tree, tuple):
325
+ if debug: log('tuple', debug, depth)
326
+ trees |= self.trees_by_choices(tree[0], choices, depth=depth, debug=debug)
327
+ elif tree.data == 'expr':
328
+ if debug: log('expr', debug, depth)
329
+ choices_str = '-'.join([f"{c}" for c in choices])
330
+ trees[choices_str] = tree
331
+
332
+ for child in tree.children[:1]:
333
+ trees |= self.trees_by_choices(child, choices + [0], depth=depth+1, debug=debug)
334
+ elif tree.data == 'value':
335
+ if debug: log('value', debug, depth)
336
+
337
+ choices_str = '-'.join([f"{c}" for c in choices])
338
+ trees[choices_str] = tree
339
+
340
+ for child in tree.children:
341
+ trees |= self.trees_by_choices(child, choices, depth=depth+1, debug=debug)
342
+ elif tree.data == 'literal':
343
+ if debug: log('literal', debug, depth)
344
+
345
+ choices_str = '-'.join([f"{c}" for c in choices])
346
+ trees[choices_str] = tree
347
+
348
+ for child in tree.children:
349
+ trees |= self.trees_by_choices(child, choices, depth=depth+1, debug=debug)
350
+ elif tree.data == 'expansions':
351
+ if debug: log('expansions', debug, depth)
352
+
353
+ choices_str = '-'.join([f"{c}" for c in choices])
354
+ trees[choices_str] = tree
355
+ for i, child in enumerate(tree.children):
356
+ trees |= self.trees_by_choices(child, choices + [i], depth=depth+1, debug=debug)
357
+ elif tree.data == 'expansion':
358
+ if debug: log('expansion', debug, depth)
359
+
360
+ choices_str = '-'.join([f"{c}" for c in choices])
361
+ trees[choices_str] = tree
362
+ for i, child in enumerate(tree.children):
363
+ trees |= self.trees_by_choices(child, choices + [i], depth=depth+1, debug=debug)
364
+ else:
365
+ if debug: log('else', debug, depth)
366
+
367
+ return trees
368
+
369
+ def strip_terminal_nodes(self, path: GPath):
370
+ while path.nodes[-1].name not in self.rules:
371
+ path = path.drop_last()
372
+
373
+ return path
374
+
375
+ def find_last_rule(self, path: GPath):
376
+ for n in reversed(path.nodes):
377
+ if n.name in self.rules:
378
+ return n
379
+
380
+ return None
381
+
382
+ def build_path(p: str):
383
+ nodes = []
384
+ for n in p.split('.'):
385
+ name_n_choices = n.split('-')
386
+ nodes.append(GNode(name_n_choices[0], choices=[int(c) for c in name_n_choices[1:]]))
387
+
388
+ return GPath(nodes, False)
389
+
390
+ def token_name(self, token):
391
+ td: TerminalDef = None
392
+ for t in reversed(self.parser.terminals):
393
+ td = t
394
+ # print(td)
395
+ if td.pattern.raw == '/./':
396
+ if token == '.':
397
+ return td.name
398
+ elif re.fullmatch(td.pattern.to_regexp(), token):
399
+ return td.name
400
+
401
+ raise Exception('cannot resolve string to a token')
402
+
403
+ def token_name_from_raw(self, raw_token):
404
+ td: TerminalDef = None
405
+ for t in reversed(self.parser.terminals):
406
+ if t.pattern.raw == raw_token:
407
+ td = t
408
+ return td.name
409
+
410
+ return self.token_name(raw_token.strip('"'))
411
+
412
+ def parse(self, s: str, debug=False):
413
+ ps = 'start'
414
+ ps = self.find_next_terminals(ps, debug=debug)
415
+
416
+ for token in self.parser.lex(s):
417
+ token_name = self.token_name(token)
418
+
419
+ ps = self.choose(ps, token_name)
420
+ ps = self.find_next_terminals(ps, debug=debug)
421
+
422
+ terminals = {p.terminal().strip('"') for p in ps}
423
+
424
+ # print(terminals)
425
+
426
+ return terminals
427
+
428
+ def choose(self, paths: list[GPath], token: str):
429
+ if LarkParser.show_returns: print(f'\n{token}\t-----------------------------')
430
+
431
+ ps = set()
432
+ for p in paths:
433
+ if f'{p.token()}' == token:
434
+ ps.add(p)
435
+
436
+ return ps
teddy/lark_parser2.py ADDED
@@ -0,0 +1,618 @@
1
+ from copy import copy
2
+ from typing import Union
3
+ import unittest
4
+ from lark import Lark, Token, Tree
5
+ from lark.grammar import NonTerminal, Terminal
6
+
7
+ class GNode:
8
+ def __init__(self, name: str, token: Token = None, choices: dict[int, int] = {}):
9
+ self.name = name
10
+ self.token = token
11
+ self.choices = choices
12
+
13
+ def __eq__(self, other: 'GNode'):
14
+ return self.__repr__() == other.__repr__()
15
+
16
+ def __hash__(self):
17
+ return hash(self.__repr__())
18
+
19
+ def __repr__(self):
20
+ n = self.name if self.name else f'{self.token}'
21
+ if self.choices:
22
+ # print(self.choices, self.choices_to_list())
23
+ choices = self.choices_to_list()
24
+ n = f'{n}-{"-".join([f"{c}" for c in choices])}'
25
+
26
+ return n
27
+
28
+ def pname(self):
29
+ return self.name if self.name else f'{self.token}'
30
+
31
+ def choice(self, depth: int):
32
+ if depth in self.choices:
33
+ return self.choices[depth]
34
+
35
+ return -1
36
+
37
+ def set_choice(self, depth: int, choice: int):
38
+ self.choices[depth] = choice
39
+
40
+ def choices_to_list(self):
41
+ choices = []
42
+
43
+ if self.choices:
44
+ for i in range(0, max(self.choices.keys()) + 1):
45
+ if i in self.choices:
46
+ choices.append(self.choices[i])
47
+ else:
48
+ choices.append(0)
49
+
50
+ return choices
51
+
52
+ def choice_list_to_str(self):
53
+ return '-'.join([f'{c}' for c in self.choices_to_list()[:-1]])
54
+
55
+ def choice_list_to_dict(self, choices: list[int]):
56
+ return {i: c for i, c in enumerate(choices)}
57
+
58
+ def drop_last(self):
59
+ new_node = copy(self)
60
+ choices = self.choices_to_list()[:-1]
61
+ new_node.choices = self.choice_list_to_dict(choices)
62
+
63
+ return new_node
64
+
65
+ class GPath:
66
+ def __init__(self, nodes: list[GNode], complete: bool, trail: list[str] = []):
67
+ self.nodes = nodes
68
+ self.complete = complete
69
+ self.trail = trail
70
+
71
+ def __eq__(self, other: 'GPath'):
72
+ return self.__repr__() == other.__repr__()
73
+
74
+ def __hash__(self):
75
+ return hash(self.__repr__())
76
+
77
+ def __repr__(self):
78
+ return '.'.join([f'{p}' for p in self.nodes])
79
+
80
+ def token(self):
81
+ return self.nodes[-1]
82
+
83
+ def append(self, node):
84
+ new_path = copy(self)
85
+ nodes = []
86
+ for n in self.nodes:
87
+ n1 = copy(n)
88
+ ss = {}
89
+ for k, v in n.choices.items():
90
+ ss[k] = v
91
+ n1.choices = ss
92
+ nodes.append(n1)
93
+ nodes.append(node)
94
+ new_path.nodes = nodes
95
+
96
+ return new_path
97
+
98
+ def drop_last(self):
99
+ new_path = copy(self)
100
+ nodes = []
101
+ for n in self.nodes[:-1]:
102
+ nodes.append(n)
103
+ new_path.nodes = nodes
104
+
105
+ return new_path
106
+
107
+ def clone(self):
108
+ new_path = copy(self)
109
+ nodes = []
110
+ for n in self.nodes:
111
+ n1 = copy(n)
112
+ ss = {}
113
+ for k, v in n.choices.items():
114
+ ss[k] = v
115
+ n1.choices = ss
116
+ nodes.append(n1)
117
+ new_path.nodes = nodes
118
+
119
+ return new_path
120
+
121
+ def terminal(self):
122
+ last_node = self.nodes[-1]
123
+ # print('SEAN', last_node.token.data)
124
+ return last_node.pname()
125
+
126
+ def terminals(paths: set['GPath']):
127
+ return ','.join(p.terminal() for p in list(paths))
128
+
129
+ class CompletePath:
130
+ def __init__(self, path: GPath, complete: False):
131
+ self.path = path
132
+ self.complete = complete
133
+
134
+ class SeqOrUnion:
135
+ def __init__(self, collection: list, is_seq: bool):
136
+ self.collection = collection
137
+ self.is_seq = is_seq
138
+
139
+ class LarkParser:
140
+ def __init__(self):
141
+ grammar = """
142
+ start: expression
143
+ expression: term (("+" | "-") term)*
144
+ term: factor (("*" | "/") factor)*
145
+ factor: NUMBER | "(" expression ")"
146
+ NUMBER: /[0-9]+/
147
+ %ignore " "
148
+ """
149
+
150
+ parser = Lark(grammar, start='start')
151
+
152
+ # print('TEST parsing', parser.parse('(56)'))
153
+
154
+ # print(parser.grammar.term_defs)
155
+
156
+ for rule in parser.grammar.rule_defs + parser.grammar.term_defs:
157
+ lhv = rule[0]
158
+ # print(f'{lhv} :=')
159
+ # print(rule[1])
160
+ if len(rule) > 2:
161
+ tree = rule[2]
162
+ # print(f'{tree.pretty()}')
163
+ # print(rule[3])
164
+
165
+ self.rules = {rule_def[0]: rule_def[2] for rule_def in parser.grammar.rule_defs}
166
+ self.terminals = {rule_def[0]: rule_def[1] for rule_def in parser.grammar.term_defs}
167
+ self.rules_by_name1 = {rule_def[0]: rule_def[1] for rule_def in parser.grammar.rule_defs}
168
+ self.rules_by_name2 = {rule_def[0]: rule_def[3] for rule_def in parser.grammar.rule_defs}
169
+
170
+ def children_by_choices(self, tree: Tree, choices: list[int] = [], depth: int = 0):
171
+ children: dict[str, SeqOrUnion] = {}
172
+
173
+ if isinstance(tree, Token):
174
+ pass
175
+ elif isinstance(tree, Terminal):
176
+ pass
177
+ elif isinstance(tree, NonTerminal):
178
+ pass
179
+ elif isinstance(tree, tuple):
180
+ children |= self.children_by_choices(tree[0], choices, depth=depth)
181
+ elif tree.data == 'expr':
182
+ for child in tree.children[:1]:
183
+ children |= self.children_by_choices(child, choices, depth=depth)
184
+ # complete = False
185
+ elif tree.data == 'value':
186
+ # print('value')
187
+ for child in tree.children:
188
+ children |= self.children_by_choices(child, choices, depth=depth)
189
+ elif tree.data == 'literal':
190
+ # print('literal')
191
+ for child in tree.children:
192
+ children |= self.children_by_choices(child, choices, depth=depth)
193
+ elif tree.data == 'expansions':
194
+ # print('expansions')
195
+ # print(tree.pretty())
196
+ choices_str = '-'.join([f"{c}" for c in choices])
197
+ children[choices_str] = SeqOrUnion(tree.children, False)
198
+ # print(f'children_by_choices[{choices_str}] = {len(tree.children)}')
199
+ for i, child in enumerate(tree.children):
200
+ children |= self.children_by_choices(child, choices + [i], depth=depth+1)
201
+ elif tree.data == 'expansion':
202
+ # print('expansion')
203
+ # print(tree.pretty())
204
+ choices_str = '-'.join([f"{c}" for c in choices])
205
+ children[choices_str] = SeqOrUnion(tree.children, True)
206
+ # print(f'children_by_choices[{choices_str}] = {len(tree.children)}')
207
+ for i, child in enumerate(tree.children):
208
+ children |= self.children_by_choices(child, choices + [i], depth=depth+1)
209
+
210
+ return children
211
+
212
+ def find_next_terminals(self, path: GPath, debug=False):
213
+ if path == 'start':
214
+ return self.find_terminals(path, debug=debug)
215
+
216
+ if isinstance(path, set):
217
+ paths = set()
218
+
219
+ for p in list(path):
220
+ paths |= self.find_next_terminals(p, debug=debug)
221
+
222
+ return paths
223
+ elif isinstance(path, str):
224
+ path = LarkParser.build_path(path)
225
+
226
+ terminals = self.find_terminals(path, debug=debug)
227
+
228
+ next_terminals = set()
229
+
230
+ for t in terminals:
231
+ paths = self.find_next(t)
232
+ for path in paths:
233
+ terms = self.find_terminals(path, debug=debug)
234
+ for term in terms:
235
+ term.trail.append(term.terminal())
236
+ next_terminals |= terms
237
+
238
+ return next_terminals
239
+
240
+ def _find_next_terminals(self, path: GPath, debug=False):
241
+ # terminals = self.find_terminals(path)
242
+
243
+ if isinstance(path, str):
244
+ path = LarkParser.build_path(path)
245
+
246
+ next_terminals = set()
247
+
248
+ # for t in terminals:
249
+ paths = self.find_next(path)
250
+ for path in paths:
251
+ next_terminals |= self.find_terminals(path, debug=debug)
252
+
253
+ return next_terminals
254
+
255
+ def find_next(self, path: GPath, depth: int = -1, debug=False):
256
+ paths: set[GPath] = set()
257
+
258
+ if not path.nodes:
259
+ return paths
260
+
261
+ if depth == -1:
262
+ if debug: print('find_next', path)
263
+
264
+ node = path.nodes[-1]
265
+ if node.name in self.rules:
266
+ tree = self.rules[node.name]
267
+ elif node.name in self.terminals:
268
+ tree = self.terminals[node.name]
269
+ else:
270
+ tree = node.token
271
+
272
+ choices = node.choices_to_list()
273
+ children = self.children_by_choices(tree)
274
+ # print('children', children)
275
+
276
+ if depth == -1:
277
+ depth = len(choices) - 1
278
+
279
+ # print(depth, len(choices), len(children[node.choice_list_to_str()]))
280
+ # print(len(choices), len(children))
281
+ check_parent = True
282
+ if children and children[node.choice_list_to_str()].is_seq and choices[depth] + 1 < len(children[node.choice_list_to_str()].collection):
283
+ node.choices[depth] += 1
284
+ if debug: print(' move to next sibling ', path)
285
+ # print('paths', path.nodes[-1] )
286
+ paths.add(path.clone())
287
+ check_parent = False
288
+
289
+ next_sibing = children[node.choice_list_to_str()].collection[node.choices[depth]]
290
+ if next_sibing.data == 'expr':
291
+ paths |= self.find_next(path, depth, debug=debug)
292
+ check_parent = True
293
+
294
+ # print('next_sibling', next_sibing)
295
+
296
+ if check_parent:
297
+ if depth > 0:
298
+ new_node = node.drop_last()
299
+ path.nodes[-1] = new_node
300
+ if debug: print(' move up to parent tree', new_node)
301
+ depth -= 1
302
+ paths |= self.find_next(path, depth, debug=debug)
303
+ else:
304
+ path = path.drop_last()
305
+ if debug: print(' move up to parent node', path)
306
+ paths |= self.find_next(path, -1, debug=debug)
307
+
308
+ return paths
309
+
310
+ def find_terminals(self, path: GPath, paths: set[GPath] = set(), path_history: set[GNode] = set(), debug=False):
311
+ if isinstance(path, str):
312
+ path = LarkParser.build_path(path)
313
+
314
+ if debug: print('find_terminals', path)
315
+
316
+ path_history.add(path.nodes[-1])
317
+
318
+ paths = self._find_terminals(None, path, debug=debug)
319
+
320
+ new_paths = set()
321
+ for p in paths:
322
+ node = p.nodes[-1]
323
+ if node.token:
324
+ # print('found terminal node', node)
325
+ new_paths.add(p)
326
+ else:
327
+ new_paths |= self.find_terminals(p, paths, path_history, debug=debug)
328
+
329
+ return new_paths
330
+
331
+ def _find_terminals(self, tree: Tree, path: GPath, depth = 0, debug=False):
332
+ paths: set[GPath] = set()
333
+ # complete = False
334
+
335
+ node = path.nodes[-1]
336
+ if not tree:
337
+ if node.name in self.rules:
338
+ tree = self.rules[node.name]
339
+ elif node.name in self.terminals:
340
+ tree = self.terminals[node.name]
341
+ else:
342
+ tree = node.token
343
+
344
+ # print(tree)
345
+
346
+ if isinstance(tree, Token):
347
+ p = path.append(GNode(name=None, token=tree))
348
+ print('<- ', tree.value, '\t\t', p)
349
+ paths.add(p)
350
+ elif isinstance(tree, Terminal):
351
+ paths.add(path.append(GNode(tree.name)))
352
+ elif isinstance(tree, NonTerminal):
353
+ # print('non-termial', tree.name)
354
+ paths.add(path.append(GNode(tree.name)))
355
+ elif isinstance(tree, tuple):
356
+ paths |= self._find_terminals(tree[0], path, depth=depth)
357
+ elif tree.data == 'expr':
358
+ # print('expr')
359
+ for child in tree.children[:1]:
360
+ paths |= self._find_terminals(child, path, depth=depth)
361
+ elif tree.data == 'value':
362
+ # print('value')
363
+ for child in tree.children:
364
+ paths |= self._find_terminals(child, path, depth=depth)
365
+ elif tree.data == 'literal':
366
+ # print('literal')
367
+ for child in tree.children:
368
+ paths |= self._find_terminals(child, path, depth=depth)
369
+ elif tree.data == 'expansions':
370
+ if node.choice(depth) == -1:
371
+ for i, child in enumerate(tree.children):
372
+ p = path.clone()
373
+ node = p.nodes[-1]
374
+ node.set_choice(depth, i)
375
+ paths |= self._find_terminals(child, p, depth=depth+1)
376
+ else:
377
+ # node.set_choice(depth, node.choice(depth))
378
+ paths |= self._find_terminals(tree.children[node.choice(depth)], path, depth=depth+1)
379
+ elif tree.data == 'expansion':
380
+ # print('expansion', path)
381
+ if (choice := node.choice(depth)) == -1:
382
+ choice = 0
383
+
384
+ node.set_choice(depth, choice)
385
+ paths |= self._find_terminals(tree.children[choice], path, depth=depth+1)
386
+
387
+ return paths
388
+
389
+ def visit(self, path: GPath, paths: set[GPath] = set(), path_history: set[GNode] = set(), next = False):
390
+ if isinstance(path, str):
391
+ print('visit', path)
392
+ path = LarkParser.build_path(path)
393
+
394
+ # print('visit', path)
395
+ if path.nodes[-1] in path_history:
396
+ return paths
397
+
398
+ path_history.add(path.nodes[-1])
399
+
400
+ paths = self.visit_tree(None, path, next=next)
401
+
402
+ new_paths = set()
403
+ for p in paths:
404
+ node = p.nodes[-1]
405
+ if node.token:
406
+ # print('found terminal node', node)
407
+ new_paths.add(p)
408
+ else:
409
+ new_paths |= self.visit(p, paths, path_history, next=False)
410
+
411
+ return new_paths
412
+
413
+ def visit_tree(self, tree: Tree, path: GPath, depth = 0, next = False):
414
+ paths: set[GPath] = set()
415
+ # complete = False
416
+
417
+ node = path.nodes[-1]
418
+ if not tree:
419
+ if node.name in self.rules:
420
+ tree = self.rules[node.name]
421
+ elif node.name in self.terminals:
422
+ tree = self.terminals[node.name]
423
+ else:
424
+ tree = node.token
425
+
426
+ # print(tree)
427
+
428
+ if isinstance(tree, Token):
429
+ p = path.append(GNode(name=None, token=tree))
430
+ print('<- ', tree.value, '\t\t', p)
431
+ paths.add(p)
432
+ elif isinstance(tree, Terminal):
433
+ paths.add(path.append(GNode(tree.name)))
434
+ elif isinstance(tree, NonTerminal):
435
+ # print('non-termial', tree.name)
436
+ paths.add(path.append(GNode(tree.name)))
437
+ elif isinstance(tree, tuple):
438
+ paths |= self.visit_tree(tree[0], path, depth=depth)
439
+ elif tree.data == 'expr':
440
+ # print('SEAN expr', tree.data, tree.children[1])
441
+ # print('expr add extra', path)
442
+ # paths.add(path)
443
+ for child in tree.children[:1]:
444
+ paths |= self.visit_tree(child, path, depth=depth)
445
+ # complete = False
446
+ elif tree.data == 'value':
447
+ # print('value')
448
+ for child in tree.children:
449
+ paths |= self.visit_tree(child, path, depth=depth)
450
+ elif tree.data == 'literal':
451
+ # print('literal')
452
+ for child in tree.children:
453
+ paths |= self.visit_tree(child, path, depth=depth)
454
+ elif tree.data == 'expansions':
455
+ # print('expansions', path)
456
+ if next:
457
+ paths |= self.visit_tree(tree.children[node.choice(depth)], path, depth=depth+1)
458
+ else:
459
+ for i, child in enumerate(tree.children):
460
+ node.set_choice(depth, i)
461
+ paths |= self.visit_tree(child, path, depth=depth+1)
462
+ elif tree.data == 'expansion':
463
+ # print('expansion', path)
464
+ if (choice := node.choice(depth)) == -1:
465
+ choice = 0
466
+
467
+ node.set_choice(depth, choice)
468
+ paths |= self.visit_tree(tree.children[choice], path, depth=depth+1)
469
+
470
+ return paths
471
+
472
+ def _find_next(self, path: GPath, paths: set[GPath] = set(), path_history: set[GNode] = set()):
473
+ if isinstance(path, str):
474
+ print('visit_next', path)
475
+ path = LarkParser.build_path(path)
476
+
477
+ # print('visit', path)
478
+ paths: set[GPath] = set()
479
+
480
+ for i in reversed(range(1, len(path.nodes) + 1)):
481
+ path = GPath(path.nodes[:i], False)
482
+ print('testing path', path)
483
+
484
+ complete = False
485
+ next = self.find_tree_next(None, path)
486
+ if next:
487
+ for n in next:
488
+ print('visiting with next', n)
489
+ paths |= self.visit(n, paths, set(), next=True)
490
+ if n.complete:
491
+ complete = True
492
+ else:
493
+ pass
494
+ # print('SEAN not complete', n)
495
+ # if not complete:
496
+ # break
497
+ # if next.complete:
498
+ # print('SEAN complete', next.complete)
499
+ # continue
500
+ if next and not complete:
501
+ break
502
+
503
+ # else:
504
+ # break
505
+
506
+ return paths
507
+
508
+ def find_tree_next(self, tree: Tree, path: GPath, depth = 0):
509
+ print('find_tree_next', path, depth)
510
+ paths: set[GPath] = set()
511
+ # complete = False
512
+
513
+ node = path.nodes[-1]
514
+ if not tree:
515
+ if node.name in self.rules:
516
+ tree = self.rules[node.name]
517
+ elif node.name in self.terminals:
518
+ tree = self.terminals[node.name]
519
+ else:
520
+ tree = node.token
521
+
522
+ if isinstance(tree, Token):
523
+ path.complete = True
524
+ pass
525
+ # print('token found', tree.value)
526
+ elif isinstance(tree, Terminal):
527
+ path.complete = True
528
+ pass
529
+ # paths.add(path.append(GNode(tree.name)))
530
+ elif isinstance(tree, NonTerminal):
531
+ pass
532
+ # print('non-termial', tree.name)
533
+ # paths.add(path.append(GNode(tree.name)))
534
+ elif isinstance(tree, tuple):
535
+ paths |= self.find_tree_next(tree[0], path, depth=depth)
536
+ elif tree.data == 'expr':
537
+ print(" " * depth, 'expr')
538
+ paths.add(path)
539
+ for child in tree.children[:1]:
540
+ paths |= self.find_tree_next(child, path, depth=depth)
541
+ # complete = False
542
+ elif tree.data == 'value':
543
+ print(" " * depth, 'value')
544
+ for child in tree.children:
545
+ paths |= self.find_tree_next(child, path, depth=depth)
546
+ elif tree.data == 'literal':
547
+ print(" " * depth, 'literal')
548
+ for child in tree.children:
549
+ paths |= self.find_tree_next(child, path, depth=depth)
550
+ elif tree.data == 'expansions':
551
+ print(" " * depth, 'expansions')
552
+ child = tree.children[node.choice(depth)]
553
+ path = self.find_tree_next(child, path, depth=depth+1)
554
+ if node.choices[depth] + 1 < len(tree.children):
555
+ node.choices[depth] += 1
556
+
557
+ paths |= path
558
+
559
+ # for i, child in enumerate(tree.children):
560
+ # # self.set_next_choice(path.nodes[-1], depth)
561
+ # paths |= self.visit_tree_next(child, rules, terminals, path, depth=depth+1)
562
+ elif tree.data == 'expansion':
563
+ print(" " * depth, 'expansion')
564
+ child = tree.children[node.choice(depth)]
565
+ if depth < len(node.choices) -1:
566
+ path = self.find_tree_next(child, path, depth=depth+1)
567
+ if node.choices[depth] + 1 < len(tree.children):
568
+ node.choices[depth] += 1
569
+
570
+ paths |= path
571
+ # else:
572
+ # if len(tree.children) > node.choices[depth] + 1:
573
+ # node.choices[depth] += 1
574
+ # if tree.children[node.choices[depth]].data == 'expr':
575
+ # print('SEAN expr')
576
+ # # np = path.drop_last()
577
+ # # print('SEAN next choice', np)
578
+ # # paths.add(np)
579
+ # path.complete = True
580
+ # paths.add(path)
581
+
582
+ # # self.set_next_choice(node, depth)
583
+ # paths.add(path)
584
+
585
+
586
+ # print(" " * depth, 'expansion', path)
587
+ # print('SEAN expansion', tree.pretty())
588
+ # if len(tree.children) > node.choices[depth] + 1:
589
+ # # print('next child found', tree.children, depth)
590
+
591
+ # node.choices[depth] += 1
592
+ # if tree.children[node.choices[depth]].data == 'expr':
593
+ # print('SEAN expr')
594
+ # # np = path.drop_last()
595
+ # # print('SEAN next choice', np)
596
+ # # paths.add(np)
597
+ # path.complete = True
598
+ # paths.add(path)
599
+
600
+ # # self.set_next_choice(node, depth)
601
+ # paths.add(path)
602
+
603
+ # # print('SEAN returning', path)
604
+
605
+ # return paths
606
+ # else:
607
+ # path.complete = True
608
+
609
+ # print('returning', paths)
610
+ return paths
611
+
612
+ def build_path(p: str):
613
+ nodes = []
614
+ for n in p.split('.'):
615
+ name_n_choices = n.split('-')
616
+ nodes.append(GNode(name_n_choices[0], choices={int(k): int(v) for k, v in enumerate(name_n_choices[1:])}))
617
+
618
+ return GPath(nodes, False)
@@ -1 +0,0 @@
1
- adam