materials-commons-cli 2.3.0b11__tar.gz → 2.3.0b12__tar.gz
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.
- {materials_commons_cli-2.3.0b11/materials_commons_cli.egg-info → materials_commons_cli-2.3.0b12}/PKG-INFO +1 -2
- materials_commons_cli-2.3.0b12/materials_commons/cli/__init__.py +1 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/parser.py +3 -8
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/uploader/file_uploader.py +15 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/websocket_server.py +1 -1
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/up.py +6 -1
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12/materials_commons_cli.egg-info}/PKG-INFO +1 -2
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons_cli.egg-info/SOURCES.txt +0 -1
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons_cli.egg-info/requires.txt +0 -1
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/setup.py +0 -1
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/tests/test_file_uploader.py +272 -0
- materials_commons_cli-2.3.0b11/materials_commons/cli/__init__.py +0 -1
- materials_commons_cli-2.3.0b11/materials_commons/cli/subcommands/mcp.py +0 -86
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/LICENSE +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/README.md +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/LICENSE.txt +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/async_reconciler.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/config.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/downloader.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/filedb.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/local_project.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/models.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/old/__init__.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/old/cloned_project.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/old/exceptions.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/old/file_functions.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/old/functions.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/old/globus.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/old/list_objects.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/old/print_formatter.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/old/sqltable.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/old/tmp_functions.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/old/tree_functions.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/old/treedb.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/old/user_config.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/reconcile2.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/reconcile3.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/requests.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/run.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/__init__.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/command_handlers/__init__.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/command_handlers/admin_handler_lookup.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/command_handlers/download_handler_lookup.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/command_handlers/list_handler_lookup.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/command_handlers/multi_handler_lookup.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/command_handlers/protocol.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/command_handlers/search_find_handler_lookup.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/command_handlers/upload_handler_lookup.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/db/__init__.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/db/db_manager.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/downloader/__init__.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/downloader/file_download_manager.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/downloader/file_downloader.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/indexer/__init__.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/indexer/file_index_manager.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/local_rest_server.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/ocommand_handlers.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/project_filedbs.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/projects.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/service_container.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/service_runtime.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/uploader/__init__.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/uploader/client_api.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/server/uploader/file_upload_manager.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/__init__.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/clone.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/config.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/dataset.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/down.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/down2.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/expt.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/fetch.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/globus.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/init.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/ls.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/ls2.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/mkdir.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/mv.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/proj.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/remote.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/rm.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/runners/__init__.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/runners/download_globus_runner.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/runners/download_v1_runner.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/scan.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/server.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/subcommands/versions.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/terminal_progress.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/walk.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons_cli.egg-info/dependency_links.txt +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons_cli.egg-info/entry_points.txt +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons_cli.egg-info/not-zip-safe +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons_cli.egg-info/top_level.txt +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/setup.cfg +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/test/test_api.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/test/test_functions.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/test/test_mc_dataset.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/test/test_mc_down.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/test/test_mc_mkdir.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/test/test_mc_mv.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/test/test_mc_proj.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/test/test_mc_rm.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/test/test_mc_up.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/test/test_treecompare_no_cache.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/test/test_treecompare_with_cache.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/test/test_treedb.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/test/test_user_config.py +0 -0
- {materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/tests/test_reconcile3.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: materials_commons_cli
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.0b12
|
|
4
4
|
Summary: Materials Commons CLI
|
|
5
5
|
Home-page: https://materials-commons.github.io/materials-commons-cli/html/index.html
|
|
6
6
|
Author: Materials Commons development team
|
|
@@ -27,7 +27,6 @@ Requires-Dist: requests~=2.28
|
|
|
27
27
|
Requires-Dist: sortedcontainers~=2.4
|
|
28
28
|
Requires-Dist: tabulate~=0.9
|
|
29
29
|
Requires-Dist: aiosqlite~=0.22
|
|
30
|
-
Requires-Dist: fastmcp~=3.4
|
|
31
30
|
Dynamic: author
|
|
32
31
|
Dynamic: author-email
|
|
33
32
|
Dynamic: classifier
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '2.3.0b12'
|
{materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/parser.py
RENAMED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import argparse
|
|
2
2
|
import json
|
|
3
3
|
import logging
|
|
4
|
+
import materials_commons.api as mcapi
|
|
4
5
|
import os
|
|
5
6
|
import sys
|
|
6
7
|
from datetime import datetime, timedelta
|
|
7
8
|
from importlib.metadata import PackageNotFoundError, version as pkg_version
|
|
8
9
|
from io import StringIO
|
|
9
10
|
|
|
10
|
-
import materials_commons.api as mcapi
|
|
11
|
-
import requests
|
|
12
|
-
|
|
13
11
|
import materials_commons.cli.old.functions as clifuncs
|
|
12
|
+
import requests
|
|
14
13
|
from materials_commons.cli.old.exceptions import MCCLIException, MissingRemoteException, \
|
|
15
14
|
MultipleRemoteException, NoDefaultRemoteException
|
|
16
15
|
from materials_commons.cli.old.user_config import Config
|
|
@@ -18,15 +17,12 @@ from materials_commons.cli.subcommands.clone import clone_subcommand
|
|
|
18
17
|
from materials_commons.cli.subcommands.config import config_subcommand
|
|
19
18
|
from materials_commons.cli.subcommands.dataset import DatasetSubcommand
|
|
20
19
|
from materials_commons.cli.subcommands.down import down_subcommand
|
|
21
|
-
from materials_commons.cli.subcommands.down2 import down2_subcommand
|
|
22
20
|
from materials_commons.cli.subcommands.expt import ExptSubcommand
|
|
23
21
|
from materials_commons.cli.subcommands.fetch import fetch_subcommand
|
|
24
22
|
# from materials_commons.cli.subcommands.samp import SampSubcommand
|
|
25
23
|
from materials_commons.cli.subcommands.globus import globus_subcommand
|
|
26
24
|
from materials_commons.cli.subcommands.init import init_subcommand
|
|
27
25
|
from materials_commons.cli.subcommands.ls import ls_subcommand
|
|
28
|
-
from materials_commons.cli.subcommands.ls2 import ls2_subcommand
|
|
29
|
-
from materials_commons.cli.subcommands.mcp import mcp_subcommand
|
|
30
26
|
from materials_commons.cli.subcommands.mkdir import mkdir_subcommand
|
|
31
27
|
from materials_commons.cli.subcommands.mv import mv_subcommand
|
|
32
28
|
# from materials_commons.cli.subcommands.proc import ProcSubcommand
|
|
@@ -61,7 +57,6 @@ standard_usage = [
|
|
|
61
57
|
# {'name': 'down2', 'desc': 'Donwload files (experimental)', 'subcommand': down2_subcommand},
|
|
62
58
|
{'name': 'config', 'desc': 'Configure `mc`', 'subcommand': config_subcommand},
|
|
63
59
|
{'name': 'server', 'desc': 'Run MC Server', 'subcommand': server_subcommand},
|
|
64
|
-
{'name': 'mcp', 'desc': 'Run MCP Server', 'subcommand': mcp_subcommand},
|
|
65
60
|
]
|
|
66
61
|
standard_interfaces = {d['name']: d for d in standard_usage}
|
|
67
62
|
|
|
@@ -169,7 +164,7 @@ def main(argv=None, working_dir=None):
|
|
|
169
164
|
|
|
170
165
|
if args.command in standard_interfaces:
|
|
171
166
|
result = standard_interfaces[args.command]['subcommand'](argv[2:], working_dir)
|
|
172
|
-
check_package_version()
|
|
167
|
+
# check_package_version()
|
|
173
168
|
return result
|
|
174
169
|
|
|
175
170
|
else:
|
|
@@ -209,6 +209,21 @@ class FileUploader:
|
|
|
209
209
|
logger.error(f"Transfer rejected: {reason}")
|
|
210
210
|
return False
|
|
211
211
|
|
|
212
|
+
elif msg["command"] == "TRANSFER_ALREADY_UPLOADED":
|
|
213
|
+
payload = msg["payload"]
|
|
214
|
+
updated_record = replace(self.upload_request.updated_record,
|
|
215
|
+
local_last_seen_ts=int(time.time()),
|
|
216
|
+
remote_checksum=payload.get("file_checksum", ""),
|
|
217
|
+
remote_size=payload.get("file_size", 0),
|
|
218
|
+
remote_file_id=payload.get("file_id", 0),
|
|
219
|
+
remote_ctime_ns=payload.get("file_created_at_ns", 0))
|
|
220
|
+
db_write_request = DBWriteRequest(project=self.upload_request.project,
|
|
221
|
+
data=updated_record,
|
|
222
|
+
command="single")
|
|
223
|
+
await self.db_write_queue.put(db_write_request)
|
|
224
|
+
self._already_uploaded = True
|
|
225
|
+
return False
|
|
226
|
+
|
|
212
227
|
logger.error(f"Unexpected response: {msg['command']}")
|
|
213
228
|
return False
|
|
214
229
|
|
|
@@ -241,7 +241,7 @@ class WebSocketCommandListener:
|
|
|
241
241
|
|
|
242
242
|
headers["MC-Client-ID"] = self.client_uuid
|
|
243
243
|
headers["MC-Client-Hostname"] = socket.gethostname()
|
|
244
|
-
headers["MC-Connection-Type"] = "
|
|
244
|
+
headers["MC-Connection-Type"] = "pycli"
|
|
245
245
|
|
|
246
246
|
try:
|
|
247
247
|
projects = server.list_local_projects()
|
|
@@ -192,6 +192,9 @@ async def ws_upload(args, working_dir):
|
|
|
192
192
|
ignore_parser = igittigitt.IgnoreParser()
|
|
193
193
|
ignore_parser.parse_rule_files(base_dir=proj.local_path, filename=".mcignore", add_default_patterns=False)
|
|
194
194
|
|
|
195
|
+
def ignore(path, _ignore):
|
|
196
|
+
return ignore_parser.match(path)
|
|
197
|
+
|
|
195
198
|
# Start services
|
|
196
199
|
container = ServiceContainer.create(ws_url=args.ws_url)
|
|
197
200
|
service_runtime = ServiceRuntime(container)
|
|
@@ -204,7 +207,7 @@ async def ws_upload(args, working_dir):
|
|
|
204
207
|
p = Path(path)
|
|
205
208
|
if p.is_dir():
|
|
206
209
|
async for current_path, path_entries in async_reconciler.walk(path=path, listdir_fn=local_listdir,
|
|
207
|
-
recursive=args.recursive, ignore_fn=
|
|
210
|
+
recursive=args.recursive, ignore_fn=ignore):
|
|
208
211
|
for entry_name in sorted(path_entries):
|
|
209
212
|
file_state = path_entries[entry_name]
|
|
210
213
|
if file_state.exception:
|
|
@@ -218,6 +221,8 @@ async def ws_upload(args, working_dir):
|
|
|
218
221
|
transfer_id = await container.file_upload_manager.upload_file(upload_request)
|
|
219
222
|
transfer_ids.append(transfer_id)
|
|
220
223
|
elif p.is_file():
|
|
224
|
+
if ignore(p, True):
|
|
225
|
+
continue
|
|
221
226
|
file_state = await async_reconciler.reconcile_file(p)
|
|
222
227
|
if file_state.exception:
|
|
223
228
|
logger.error(f"Error encountered while processing {p}: {file_state.exception}")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: materials_commons_cli
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.0b12
|
|
4
4
|
Summary: Materials Commons CLI
|
|
5
5
|
Home-page: https://materials-commons.github.io/materials-commons-cli/html/index.html
|
|
6
6
|
Author: Materials Commons development team
|
|
@@ -27,7 +27,6 @@ Requires-Dist: requests~=2.28
|
|
|
27
27
|
Requires-Dist: sortedcontainers~=2.4
|
|
28
28
|
Requires-Dist: tabulate~=0.9
|
|
29
29
|
Requires-Dist: aiosqlite~=0.22
|
|
30
|
-
Requires-Dist: fastmcp~=3.4
|
|
31
30
|
Dynamic: author
|
|
32
31
|
Dynamic: author-email
|
|
33
32
|
Dynamic: classifier
|
|
@@ -69,7 +69,6 @@ materials_commons/cli/subcommands/globus.py
|
|
|
69
69
|
materials_commons/cli/subcommands/init.py
|
|
70
70
|
materials_commons/cli/subcommands/ls.py
|
|
71
71
|
materials_commons/cli/subcommands/ls2.py
|
|
72
|
-
materials_commons/cli/subcommands/mcp.py
|
|
73
72
|
materials_commons/cli/subcommands/mkdir.py
|
|
74
73
|
materials_commons/cli/subcommands/mv.py
|
|
75
74
|
materials_commons/cli/subcommands/proj.py
|
{materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/tests/test_file_uploader.py
RENAMED
|
@@ -7,11 +7,13 @@ from unittest.mock import AsyncMock
|
|
|
7
7
|
import pytest
|
|
8
8
|
|
|
9
9
|
from materials_commons.cli.server.uploader.file_uploader import FileUploader
|
|
10
|
+
from materials_commons.cli.subcommands.up import ws_upload
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
@dataclass(frozen=True)
|
|
13
14
|
class FakeUpdatedRecord:
|
|
14
15
|
local_checksum: str = "local-checksum"
|
|
16
|
+
local_last_seen_ts: int = 0
|
|
15
17
|
remote_checksum: str = ""
|
|
16
18
|
remote_size: int = 0
|
|
17
19
|
remote_file_id: int = 0
|
|
@@ -81,6 +83,276 @@ def drain_queue(queue):
|
|
|
81
83
|
items.append(queue.get_nowait())
|
|
82
84
|
return items
|
|
83
85
|
|
|
86
|
+
def test_wait_for_acceptance_already_uploaded_writes_updated_record_to_db_queue(tmp_path):
|
|
87
|
+
"""
|
|
88
|
+
Intent:
|
|
89
|
+
Verify TRANSFER_ALREADY_UPLOADED updates the file database queue.
|
|
90
|
+
|
|
91
|
+
When the server reports that a file has already been uploaded, the uploader
|
|
92
|
+
should treat acceptance as complete, mark the upload as already uploaded, and
|
|
93
|
+
enqueue the updated remote metadata for persistence.
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
async def run_test():
|
|
97
|
+
uploader, _, db_write_queue = make_uploader(tmp_path, file_bytes=b"hello")
|
|
98
|
+
|
|
99
|
+
await uploader.handle_response(
|
|
100
|
+
{
|
|
101
|
+
"command": "TRANSFER_ALREADY_UPLOADED",
|
|
102
|
+
"payload": {
|
|
103
|
+
"file_checksum": "remote-checksum",
|
|
104
|
+
"file_size": 5,
|
|
105
|
+
"file_id": 4321,
|
|
106
|
+
"file_created_at_ns": 987654321,
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
result = await uploader._wait_for_acceptance()
|
|
112
|
+
|
|
113
|
+
assert result is False
|
|
114
|
+
assert uploader._already_uploaded is True
|
|
115
|
+
assert uploader.waiting_for_response is None
|
|
116
|
+
|
|
117
|
+
db_write_request = await db_write_queue.get()
|
|
118
|
+
assert db_write_request.project == uploader.upload_request.project
|
|
119
|
+
assert db_write_request.command == "single"
|
|
120
|
+
assert db_write_request.data.remote_checksum == "remote-checksum"
|
|
121
|
+
assert db_write_request.data.remote_size == 5
|
|
122
|
+
assert db_write_request.data.remote_file_id == 4321
|
|
123
|
+
assert db_write_request.data.remote_ctime_ns == 987654321
|
|
124
|
+
|
|
125
|
+
asyncio.run(run_test())
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def test_upload_returns_true_and_updates_db_when_server_says_already_uploaded(tmp_path):
|
|
129
|
+
"""
|
|
130
|
+
Intent:
|
|
131
|
+
Verify the upload-level TRANSFER_ALREADY_UPLOADED path.
|
|
132
|
+
|
|
133
|
+
upload() should return success without sending chunks or TRANSFER_COMPLETE,
|
|
134
|
+
and it should preserve the database update produced during acceptance.
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
async def run_test():
|
|
138
|
+
uploader, ws_send_queue, db_write_queue = make_uploader(
|
|
139
|
+
tmp_path,
|
|
140
|
+
file_bytes=b"hello",
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
await uploader.handle_response(
|
|
144
|
+
{
|
|
145
|
+
"command": "TRANSFER_ALREADY_UPLOADED",
|
|
146
|
+
"payload": {
|
|
147
|
+
"file_checksum": "remote-checksum",
|
|
148
|
+
"file_size": 5,
|
|
149
|
+
"file_id": 2468,
|
|
150
|
+
"file_created_at_ns": 13579,
|
|
151
|
+
},
|
|
152
|
+
}
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
result = await uploader.upload()
|
|
156
|
+
|
|
157
|
+
assert result is True
|
|
158
|
+
|
|
159
|
+
sent_messages = drain_queue(ws_send_queue)
|
|
160
|
+
assert len(sent_messages) == 1
|
|
161
|
+
assert sent_messages[0]["command"] == "TRANSFER_INIT"
|
|
162
|
+
|
|
163
|
+
db_write_request = await db_write_queue.get()
|
|
164
|
+
assert db_write_request.command == "single"
|
|
165
|
+
assert db_write_request.data.remote_checksum == "remote-checksum"
|
|
166
|
+
assert db_write_request.data.remote_size == 5
|
|
167
|
+
assert db_write_request.data.remote_file_id == 2468
|
|
168
|
+
assert db_write_request.data.remote_ctime_ns == 13579
|
|
169
|
+
|
|
170
|
+
asyncio.run(run_test())
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def test_ws_upload_single_file_in_mcignore_is_not_uploaded_or_reconciled(tmp_path, monkeypatch):
|
|
174
|
+
"""
|
|
175
|
+
Intent:
|
|
176
|
+
Verify websocket single-file upload honors .mcignore.
|
|
177
|
+
|
|
178
|
+
If the requested file matches .mcignore, ws_upload() should skip it before
|
|
179
|
+
reconciliation and should not enqueue an upload.
|
|
180
|
+
"""
|
|
181
|
+
|
|
182
|
+
async def run_test():
|
|
183
|
+
project_root = tmp_path
|
|
184
|
+
ignored_file = project_root / "ignored.txt"
|
|
185
|
+
ignored_file.write_text("do not upload")
|
|
186
|
+
(project_root / ".mcignore").write_text("ignored.txt\n")
|
|
187
|
+
|
|
188
|
+
db = SimpleNamespace(close=AsyncMock())
|
|
189
|
+
proj = SimpleNamespace(local_path=project_root, get_filedb=AsyncMock(return_value=db))
|
|
190
|
+
|
|
191
|
+
class FakeLocalProject:
|
|
192
|
+
@staticmethod
|
|
193
|
+
def load(_working_dir):
|
|
194
|
+
return proj
|
|
195
|
+
|
|
196
|
+
class FakeServiceRuntime:
|
|
197
|
+
def __init__(self, _container):
|
|
198
|
+
pass
|
|
199
|
+
|
|
200
|
+
async def start(self, websocket_listener=True):
|
|
201
|
+
return None
|
|
202
|
+
|
|
203
|
+
async def stop(self, drain=True):
|
|
204
|
+
return None
|
|
205
|
+
|
|
206
|
+
upload_file = AsyncMock()
|
|
207
|
+
|
|
208
|
+
fake_container = SimpleNamespace(
|
|
209
|
+
file_upload_manager=SimpleNamespace(
|
|
210
|
+
upload_file=upload_file,
|
|
211
|
+
wait_all=AsyncMock(),
|
|
212
|
+
)
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
class FakeServiceContainer:
|
|
216
|
+
@staticmethod
|
|
217
|
+
def create(ws_url):
|
|
218
|
+
return fake_container
|
|
219
|
+
|
|
220
|
+
reconcile_file = AsyncMock()
|
|
221
|
+
|
|
222
|
+
class FakeAsyncReconciler:
|
|
223
|
+
def __init__(self, db, proj, reconcile_mode):
|
|
224
|
+
pass
|
|
225
|
+
|
|
226
|
+
async def reconcile_file(self, path):
|
|
227
|
+
return await reconcile_file(path)
|
|
228
|
+
|
|
229
|
+
monkeypatch.setattr("materials_commons.cli.subcommands.up.LocalProject", FakeLocalProject)
|
|
230
|
+
monkeypatch.setattr("materials_commons.cli.subcommands.up.ServiceRuntime", FakeServiceRuntime)
|
|
231
|
+
monkeypatch.setattr("materials_commons.cli.subcommands.up.ServiceContainer", FakeServiceContainer)
|
|
232
|
+
monkeypatch.setattr("materials_commons.cli.subcommands.up.AsyncReconciler", FakeAsyncReconciler)
|
|
233
|
+
|
|
234
|
+
args = SimpleNamespace(
|
|
235
|
+
paths=[ignored_file.as_posix()],
|
|
236
|
+
recursive=False,
|
|
237
|
+
ws_url="ws://example.test",
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
await ws_upload(args, project_root)
|
|
241
|
+
|
|
242
|
+
reconcile_file.assert_not_awaited()
|
|
243
|
+
upload_file.assert_not_awaited()
|
|
244
|
+
fake_container.file_upload_manager.wait_all.assert_awaited_once()
|
|
245
|
+
db.close.assert_awaited_once()
|
|
246
|
+
|
|
247
|
+
asyncio.run(run_test())
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def test_ws_upload_directory_walk_does_not_upload_files_in_mcignore(tmp_path, monkeypatch):
|
|
251
|
+
"""
|
|
252
|
+
Intent:
|
|
253
|
+
Verify websocket directory upload honors .mcignore during walk.
|
|
254
|
+
|
|
255
|
+
The directory walk should receive and use the ignore function, causing ignored
|
|
256
|
+
files to be excluded from upload while non-ignored files are still uploaded.
|
|
257
|
+
"""
|
|
258
|
+
|
|
259
|
+
async def run_test():
|
|
260
|
+
project_root = tmp_path
|
|
261
|
+
allowed_file = project_root / "allowed.txt"
|
|
262
|
+
ignored_file = project_root / "ignored.txt"
|
|
263
|
+
ignored_dir = project_root / "ignored-dir"
|
|
264
|
+
ignored_dir_file = ignored_dir / "nested.txt"
|
|
265
|
+
|
|
266
|
+
allowed_file.write_text("upload me")
|
|
267
|
+
ignored_file.write_text("do not upload me")
|
|
268
|
+
ignored_dir.mkdir()
|
|
269
|
+
ignored_dir_file.write_text("do not walk me")
|
|
270
|
+
(project_root / ".mcignore").write_text("ignored.txt\nignored-dir/\n")
|
|
271
|
+
|
|
272
|
+
db = SimpleNamespace(close=AsyncMock())
|
|
273
|
+
proj = SimpleNamespace(local_path=project_root, get_filedb=AsyncMock(return_value=db))
|
|
274
|
+
|
|
275
|
+
class FakeLocalProject:
|
|
276
|
+
@staticmethod
|
|
277
|
+
def load(_working_dir):
|
|
278
|
+
return proj
|
|
279
|
+
|
|
280
|
+
class FakeServiceRuntime:
|
|
281
|
+
def __init__(self, _container):
|
|
282
|
+
pass
|
|
283
|
+
|
|
284
|
+
async def start(self, websocket_listener=True):
|
|
285
|
+
return None
|
|
286
|
+
|
|
287
|
+
async def stop(self, drain=True):
|
|
288
|
+
return None
|
|
289
|
+
|
|
290
|
+
upload_file = AsyncMock(side_effect=["transfer-allowed"])
|
|
291
|
+
|
|
292
|
+
fake_container = SimpleNamespace(
|
|
293
|
+
file_upload_manager=SimpleNamespace(
|
|
294
|
+
upload_file=upload_file,
|
|
295
|
+
wait_all=AsyncMock(),
|
|
296
|
+
)
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
class FakeServiceContainer:
|
|
300
|
+
@staticmethod
|
|
301
|
+
def create(ws_url):
|
|
302
|
+
return fake_container
|
|
303
|
+
|
|
304
|
+
observed_ignore_results = {}
|
|
305
|
+
|
|
306
|
+
class FakeAsyncReconciler:
|
|
307
|
+
def __init__(self, db, proj, reconcile_mode):
|
|
308
|
+
pass
|
|
309
|
+
|
|
310
|
+
async def walk(self, path, listdir_fn, recursive=False, ignore_fn=None):
|
|
311
|
+
observed_ignore_results["allowed_file"] = ignore_fn(allowed_file, False)
|
|
312
|
+
observed_ignore_results["ignored_file"] = ignore_fn(ignored_file, False)
|
|
313
|
+
observed_ignore_results["ignored_dir"] = ignore_fn(ignored_dir, True)
|
|
314
|
+
observed_ignore_results["ignored_dir_file"] = ignore_fn(ignored_dir_file, False)
|
|
315
|
+
|
|
316
|
+
yield Path(path), {
|
|
317
|
+
"allowed.txt": SimpleNamespace(
|
|
318
|
+
exception=None,
|
|
319
|
+
observation=SimpleNamespace(name="allowed.txt"),
|
|
320
|
+
file_decision=SimpleNamespace(
|
|
321
|
+
action="upload",
|
|
322
|
+
updated_record=FakeUpdatedRecord(local_checksum="allowed-checksum"),
|
|
323
|
+
),
|
|
324
|
+
)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
monkeypatch.setattr("materials_commons.cli.subcommands.up.LocalProject", FakeLocalProject)
|
|
328
|
+
monkeypatch.setattr("materials_commons.cli.subcommands.up.ServiceRuntime", FakeServiceRuntime)
|
|
329
|
+
monkeypatch.setattr("materials_commons.cli.subcommands.up.ServiceContainer", FakeServiceContainer)
|
|
330
|
+
monkeypatch.setattr("materials_commons.cli.subcommands.up.AsyncReconciler", FakeAsyncReconciler)
|
|
331
|
+
|
|
332
|
+
args = SimpleNamespace(
|
|
333
|
+
paths=[project_root.as_posix()],
|
|
334
|
+
recursive=True,
|
|
335
|
+
ws_url="ws://example.test",
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
await ws_upload(args, project_root)
|
|
339
|
+
|
|
340
|
+
assert observed_ignore_results == {
|
|
341
|
+
"allowed_file": False,
|
|
342
|
+
"ignored_file": True,
|
|
343
|
+
"ignored_dir": True,
|
|
344
|
+
"ignored_dir_file": True,
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
upload_file.assert_awaited_once()
|
|
348
|
+
upload_request = upload_file.await_args.args[0]
|
|
349
|
+
assert upload_request.observation.name == "allowed.txt"
|
|
350
|
+
assert upload_request.updated_record.local_checksum == "allowed-checksum"
|
|
351
|
+
|
|
352
|
+
fake_container.file_upload_manager.wait_all.assert_awaited_once()
|
|
353
|
+
db.close.assert_awaited_once()
|
|
354
|
+
|
|
355
|
+
asyncio.run(run_test())
|
|
84
356
|
|
|
85
357
|
def test_send_transfer_init_puts_expected_message_on_websocket_queue(tmp_path):
|
|
86
358
|
"""
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '2.3.0b11'
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import argparse
|
|
2
|
-
import functools
|
|
3
|
-
import inspect
|
|
4
|
-
|
|
5
|
-
from mcp.server.fastmcp import FastMCP
|
|
6
|
-
from materials_commons.cli.config import Config
|
|
7
|
-
from materials_commons.api.client import Client
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
mcp = FastMCP(
|
|
11
|
-
name="mcmcp",
|
|
12
|
-
instructions=""
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def make_parser():
|
|
17
|
-
parser = argparse.ArgumentParser(
|
|
18
|
-
description="MCP Server for Materials Commons",
|
|
19
|
-
usage="mc mcp",
|
|
20
|
-
)
|
|
21
|
-
parser.add_argument("--port", type=int, default=8000)
|
|
22
|
-
parser.add_argument("--mc-url", type=str, default="https://materialscommons.org/api")
|
|
23
|
-
return parser
|
|
24
|
-
|
|
25
|
-
def mcp_subcommand(argv, working_dir=None):
|
|
26
|
-
parser = make_parser()
|
|
27
|
-
args = parser.parse_args(argv)
|
|
28
|
-
config = Config.load()
|
|
29
|
-
client = config.default_remote.make_client()
|
|
30
|
-
register_mcapi_tools(client)
|
|
31
|
-
mcp.run()
|
|
32
|
-
return args
|
|
33
|
-
|
|
34
|
-
def register_mcapi_tools(client: Client):
|
|
35
|
-
for method_name, method in inspect.getmembers(client, predicate=callable):
|
|
36
|
-
if method_name.startswith("_"):
|
|
37
|
-
continue
|
|
38
|
-
if not is_get_or_list_method(method_name):
|
|
39
|
-
continue
|
|
40
|
-
|
|
41
|
-
doc = inspect.getdoc(method)
|
|
42
|
-
if doc is None:
|
|
43
|
-
continue
|
|
44
|
-
|
|
45
|
-
signature = inspect.signature(method)
|
|
46
|
-
|
|
47
|
-
@functools.wraps(method)
|
|
48
|
-
def tool_wrapper(*args, __method=method, **kwargs):
|
|
49
|
-
result = __method(*args, **kwargs)
|
|
50
|
-
return to_jsonable(result)
|
|
51
|
-
|
|
52
|
-
tool_wrapper.__name__ = method_name
|
|
53
|
-
tool_wrapper.__doc__ = doc
|
|
54
|
-
tool_wrapper.__signature__ = signature
|
|
55
|
-
|
|
56
|
-
mcp.tool(name=method_name)(tool_wrapper)
|
|
57
|
-
|
|
58
|
-
def is_get_or_list_method(method_name: str):
|
|
59
|
-
return method_name.startswith("get_") or method_name.startswith("list_")
|
|
60
|
-
|
|
61
|
-
def to_jsonable(value):
|
|
62
|
-
if value is None:
|
|
63
|
-
return None
|
|
64
|
-
|
|
65
|
-
if isinstance(value, (str, int, float, bool)):
|
|
66
|
-
return value
|
|
67
|
-
|
|
68
|
-
if isinstance(value, list):
|
|
69
|
-
return [to_jsonable(item) for item in value]
|
|
70
|
-
|
|
71
|
-
if isinstance(value, tuple):
|
|
72
|
-
return [to_jsonable(item) for item in value]
|
|
73
|
-
|
|
74
|
-
if isinstance(value, dict):
|
|
75
|
-
return {
|
|
76
|
-
str(key): to_jsonable(item)
|
|
77
|
-
for key, item in value.items()
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if hasattr(value, "to_dict"):
|
|
81
|
-
return to_jsonable(value.to_dict())
|
|
82
|
-
|
|
83
|
-
if hasattr(value, "__dict__"):
|
|
84
|
-
return to_jsonable(value.__dict__)
|
|
85
|
-
|
|
86
|
-
return str(value)
|
|
File without changes
|
|
File without changes
|
{materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/LICENSE.txt
RENAMED
|
File without changes
|
|
File without changes
|
{materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/config.py
RENAMED
|
File without changes
|
|
File without changes
|
{materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/filedb.py
RENAMED
|
File without changes
|
|
File without changes
|
{materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/models.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/requests.py
RENAMED
|
File without changes
|
{materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/run.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/materials_commons/cli/walk.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{materials_commons_cli-2.3.0b11 → materials_commons_cli-2.3.0b12}/test/test_treecompare_no_cache.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|