Skip to content

Commit 0f047b4

Browse files
Object Store Get & API Cleanup (#443)
- Add new object store get command - Fix object store help commands - Further API cleanup
1 parent 3aead51 commit 0f047b4

File tree

19 files changed

+270
-228
lines changed

19 files changed

+270
-228
lines changed

README.md

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ A locally-focused workflow (local development, local execution) with the CLI may
7979
- [`lean cloud object-store get`](#lean-cloud-object-store-get)
8080
- [`lean cloud object-store list`](#lean-cloud-object-store-list)
8181
- [`lean cloud object-store ls`](#lean-cloud-object-store-ls)
82+
- [`lean cloud object-store properties`](#lean-cloud-object-store-properties)
8283
- [`lean cloud object-store set`](#lean-cloud-object-store-set)
8384
- [`lean cloud optimize`](#lean-cloud-optimize)
8485
- [`lean cloud pull`](#lean-cloud-pull)
@@ -112,6 +113,7 @@ A locally-focused workflow (local development, local execution) with the CLI may
112113
- [`lean object-store get`](#lean-object-store-get)
113114
- [`lean object-store list`](#lean-object-store-list)
114115
- [`lean object-store ls`](#lean-object-store-ls)
116+
- [`lean object-store properties`](#lean-object-store-properties)
115117
- [`lean object-store set`](#lean-object-store-set)
116118
- [`lean optimize`](#lean-optimize)
117119
- [`lean project-create`](#lean-project-create)
@@ -450,6 +452,8 @@ Usage: lean cloud object-store delete [OPTIONS] KEY
450452
451453
Delete a value from the organization's cloud object store.
452454
455+
:param key: The desired key name to delete.
456+
453457
Options:
454458
--verbose Enable debug logging
455459
--help Show this message and exit.
@@ -459,16 +463,20 @@ _See code: [lean/commands/cloud/object_store/delete.py](lean/commands/cloud/obje
459463

460464
### `lean cloud object-store get`
461465

462-
Get a value from the organization's cloud object store.
466+
Download an object store value to disk from the organization's cloud object store.
463467

464468
```
465-
Usage: lean cloud object-store get [OPTIONS] KEY
469+
Usage: lean cloud object-store get [OPTIONS] [KEY]...
470+
471+
Download an object store value to disk from the organization's cloud object store.
466472
467-
Get a value from the organization's cloud object store.
473+
:param key: The desired key to fetch, multiple can be provided.
468474
469475
Options:
470-
--verbose Enable debug logging
471-
--help Show this message and exit.
476+
--destination-folder TEXT The destination folder to download the object store values, if not provided will use to
477+
current directory
478+
--verbose Enable debug logging
479+
--help Show this message and exit.
472480
```
473481

474482
_See code: [lean/commands/cloud/object_store/get.py](lean/commands/cloud/object_store/get.py)_
@@ -482,6 +490,8 @@ Usage: lean cloud object-store list [OPTIONS] [KEY]
482490
483491
List all values for the given root key in the organization's cloud object store.
484492
493+
:param key: The desired root key to list.
494+
485495
Options:
486496
--verbose Enable debug logging
487497
--help Show this message and exit.
@@ -498,13 +508,33 @@ Usage: lean cloud object-store ls [OPTIONS] [KEY]
498508
499509
List all values for the given root key in the organization's cloud object store.
500510
511+
:param key: The desired root key to list.
512+
501513
Options:
502514
--verbose Enable debug logging
503515
--help Show this message and exit.
504516
```
505517

506518
_See code: [lean/commands/cloud/object_store/ls.py](lean/commands/cloud/object_store/ls.py)_
507519

520+
### `lean cloud object-store properties`
521+
522+
Get a value properties from the organization's cloud object store.
523+
524+
```
525+
Usage: lean cloud object-store properties [OPTIONS] KEY
526+
527+
Get a value properties from the organization's cloud object store.
528+
529+
:param key: The desired key to fetch the properties for.
530+
531+
Options:
532+
--verbose Enable debug logging
533+
--help Show this message and exit.
534+
```
535+
536+
_See code: [lean/commands/cloud/object_store/properties.py](lean/commands/cloud/object_store/properties.py)_
537+
508538
### `lean cloud object-store set`
509539

510540
Sets the data to the given key in the organization's cloud object store.
@@ -1427,6 +1457,22 @@ Options:
14271457

14281458
_See code: [lean/commands/object_store/ls.py](lean/commands/object_store/ls.py)_
14291459

1460+
### `lean object-store properties`
1461+
1462+
Opens the local storage directory in the file explorer.
1463+
1464+
```
1465+
Usage: lean object-store properties [OPTIONS]
1466+
1467+
Opens the local storage directory in the file explorer.
1468+
1469+
Options:
1470+
--verbose Enable debug logging
1471+
--help Show this message and exit.
1472+
```
1473+
1474+
_See code: [lean/commands/object_store/properties.py](lean/commands/object_store/properties.py)_
1475+
14301476
### `lean object-store set`
14311477

14321478
Opens the local storage directory in the file explorer.

lean/commands/cloud/object_store/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616
from lean.commands.cloud.object_store.set import set
1717
from lean.commands.cloud.object_store.list import list
1818
from lean.commands.cloud.object_store.delete import delete
19+
from lean.commands.cloud.object_store.properties import properties
1920

2021
object_store.add_command(get)
2122
object_store.add_command(set)
2223
object_store.add_command(list)
2324
object_store.add_command(delete)
24-
25+
object_store.add_command(properties)

lean/commands/cloud/object_store/delete.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@
2222
def delete(key: str) -> str:
2323
"""
2424
Delete a value from the organization's cloud object store.
25-
25+
26+
:param key: The desired key name to delete.
2627
"""
2728
organization_id = container.organization_manager.try_get_working_organization_id()
2829
api_client = container.api_client
29-
api_client.object_store.delete(key, organization_id)
30+
api_client.object_store.delete(key, organization_id)

lean/commands/cloud/object_store/get.py

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,45 +11,50 @@
1111
# See the License for the specific language governing permissions and
1212
# limitations under the License.
1313

14-
from click import command, argument
14+
from uuid import uuid4
15+
from os import path, getcwd, unlink, mkdir
16+
17+
from click import command, option, argument
1518
from lean.click import LeanCommand
1619
from lean.container import container
1720

1821

1922
@command(cls=LeanCommand)
20-
@argument("key", type=str)
21-
def get(key: str) -> str:
23+
@argument("key", type=str, nargs=-1)
24+
@option("--destination-folder", type=str, default="",
25+
help=f"The destination folder to download the object store values,"
26+
f" if not provided will use to current directory")
27+
def get(key: [str], destination_folder: str):
2228
"""
23-
Get a value from the organization's cloud object store.
29+
Download an object store value to disk from the organization's cloud object store.
2430
31+
:param key: The desired key to fetch, multiple can be provided.
2532
"""
2633
organization_id = container.organization_manager.try_get_working_organization_id()
2734
api_client = container.api_client
2835
logger = container.logger
29-
data = api_client.object_store.get(key, organization_id)
30-
31-
try:
32-
headers = ["size", "modified", "key", "preview"]
33-
display_headers = ["Bytes", "Modified", "Filename", "Preview"]
34-
data_row = []
35-
for header in headers:
36-
if header == "preview":
37-
value = str(data["metadata"].get(header, "N/A"))
38-
data_row.append(_clean_up_preview(value))
39-
else:
40-
value = str(data["metadata"].get(header, ""))
41-
data_row.append(value)
42-
all_rows = [display_headers] + [data_row]
43-
column_widths = [max(len(row[i]) for row in all_rows) for i in range(len(all_rows[0]))]
44-
for row in all_rows:
45-
logger.info(" ".join(value.ljust(width) for value, width in zip(row, column_widths)))
46-
except KeyError as e:
47-
logger.error(f"Key {key} not found.")
48-
except Exception as e:
49-
logger.error(f"Error: {e}")
50-
51-
52-
def _clean_up_preview(preview: str) -> str:
53-
return preview.rstrip()[:10]
5436

37+
logger.info(f"Fetching object store download url")
38+
url = api_client.object_store.get(key, organization_id, logger)
39+
if not destination_folder:
40+
destination_folder = getcwd()
41+
42+
if not path.exists(destination_folder):
43+
mkdir(destination_folder)
44+
45+
temp_file = path.join(destination_folder, f"{str(uuid4())}.zip")
46+
47+
with logger.transient_progress() as progress:
48+
progress.add_task(f"Start downloading keys into {temp_file}:", total=None)
49+
logger.debug(f"Downloading: {url}")
50+
51+
api_client.data.download_url(url, temp_file, lambda advance: None)
52+
53+
logger.info(f"Unzipping object store keys values into: '{destination_folder}'")
54+
from zipfile import ZipFile
55+
with ZipFile(temp_file, 'r') as zip_ref:
56+
zip_ref.extractall(destination_folder)
5557

58+
if path.exists(temp_file):
59+
logger.debug(f"Deleting temp file: '{temp_file}'")
60+
unlink(temp_file)

lean/commands/cloud/object_store/list.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919

2020
@object_store.command(cls=LeanCommand, name="list", aliases=["ls"])
2121
@argument("key", type=str, default="/")
22-
def list(key: str) -> str:
22+
def list(key: str):
2323
"""
2424
List all values for the given root key in the organization's cloud object store.
25+
26+
:param key: The desired root key to list.
2527
"""
2628
organization_id = container.organization_manager.try_get_working_organization_id()
2729
api_client = container.api_client
@@ -41,4 +43,4 @@ def list(key: str) -> str:
4143
except KeyError as e:
4244
logger.error(f"Key {key} not found.")
4345
except Exception as e:
44-
logger.error(f"Error: {e}")
46+
logger.error(f"Error: {e}")
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
2+
# Lean CLI v1.0. Copyright 2021 QuantConnect Corporation.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
from click import command, argument
15+
from lean.click import LeanCommand
16+
from lean.container import container
17+
18+
19+
@command(cls=LeanCommand)
20+
@argument("key", type=str)
21+
def properties(key: str):
22+
"""
23+
Get a value properties from the organization's cloud object store.
24+
25+
:param key: The desired key to fetch the properties for.
26+
"""
27+
organization_id = container.organization_manager.try_get_working_organization_id()
28+
api_client = container.api_client
29+
logger = container.logger
30+
data = api_client.object_store.properties(key, organization_id)
31+
32+
try:
33+
headers = ["size", "modified", "key", "preview"]
34+
display_headers = ["Bytes", "Modified", "Filename", "Preview"]
35+
data_row = []
36+
for header in headers:
37+
if header == "preview":
38+
value = str(data["metadata"].get(header, "N/A"))
39+
data_row.append(_clean_up_preview(value))
40+
else:
41+
value = str(data["metadata"].get(header, ""))
42+
data_row.append(value)
43+
all_rows = [display_headers] + [data_row]
44+
column_widths = [max(len(row[i]) for row in all_rows) for i in range(len(all_rows[0]))]
45+
for row in all_rows:
46+
logger.info(" ".join(value.ljust(width) for value, width in zip(row, column_widths)))
47+
except KeyError as e:
48+
logger.error(f"Key {key} not found.")
49+
except Exception as e:
50+
logger.error(f"Error: {e}")
51+
52+
53+
def _clean_up_preview(preview: str) -> str:
54+
return preview.rstrip()[:10]

lean/commands/cloud/object_store/set.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,4 @@ def set(key: str, path: Path) -> None:
3131
api_client = container.api_client
3232
with open(path, "rb") as file:
3333
bytes_data: bytes = file.read()
34-
api_client.object_store.set(key, bytes_data, organization_id)
34+
api_client.object_store.set(key, bytes_data, organization_id)

lean/commands/object_store/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616
from lean.commands.object_store.set import set
1717
from lean.commands.object_store.list import list
1818
from lean.commands.object_store.delete import delete
19+
from lean.commands.object_store.properties import properties
1920

2021
object_store.add_command(get)
2122
object_store.add_command(set)
2223
object_store.add_command(list)
2324
object_store.add_command(delete)
24-
25+
object_store.add_command(properties)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
2+
# Lean CLI v1.0. Copyright 2021 QuantConnect Corporation.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
15+
from click import command
16+
from lean.click import LeanCommand
17+
from lean.container import container
18+
from lean.components.util.object_store_helper import open_storage_directory_in_explorer
19+
20+
21+
@command(cls=LeanCommand)
22+
def properties() -> str:
23+
"""
24+
Opens the local storage directory in the file explorer.
25+
"""
26+
open_storage_directory_in_explorer(container.lean_config_manager)

0 commit comments

Comments
 (0)