sliderule-cli 5.6.1__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.
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.4
2
+ Name: sliderule-cli
3
+ Version: 5.6.1
4
+ Summary: SlideRule Command Line Tool
5
+ License-Expression: BSD-3-Clause
6
+ Requires-Python: >=3.9
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: sliderule
10
+ Requires-Dist: boto3
11
+ Provides-Extra: progress
12
+ Requires-Dist: tqdm; extra == "progress"
13
+ Provides-Extra: recorder
14
+ Requires-Dist: geoip2; extra == "recorder"
15
+ Requires-Dist: pillow; extra == "recorder"
16
+ Requires-Dist: matplotlib; extra == "recorder"
17
+ Dynamic: license-file
18
+
19
+ # sliderule-cli
20
+
21
+ The SlideRule Command Line Tool
@@ -0,0 +1,16 @@
1
+ sliderule_cli-5.6.1.dist-info/licenses/LICENSE,sha256=119rmm_x_XICR1bLzv5ISXhCTfJ1GADdw145fZ3kbM0,1524
2
+ sliderule_cluster/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ sliderule_cluster/main.py,sha256=89DoY7nhYd36Vmach6jlHNQOK8o9rJ70_t5n6P5ww18,8435
4
+ sliderule_provisioner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ sliderule_provisioner/main.py,sha256=jDg2I1gVM98kITdNDjQQA1h9GzkuuiNLzBeIT6Fn6H4,6179
6
+ sliderule_recorder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ sliderule_recorder/environment.yml,sha256=NrjKVuDD16mc1Kzizl6nerai1k6Bu9fcL3aEhYogbDQ,175
8
+ sliderule_recorder/main.py,sha256=eaJpevchj8HZjbuAQcD0lTZRhHvKLjxdOkrMEqu2fno,23139
9
+ sliderule_runner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ sliderule_runner/database.py,sha256=z6OwXbJQlhHzj_E7sa1R6yKkIBvIHpnuf9FUAz1NCr4,2953
11
+ sliderule_runner/main.py,sha256=b70PcgYwCNSw-1KL4jqcFkmsCzM1J3kYbCP0791Wb8k,11550
12
+ sliderule_cli-5.6.1.dist-info/METADATA,sha256=cEwsg952ADP-tvEy7fzoNe-qyfjXVS7PKVUdjro03Gg,554
13
+ sliderule_cli-5.6.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
14
+ sliderule_cli-5.6.1.dist-info/entry_points.txt,sha256=qA4WQESkLLqYTxo6bhooVBXcXFk-6pfl3gIs7yDlCW8,218
15
+ sliderule_cli-5.6.1.dist-info/top_level.txt,sha256=uGQrdicJQc2qDd2pOcTS5DX0rcp-IwiCI0EtEiiaRKw,76
16
+ sliderule_cli-5.6.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,5 @@
1
+ [console_scripts]
2
+ sliderule-cluster = sliderule_cluster.main:main
3
+ sliderule-provisioner = sliderule_provisioner.main:main
4
+ sliderule-recorder = sliderule_recorder.main:main
5
+ sliderule-runner = sliderule_runner.main:main
@@ -0,0 +1,12 @@
1
+ Copyright (c) 2021, University of Washington.
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
+
6
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7
+
8
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9
+
10
+ 3. Neither the name of the University of Washington nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY OF WASHINGTON AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OF WASHINGTON OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,4 @@
1
+ sliderule_cluster
2
+ sliderule_provisioner
3
+ sliderule_recorder
4
+ sliderule_runner
File without changes
@@ -0,0 +1,194 @@
1
+ import json
2
+ import uuid
3
+ import tempfile
4
+ import argparse
5
+ from pathlib import Path
6
+ from sliderule import sliderule
7
+
8
+ #########################################
9
+ # Tool
10
+ #########################################
11
+
12
+ class Tool:
13
+
14
+ # constructor
15
+ def __init__(self, args):
16
+ self.args = args
17
+ self.session = sliderule.create_session(domain=args.domain, cluster=args.cluster, user_service=args.user_service, verbose=args.verbose)
18
+
19
+ # display_result
20
+ def __display_result(self, result, reformat=False):
21
+ if reformat:
22
+ result = json.dumps(result, indent=2)
23
+ print(f'{self.args.cluster}.{self.args.domain} [{self.session.service}]: {result}')
24
+
25
+ # get_parms
26
+ def __get_parms(self, parms=None):
27
+ if self.args.parms:
28
+ with open(self.args.parms, "r") as file:
29
+ parms = json.load(file) # override
30
+ return parms
31
+
32
+ # get_poly
33
+ def __get_poly(self):
34
+ if self.args.poly:
35
+ return sliderule.toregion(self.args.poly)["poly"]
36
+ elif self.args.geojson:
37
+ return sliderule.toregion(self.args.geojson)["poly"]
38
+ elif self.args.bbox:
39
+ return sliderule.toregion(self.args.bbox)["poly"]
40
+ else:
41
+ return None
42
+
43
+ # whoami
44
+ def whoami(self):
45
+ rsps = self.session.source("whoami", parm={}, path="/discovery", retries=0, rethrow=True)
46
+ result = json.dumps(rsps)
47
+ self.__display_result(result)
48
+ return result
49
+
50
+ # status
51
+ def status(self):
52
+ if self.session.service != self.session.PUBLIC_CLUSTER:
53
+ parm = {"service":self.session.service}
54
+ else:
55
+ parm = {}
56
+ rsps = self.session.source("status", parm=parm, path="/discovery", retries=0, rethrow=True)
57
+ result = json.dumps(rsps)
58
+ self.__display_result(result)
59
+ return result
60
+
61
+ # version
62
+ def version(self):
63
+ result = sliderule.get_version(session=self.session)
64
+ self.__display_result(result, reformat=True)
65
+ return result
66
+
67
+ # defaults
68
+ def defaults(self):
69
+ result = sliderule.source("defaults", session=self.session)
70
+ self.__display_result(result, reformat=True)
71
+ return result
72
+
73
+ # earthdata
74
+ def earthdata(self):
75
+ parms = self.__get_parms({ k: v for k, v in {
76
+ "asset": self.args.asset,
77
+ "short_name": self.args.short_name,
78
+ "poly": self.__get_poly(),
79
+ "t0": self.args.t0,
80
+ "t1": self.args.t1,
81
+ "with_meta": self.args.with_meta,
82
+ "name_filter": self.args.name_filter,
83
+ "max_resources": self.args.max_resources
84
+ }.items() if v is not None })
85
+ result = sliderule.source("earthdata", parms, rethrow=True, session=self.session)
86
+ self.__display_result(result, reformat=True)
87
+ return result
88
+
89
+ # run
90
+ def run(self):
91
+ # get request parameters
92
+ if self.args.parms.startswith('"') or self.args.parms.startswith('{'):
93
+ parms = self.args.parms
94
+ else:
95
+ parms = self.__get_parms()
96
+ # build output parameters (if not supplied in request)
97
+ if "output" not in parms:
98
+ output_format = "geoparquet"
99
+ output_path = str(Path(tempfile.gettempdir()) / f"{uuid.uuid4()}.{output_format}")
100
+ parms |= {
101
+ "output": {
102
+ "path": output_path,
103
+ "format": output_format
104
+ }
105
+ }
106
+ elif "path" in parms["output"]:
107
+ output_path = parms["output"]["path"]
108
+ else:
109
+ output_path = None # will need to look for it later
110
+ # make request
111
+ rsps = sliderule.source(self.args.api, {"parms": parms}, stream=True, session=self.session)
112
+ # find remote output path (if not already set)
113
+ if not output_path:
114
+ for rsp in rsps:
115
+ if 'arrowrec.remote' == rsp['__rectype']:
116
+ output_path = rsp['url']
117
+ break
118
+ # set and return results
119
+ result = output_path
120
+ self.__display_result(result, reformat=True)
121
+ return result
122
+
123
+ #########################################
124
+ # Main
125
+ #########################################
126
+
127
+ def main():
128
+
129
+ # options shared by every subcommand; parents= lets them appear after the command name
130
+ common = argparse.ArgumentParser(add_help=False)
131
+ common.add_argument('--domain', type=str, default="slideruleearth.io")
132
+ common.add_argument('--cluster', type=str, default="sliderule")
133
+ common.add_argument('--user_service', action='store_true', default=False, help="uses dedicated user capacity")
134
+ common.add_argument('--verbose', action='store_true', default=False, help="turns on verbose log messages")
135
+ common.add_argument('--result', type=str, default=None, help="file name to store result of command")
136
+
137
+ # command line arguments
138
+ parser = argparse.ArgumentParser(prog="sliderule-cluster", description="""SlideRule Cluster""")
139
+ subparsers = parser.add_subparsers(dest="command", required=True)
140
+
141
+ # whoami
142
+ whoami = subparsers.add_parser("whoami", parents=[common], help="self identification of the cluster; returns cluster name")
143
+ whoami.set_defaults(func=Tool.whoami)
144
+
145
+ # status
146
+ status = subparsers.add_parser("status", parents=[common], help="registration status of cluster")
147
+ status.set_defaults(func=Tool.status)
148
+
149
+ # version
150
+ version = subparsers.add_parser("version", parents=[common], help="cluster version information")
151
+ version.set_defaults(func=Tool.version)
152
+
153
+ # defaults
154
+ defaults = subparsers.add_parser("defaults", parents=[common], help="cluster default parameter values")
155
+ defaults.set_defaults(func=Tool.defaults)
156
+
157
+ # earthdata
158
+ earthdata = subparsers.add_parser("earthdata", parents=[common], help="earthdata search")
159
+ earthdata.add_argument('--asset', type=str, default="icesat2", help="SlideRule asset name")
160
+ earthdata.add_argument('--poly', type=float, nargs='+', default=None, help="closed counter-clockwise list of latitude longitude pairs defining the area of interest; e.g. lon1 lat1 lon2 lat2 lon3 lat3 ... lon1 lat1")
161
+ earthdata.add_argument('--geojson', type=str, default=None, help="geojson filename defining the area of interest")
162
+ earthdata.add_argument('--bbox', type=float, nargs='+', default=None, help="bounding box defining the area of interest; e.g. lon_ll lat_ll lon_ur lat_ur")
163
+ earthdata.add_argument('--t0', type=str, default=None, help="start time as an ISO datetime string YYYY-MM-DDTHH:MM:SSZ") # datetime.fromisoformat(args.t0)
164
+ earthdata.add_argument('--t1', type=str, default=None, help="stop time as an ISO datetime string YYYY-MM-DDTHH:MM:SSZ") # datetime.fromisoformat(args.t1)
165
+ earthdata.add_argument('--max_resources', type=int, default=None, help="maximum number of resources allowed to be returned by query; queries exceeding this number return an error")
166
+ earthdata.add_argument('--short_name', type=str, default=None, help="CMR dataset name")
167
+ earthdata.add_argument('--with_meta', action='store_true', default=False, help="return metadata along with query results")
168
+ earthdata.add_argument('--name_filter', type=str, default=None, help="regular expression to evaluate against resource names returned by query")
169
+ earthdata.set_defaults(func=Tool.earthdata)
170
+
171
+ # run
172
+ run = subparsers.add_parser("run", parents=[common], help="execute dataframe based api request")
173
+ run.add_argument('api', type=str, metavar="<api>", help="endpoint being called")
174
+ run.add_argument('--parms', type=str, required=True, help="string or filename containing json parameters to use in request")
175
+ run.set_defaults(func=Tool.run)
176
+
177
+ # parse command line
178
+ args = parser.parse_args()
179
+
180
+ # create tool
181
+ tool = Tool(args)
182
+
183
+ # route command
184
+ try:
185
+ result = args.func(tool)
186
+ if args.result:
187
+ with open(args.result, "w") as file:
188
+ file.write(result)
189
+ except Exception as e:
190
+ if args.verbose: raise
191
+ print(f"Unhandled error: {e}")
192
+
193
+ # running via direct invocation
194
+ if __name__ == "__main__": main()
File without changes
@@ -0,0 +1,154 @@
1
+ import json
2
+ import argparse
3
+ from datetime import datetime
4
+ from zoneinfo import ZoneInfo
5
+ from sliderule import sliderule
6
+
7
+ #########################################
8
+ # Tool
9
+ #########################################
10
+
11
+ class Tool:
12
+
13
+ # Constructor
14
+ def __init__(self, args):
15
+ self.args = args
16
+ self.session = sliderule.create_session(domain=args.domain, cluster=args.cluster, user_service=args.user_service, verbose=args.verbose)
17
+
18
+ def __display_concise(self, response):
19
+ data = {
20
+ "error": response.get("error"),
21
+ "error_description": response.get("error_description"),
22
+ "stack_name": response.get("response", {}).get("StackName"),
23
+ "stack_status": response.get("response", {}).get("StackStatus"),
24
+ "creation_time": response.get("response", {}).get("CreationTime"),
25
+ "auto_shutdown": response.get("auto_shutdown"),
26
+ "current_nodes": response.get("current_nodes"),
27
+ "version": response.get("version"),
28
+ "is_public": response.get("is_public"),
29
+ "node_capacity": response.get("node_capacity"),
30
+ "users": response.get("users")
31
+ }
32
+ for date_field in ["creation_time", "auto_shutdown"]:
33
+ if data[date_field]:
34
+ data[date_field] = datetime.fromisoformat(data[date_field]).astimezone(ZoneInfo(self.args.timezone)).strftime("%Y-%m-%d %H:%M:%S %Z")
35
+ if data["users"]:
36
+ for user in data["users"]:
37
+ data["users"][user]["auto_shutdown"] = datetime.fromisoformat(data["users"][user]["auto_shutdown"]).astimezone(ZoneInfo(self.args.timezone)).strftime("%Y-%m-%d %H:%M:%S %Z")
38
+ return {k:data[k] for k in data if data[k] is not None}
39
+
40
+ # Deploy
41
+ def deploy(self):
42
+ return self.session.provisioner.deploy(is_public=(self.args.is_public == "true"), node_capacity=self.args.node_capacity, ttl=self.args.ttl, version=self.args.version)
43
+
44
+ # Extend
45
+ def extend(self):
46
+ return self.session.provisioner.extend(ttl=self.args.ttl)
47
+
48
+ # Destroy
49
+ def destroy(self):
50
+ return self.session.provisioner.destroy()
51
+
52
+ # Status
53
+ def status(self):
54
+ return self.__display_concise(self.session.provisioner.status())
55
+
56
+ # Events
57
+ def events(self):
58
+ return self.session.provisioner.events()
59
+
60
+ # Report
61
+ def report(self):
62
+ return {k[0]:self.__display_concise(k[1]) for k in self.session.provisioner.report(kind=self.args.kind).items()}
63
+
64
+ # Test
65
+ def test(self):
66
+ return self.session.gateway_request("test", subdomain="provisioner", data={"branch":self.args.branch})
67
+
68
+ # Info
69
+ def info(self):
70
+ return self.session.provisioner.info()
71
+
72
+ # Authenticate
73
+ def authenticate(self):
74
+ return self.session.authenticate(force_login=True)
75
+
76
+
77
+ #########################################
78
+ # Main
79
+ #########################################
80
+
81
+ def main():
82
+
83
+ # command line arguments
84
+ parser = argparse.ArgumentParser(prog="sliderule-runner", description="""SlideRule Runner""")
85
+ subparsers = parser.add_subparsers(dest="command", required=True)
86
+
87
+ # options shared by every subcommand; parents= lets them appear after the command name
88
+ common = argparse.ArgumentParser(add_help=False)
89
+ common.add_argument('--domain', type=str, default="slideruleearth.io")
90
+ common.add_argument('--cluster', type=str, default="developers")
91
+ common.add_argument('--user_service', action='store_true', default=False)
92
+ common.add_argument('--concise', action='store_true', default=False)
93
+ common.add_argument('--verbose', action='store_true', default=False)
94
+ common.add_argument('--timezone', type=str, default="America/New_York")
95
+
96
+ # deploy
97
+ deploy = subparsers.add_parser("deploy", parents=[common], help="deploy a cluster (stand-alone or as user capacity)")
98
+ deploy.add_argument('--is_public', type=str, default="false")
99
+ deploy.add_argument('--node_capacity', type=int, default=1)
100
+ deploy.add_argument('--ttl', type=int, default=60) # 1 hour
101
+ deploy.add_argument('--version', type=str, default="unstable")
102
+ deploy.set_defaults(func=Tool.deploy)
103
+
104
+ # extend
105
+ extend = subparsers.add_parser("extend", parents=[common], help="extend a cluster")
106
+ extend.add_argument('--ttl', type=int, default=60) # 1 hour
107
+ extend.set_defaults(func=Tool.extend)
108
+
109
+ # destroy
110
+ destroy = subparsers.add_parser("destroy", parents=[common], help="destroy a cluster")
111
+ destroy.set_defaults(func=Tool.destroy)
112
+
113
+ # status
114
+ status = subparsers.add_parser("status", parents=[common], help="status a cluster")
115
+ status.set_defaults(func=Tool.status)
116
+
117
+ # events
118
+ events = subparsers.add_parser("events", parents=[common], help="list the stack events associated with a cluster")
119
+ events.set_defaults(func=Tool.events)
120
+
121
+ # report
122
+ report = subparsers.add_parser("report", parents=[common], help="report metadata of active clusters")
123
+ report.add_argument('--kind', type=str, default="clusters", help="'cluster' for cluster report, 'test' for test report")
124
+ report.set_defaults(func=Tool.report)
125
+
126
+ # test
127
+ test = subparsers.add_parser("test", parents=[common], help="execute the test runner")
128
+ test.add_argument('--branch', type=str, default="main")
129
+ test.set_defaults(func=Tool.test)
130
+
131
+ # info
132
+ info = subparsers.add_parser("info", parents=[common], help="display information about provisioner")
133
+ info.set_defaults(func=Tool.info)
134
+
135
+ # authenticate
136
+ authenticate = subparsers.add_parser("authenticate", parents=[common], help="force re-authentication of user account")
137
+ authenticate.set_defaults(func=Tool.authenticate)
138
+
139
+ # parse command line
140
+ args = parser.parse_args()
141
+
142
+ # create tool
143
+ tool = Tool(args)
144
+
145
+ # route command
146
+ try:
147
+ result = args.func(tool)
148
+ print(f'{json.dumps(result, indent=2)}')
149
+ except Exception as e:
150
+ if args.verbose: raise
151
+ print(f"Unhandled error: {e}")
152
+
153
+ # running via direct invocation
154
+ if __name__ == "__main__": main()
File without changes
@@ -0,0 +1,12 @@
1
+ # conda env create -f environment.yml
2
+ name: recorder
3
+ channels:
4
+ - conda-forge
5
+ - defaults
6
+ dependencies:
7
+ - python
8
+ - boto3
9
+ - geoip2
10
+ - pandas
11
+ - pillow
12
+ - matplotlib