scmcp-shared 0.3.0__py3-none-any.whl → 0.3.6__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.
scmcp_shared/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
 
2
- __version__ = "0.3.0"
2
+ __version__ = "0.3.6"
3
3
 
scmcp_shared/cli.py CHANGED
@@ -1,77 +1,89 @@
1
- import typer
2
- from typing import Optional, Union, Type
1
+ import argparse
2
+ from typing import Optional, Union, Type, Dict, Callable
3
3
  from enum import Enum
4
- from .util import add_figure_route, set_env,setup_mcp
5
-
6
-
7
- class TransportEnum(str, Enum):
8
- STDIO = "stdio"
9
- SSE = "sse"
10
- SHTTP = "shttp"
11
-
12
- @property
13
- def transport_value(self) -> str:
14
- """Get the actual transport value to use."""
15
- if self == TransportEnum.SHTTP:
16
- return "streamable-http"
17
- return self.value
18
-
19
-
20
- class ModuleEnum(str, Enum):
21
- """Base class for module types."""
22
- ALL = "all"
23
-
4
+ from .util import add_figure_route, set_env
5
+ import os
24
6
 
25
7
 
26
8
  class MCPCLI:
27
9
  """Base class for CLI applications with support for dynamic modules and parameters."""
28
10
 
29
- def __init__(self, name: str, help_text: str, manager=None, modules=ModuleEnum):
11
+ def __init__(self, name: str, help_text: str, mcp=None, manager=None):
30
12
  self.name = name
31
- self.modules = modules
13
+ self.mcp = mcp
32
14
  self.manager = manager
33
- self.app = typer.Typer(
34
- name=name,
35
- help=help_text,
36
- add_completion=False,
37
- no_args_is_help=True,
15
+ self.parser = argparse.ArgumentParser(
16
+ description=help_text,
17
+ prog=name
38
18
  )
19
+ self.subcommands: Dict[str, tuple[argparse.ArgumentParser, Callable]] = {}
39
20
  self._setup_commands()
40
21
 
41
22
  def _setup_commands(self):
42
23
  """Setup the main commands for the CLI."""
43
- self.app.command(name="run", help="Start the server with the specified configuration")(self.run_command())
44
- self.app.callback()(self._callback)
45
-
46
- def run_command(self):
47
- def _run_command(
48
- log_file: Optional[str] = typer.Option(None, "--log-file", help="log file path, use stdout if None"),
49
- transport: TransportEnum = typer.Option(TransportEnum.STDIO, "-t", "--transport", help="specify transport type",
50
- case_sensitive=False),
51
- port: int = typer.Option(8000, "-p", "--port", help="transport port"),
52
- host: str = typer.Option("127.0.0.1", "--host", help="transport host"),
53
- forward: str = typer.Option(None, "-f", "--forward", help="forward request to another server"),
54
- module: list[self.modules] = typer.Option(
55
- [self.modules.ALL],
56
- "-m",
57
- "--module",
58
- help="specify module to run"
59
- ),
60
- ):
61
- """Start the server with the specified configuration."""
62
- if "all" in module:
63
- modules = None
64
- elif isinstance(module, list) and bool(module):
65
- modules = [m.value for m in module]
66
- self.mcp = self.manager(self.name, include_modules=modules).mcp
67
-
68
- self.run_mcp(log_file, forward, transport, host, port)
69
- return _run_command
24
+ subparsers = self.parser.add_subparsers(dest='command', help='Available commands')
25
+ run_parser = subparsers.add_parser('run', help='Start the server with the specified configuration')
26
+ self._setup_run_command(run_parser)
27
+ self.subcommands['run'] = (run_parser, self._run_command)
70
28
 
71
-
72
- def _callback(self):
73
- """Liana MCP CLI root command."""
74
- pass
29
+ def _setup_run_command(self, parser: argparse.ArgumentParser):
30
+ """Setup run command arguments."""
31
+ parser.add_argument('-t', '--transport', default="stdio",
32
+ choices=["stdio", "shttp", "sse"],
33
+ help='specify transport type')
34
+ parser.add_argument('-p', '--port', type=int, default=8000, help='transport port')
35
+ parser.add_argument('--host', default='127.0.0.1', help='transport host')
36
+ parser.add_argument('-f', '--forward', help='forward request to another server')
37
+ parser.add_argument('-wd', '--working-dir', default=".", help='working directory')
38
+ parser.add_argument('--log-file', help='log file path, use stdout if None')
39
+
40
+ def add_command(self, name: str, help_text: str, handler: Callable) -> argparse.ArgumentParser:
41
+ """add new subcommand
42
+
43
+ Args:
44
+ name: subcommand name
45
+ help_text: help text
46
+ handler: handler function
47
+
48
+ Returns:
49
+ ArgumentParser: parser for the subcommand
50
+ """
51
+ subparsers = self.parser._subparsers._group_actions[0]
52
+ parser = subparsers.add_parser(name, help=help_text)
53
+ self.subcommands[name] = (parser, handler)
54
+ return parser
55
+
56
+ def get_command_parser(self, name: str) -> Optional[argparse.ArgumentParser]:
57
+ """get the parser for the subcommand
58
+
59
+ Args:
60
+ name: subcommand name
61
+
62
+ Returns:
63
+ ArgumentParser: parser for the subcommand, return None if the subcommand does not exist
64
+ """
65
+ if name in self.subcommands:
66
+ return self.subcommands[name][0]
67
+ return None
68
+
69
+ def _run_command(self, args):
70
+ """Start the server with the specified configuration."""
71
+ os.chdir(args.working_dir)
72
+ if hasattr(args, 'module'):
73
+ if "all" in args.module:
74
+ modules = None
75
+ elif isinstance(args.module, list) and bool(args.module):
76
+ modules = args.module
77
+ else:
78
+ modules = None
79
+ if self.manager is not None:
80
+ self.mcp = self.manager(self.name, include_modules=modules).mcp
81
+ elif self.mcp is not None:
82
+ pass
83
+ else:
84
+ raise ValueError("No manager or mcp provided")
85
+ transport = args.transport
86
+ self.run_mcp(args.log_file, args.forward, transport, args.host, args.port)
75
87
 
76
88
  def run_mcp(self, log_file, forward, transport, host, port):
77
89
  set_env(log_file, forward, transport, host, port)
@@ -80,8 +92,8 @@ class MCPCLI:
80
92
  if transport == "stdio":
81
93
  self.mcp.run()
82
94
  elif transport in ["sse", "shttp"]:
95
+ transport = "streamable-http" if transport == "shttp" else transport
83
96
  add_figure_route(self.mcp)
84
- transport = transport.transport_value
85
97
  self.mcp.run(
86
98
  transport=transport,
87
99
  host=host,
@@ -89,8 +101,11 @@ class MCPCLI:
89
101
  log_level="info"
90
102
  )
91
103
 
92
- def run_cli(self, mcp=None, module_dic=None):
104
+ def run(self):
93
105
  """Run the CLI application."""
94
- self.mcp = mcp
95
- self.module_dic = module_dic
96
- self.app()
106
+ args = self.parser.parse_args()
107
+ if args.command in self.subcommands:
108
+ handler = self.subcommands[args.command][1]
109
+ handler(args)
110
+ else:
111
+ self.parser.print_help()
scmcp_shared/schema/io.py CHANGED
@@ -30,9 +30,9 @@ class ReadModel(BaseModel):
30
30
  default=False,
31
31
  description="Assume the first column stores row names. This is only necessary if these are not strings: strings in the first column are automatically assumed to be row names."
32
32
  )
33
- first_column_obs: bool = Field(
34
- default=True,
35
- description="If True, assume the first column stores observations (cell or barcode) names when provide text file. If False, the data will be transposed."
33
+ transpose: bool = Field(
34
+ default=False,
35
+ description="If True, the data will be transposed."
36
36
  )
37
37
  backup_url: str = Field(
38
38
  default=None,
scmcp_shared/schema/tl.py CHANGED
@@ -938,6 +938,11 @@ class PCAModel(BaseModel):
938
938
  gt=0
939
939
  )
940
940
 
941
+ key_added: str = Field(
942
+ default="X_pca",
943
+ description="PCA embedding stored key in adata.obsm."
944
+ )
945
+
941
946
  @field_validator('n_comps', 'chunk_size')
942
947
  def validate_positive_integers(cls, v: Optional[int]) -> Optional[int]:
943
948
  """Validate positive integers"""
scmcp_shared/server/io.py CHANGED
@@ -33,7 +33,7 @@ class ScanpyIOMCP(BaseMCP):
33
33
  elif file.is_file():
34
34
  func_kwargs = filter_args(request, sc.read)
35
35
  adata = sc.read(**func_kwargs)
36
- if not kwargs.get("first_column_obs", True):
36
+ if not kwargs.get("transpose", True):
37
37
  adata = adata.T
38
38
  else:
39
39
  raise FileNotFoundError(f"{kwargs['filename']} does not exist")
@@ -47,8 +47,18 @@ class ScanpyIOMCP(BaseMCP):
47
47
  adata.layers["counts"] = adata.X
48
48
  adata.var_names_make_unique()
49
49
  adata.obs_names_make_unique()
50
+ adata.obs["scmcp_sampleid"] = adinfo.sampleid or ads.active_id
50
51
  ads.set_adata(adata, adinfo=adinfo)
51
- return generate_msg(adinfo, adata, ads)
52
+ return [
53
+ {
54
+ "sampleid": adinfo.sampleid or ads.active_id,
55
+ "adtype": adinfo.adtype,
56
+ "adata": adata,
57
+ "adata.obs_names[:10]": adata.obs_names[:10],
58
+ "adata.var_names[:10]": adata.var_names[:10],
59
+ "notice": "check obs_names and var_names. transpose the data if needed"
60
+ }
61
+ ]
52
62
  except ToolError as e:
53
63
  raise ToolError(e)
54
64
  except Exception as e:
scmcp_shared/server/pp.py CHANGED
@@ -86,12 +86,12 @@ class ScanpyPreprocessingMCP(BaseMCP):
86
86
  if request.var_max is not None:
87
87
  mask = mask & (adata.var[request.var_key] <= request.var_max)
88
88
  adata = adata[:, mask]
89
- if request.highly_variable is not None:
90
- adata = adata[:, adata.var.highly_variable]
89
+ if request.highly_variable:
90
+ adata = adata[:, mask & adata.var.highly_variable]
91
91
  add_op_log(adata, "subset_genes",
92
92
  {
93
- "var_key": request.var_key, "var_value": request.var_value,
94
- "var_min": request.var_min, "var_max": request.var_max, "hpv": request.highly_variable
93
+ "var_key": request.var_key, "var_min": request.var_min, "var_max": request.var_max,
94
+ "hpv": request.highly_variable
95
95
  }, adinfo
96
96
  )
97
97
  ads.set_adata(adata, adinfo=adinfo)
@@ -133,7 +133,7 @@ class ScanpyPreprocessingMCP(BaseMCP):
133
133
  return _calculate_qc_metrics
134
134
 
135
135
  def _tool_log1p(self):
136
- def _log1p(request: Log1PModel, adinfo: self.AdataInfo=self.AdataInfo()):
136
+ def _log1p(request: Log1PModel=Log1PModel(), adinfo: self.AdataInfo=self.AdataInfo()):
137
137
  """Logarithmize the data matrix"""
138
138
  try:
139
139
  result = forward_request("pp_log1p", request, adinfo)
scmcp_shared/server/tl.py CHANGED
@@ -23,7 +23,7 @@ class ScanpyToolsMCP(BaseMCP):
23
23
  super().__init__("ScanpyMCP-TL-Server", include_tools, exclude_tools, AdataInfo)
24
24
 
25
25
  def _tool_tsne(self):
26
- def _tsne(request: TSNEModel, adinfo: self.AdataInfo=self.AdataInfo()):
26
+ def _tsne(request: TSNEModel=TSNEModel(), adinfo: self.AdataInfo=self.AdataInfo()):
27
27
  """t-distributed stochastic neighborhood embedding (t-SNE) for visualization"""
28
28
  try:
29
29
  result = forward_request("tl_tsne", request, adinfo)
@@ -45,7 +45,7 @@ class ScanpyToolsMCP(BaseMCP):
45
45
  return _tsne
46
46
 
47
47
  def _tool_umap(self):
48
- def _umap(request: UMAPModel, adinfo: self.AdataInfo=self.AdataInfo()):
48
+ def _umap(request: UMAPModel=UMAPModel(), adinfo: self.AdataInfo=self.AdataInfo()):
49
49
  """Uniform Manifold Approximation and Projection (UMAP) for visualization"""
50
50
  try:
51
51
  result = forward_request("tl_umap", request, adinfo)
@@ -134,7 +134,7 @@ class ScanpyToolsMCP(BaseMCP):
134
134
  return _embedding_density
135
135
 
136
136
  def _tool_leiden(self):
137
- def _leiden(request: LeidenModel, adinfo: self.AdataInfo=self.AdataInfo()):
137
+ def _leiden(request: LeidenModel=LeidenModel(), adinfo: self.AdataInfo=self.AdataInfo()):
138
138
  """Leiden clustering algorithm for community detection"""
139
139
  try:
140
140
  result = forward_request("tl_leiden", request, adinfo)
@@ -156,7 +156,7 @@ class ScanpyToolsMCP(BaseMCP):
156
156
  return _leiden
157
157
 
158
158
  def _tool_louvain(self):
159
- def _louvain(request: LouvainModel, adinfo: self.AdataInfo=self.AdataInfo()):
159
+ def _louvain(request: LouvainModel=LouvainModel(), adinfo: self.AdataInfo=self.AdataInfo()):
160
160
  """Louvain clustering algorithm for community detection"""
161
161
  try:
162
162
  result = forward_request("tl_louvain", request, adinfo)
@@ -376,7 +376,7 @@ class ScanpyToolsMCP(BaseMCP):
376
376
  return _score_genes_cell_cycle
377
377
 
378
378
  def _tool_pca(self):
379
- def _pca(request: PCAModel, adinfo: self.AdataInfo=self.AdataInfo()):
379
+ def _pca(request: PCAModel=PCAModel(), adinfo: self.AdataInfo=self.AdataInfo()):
380
380
  """Compute PCA (Principal Component Analysis)."""
381
381
  try:
382
382
  result = forward_request("tl_pca", request, adinfo)
@@ -87,7 +87,7 @@ class ScanpyUtilMCP(BaseMCP):
87
87
  return _mark_var
88
88
 
89
89
  def _tool_list_var(self):
90
- def _list_var(request: ListVarModel, adinfo: self.AdataInfo=self.AdataInfo()):
90
+ def _list_var(request: ListVarModel=ListVarModel(), adinfo: self.AdataInfo=self.AdataInfo()):
91
91
  """List key columns in adata.var. It should be called for checking when other tools need var key column names as input."""
92
92
  try:
93
93
  result = forward_request("ul_list_var", request, adinfo)
@@ -95,7 +95,7 @@ class ScanpyUtilMCP(BaseMCP):
95
95
  return result
96
96
  adata = get_ads().get_adata(adinfo=adinfo)
97
97
  columns = list(adata.var.columns)
98
- add_op_log(adata, list_var, {}, adinfo)
98
+ add_op_log(adata, "list_var", {}, adinfo)
99
99
  return columns
100
100
  except ToolError as e:
101
101
  raise ToolError(e)
@@ -115,7 +115,7 @@ class ScanpyUtilMCP(BaseMCP):
115
115
  return result
116
116
  adata = get_ads().get_adata(adinfo=adinfo)
117
117
  columns = list(adata.obs.columns)
118
- add_op_log(adata, list_obs, {}, adinfo)
118
+ add_op_log(adata, "list_obs", {}, adinfo)
119
119
  return columns
120
120
  except ToolError as e:
121
121
  raise ToolError(e)
@@ -135,8 +135,12 @@ class ScanpyUtilMCP(BaseMCP):
135
135
  return result
136
136
  adata = get_ads().get_adata(adinfo=adinfo)
137
137
  var_names = request.var_names
138
- result = {v: v in adata.var_names for v in var_names}
139
- add_op_log(adata, check_var, {"var_names": var_names}, adinfo)
138
+ if adata.raw is not None:
139
+ all_var_names = adata.raw.to_adata().var_names
140
+ else:
141
+ all_var_names = adata.var_names
142
+ result = {v: v in all_var_names for v in var_names}
143
+ add_op_log(adata, "check_var", {"var_names": var_names}, adinfo)
140
144
  return result
141
145
  except ToolError as e:
142
146
  raise ToolError(e)
@@ -157,7 +161,7 @@ class ScanpyUtilMCP(BaseMCP):
157
161
  ads = get_ads()
158
162
  adata = ads.get_adata(adinfo=adinfo)
159
163
  kwargs = {k: v for k, v in request.model_dump().items() if v is not None}
160
- merged_adata = adata.concat(list(ads.adata_dic[dtype].values()), **kwargs)
164
+ merged_adata = adata.concat(ads.adata_dic, **kwargs)
161
165
  ads.adata_dic[dtype] = {}
162
166
  ads.active_id = "merged_adata"
163
167
  add_op_log(merged_adata, ad.concat, kwargs, adinfo)
scmcp_shared/util.py CHANGED
@@ -104,6 +104,10 @@ def savefig(axes, func=None, **kwargs):
104
104
  args = []
105
105
  for k,v in kwargs.items():
106
106
  if isinstance(v, (tuple, list, set)):
107
+ v = v[:3] ## show first 3 elements
108
+ args.append(f"{k}-{'-'.join([str(i) for i in v])}")
109
+ elif isinstance(v, dict):
110
+ v = list(v.keys())[:3] ## show first 3 elements
107
111
  args.append(f"{k}-{'-'.join([str(i) for i in v])}")
108
112
  else:
109
113
  args.append(f"{k}-{v}")
@@ -209,7 +213,7 @@ def get_ads():
209
213
 
210
214
 
211
215
  def generate_msg(adinfo, adata, ads):
212
- return {"sampleid": adinfo.sampleid or ads.active_id, "dtype": adinfo.adtype, "adata": adata}
216
+ return {"sampleid": adinfo.sampleid or ads.active_id, "adtype": adinfo.adtype, "adata": adata}
213
217
 
214
218
 
215
219
  def sc_like_plot(plot_func, adata, request, adinfo, **kwargs):
@@ -260,17 +264,19 @@ def setup_mcp(mcp, sub_mcp_dic, modules=None):
260
264
  return mcp
261
265
 
262
266
  def _update_args(mcp, func, args_dic : dict):
263
- defs = mcp._tool_manager._tools[func].parameters['$defs']
264
- model_names = list(defs.keys())
265
- args_model = model_names[0] if model_names[0] != "AdataModel" else model_names[1]
266
267
  for args, property_dic in args_dic.items():
267
268
  for pk, v in property_dic.items():
268
- for model in model_names:
269
- if args in mcp._tool_manager._tools[func].parameters['$defs'][model]["properties"]:
270
- mcp._tool_manager._tools[func].parameters['$defs'][model]["properties"][args][pk] = v
269
+ mcp._tool_manager._tools[func].parameters["properties"]["request"].setdefault(pk, {})
270
+ mcp._tool_manager._tools[func].parameters["properties"]["request"][pk][args] = v
271
271
 
272
272
 
273
273
  def update_mcp_args(mcp, tool_args : dict):
274
274
  tools = mcp._tool_manager._tools.keys()
275
275
  for tool in tool_args:
276
276
  _update_args(mcp, tool, tool_args[tool])
277
+
278
+
279
+ def check_adata(adata, adinfo, ads):
280
+ sampleid = adinfo.sampleid or ads.active_id
281
+ if sampleid != adata.uns["scmcp_sampleid"]:
282
+ raise ValueError(f"sampleid mismatch: {sampleid} != {adata.uns['scmcp_sampleid']}")
@@ -1,7 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scmcp_shared
3
- Version: 0.3.0
3
+ Version: 0.3.6
4
4
  Summary: A shared function libray for scmcphub
5
+ Project-URL: Homepage, http://scmcphub.org/
6
+ Project-URL: Repository, https://github.com/scmcphub/scmcp-shared
7
+ Project-URL: Documentation, https://docs.scmcphub.org/
5
8
  Author-email: shuang <hsh-me@outlook.com>
6
9
  License: BSD 3-Clause License
7
10
 
@@ -32,10 +35,11 @@ License: BSD 3-Clause License
32
35
  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33
36
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
37
  License-File: LICENSE
38
+ Keywords: AI,agent,bioinformatics,llm,mcp,model context protocol,scRNA-seq,single cell
35
39
  Requires-Python: >=3.10
36
40
  Requires-Dist: fastmcp>=2.3.4
37
41
  Requires-Dist: mcp>=1.8.0
38
- Requires-Dist: pydantic
42
+ Requires-Dist: nest-asyncio
39
43
  Requires-Dist: scanpy
40
44
  Description-Content-Type: text/markdown
41
45
 
@@ -0,0 +1,21 @@
1
+ scmcp_shared/__init__.py,sha256=uRdcgGfRb4TRwNLKx3spJv6bL90b8RrAvcbq2RJ2TFI,24
2
+ scmcp_shared/cli.py,sha256=KYHp5_VE2JVVT4Su57ELzQa1lI2P8Gw0b4ruBP_Dtxk,4396
3
+ scmcp_shared/logging_config.py,sha256=eCuLuyxMmbj8A1E0VqYWoKA5JPTSbo6cmjS4LOyd0RQ,872
4
+ scmcp_shared/util.py,sha256=8_c6WPNpYNoxKpq6tQCC4elCQkWyk3rH-hTe1sqff4A,9535
5
+ scmcp_shared/schema/__init__.py,sha256=Kwkc7kPLjExOlxt1sWEy_5qa96MvOS8sNCMlZa6yRg8,737
6
+ scmcp_shared/schema/io.py,sha256=hmKMr5A8YRtPmGD3pwN9RPA8Urhp1WEMzEaNt7SnD7k,4636
7
+ scmcp_shared/schema/pl.py,sha256=rzE09wHMY3JR56HZc-QfIUUM0fGXRKd-7Dh3CrQrFB0,29547
8
+ scmcp_shared/schema/pp.py,sha256=48F6oKf-I8IZuNQDfq_Lpp3fLLKA4PruqRje_ZrtTyw,21664
9
+ scmcp_shared/schema/tl.py,sha256=DaZUce33OW67h-caK9BW4sD9zhlehmj3mCq1P-3vllM,34407
10
+ scmcp_shared/schema/util.py,sha256=x_2GPsmliHabi9V5C6YEv_M8ZHJsinDZJ6ePWrLPmcI,4815
11
+ scmcp_shared/server/__init__.py,sha256=4KE2Y_gDenF0ZyTGicQW0fTgJfMIQYZfpRP4hQ4rFYs,416
12
+ scmcp_shared/server/base.py,sha256=kaOfi4yHLWr_AdBdpKzDrJiwRmbHF2jbsfI5g2qqgRA,6576
13
+ scmcp_shared/server/io.py,sha256=tBi1D3ItOxuQmuq2fV9c9t9-J7JuaiPMcBB9UT-S-PM,3928
14
+ scmcp_shared/server/pl.py,sha256=HdhjrZfEx-IzCkZ03IGCW-mjUItfNvKdSOFbJ2_-2XQ,14854
15
+ scmcp_shared/server/pp.py,sha256=xWwW5Y5h-XdMYmSZjvACnoY7-4SfjharwI1GB6FcDPQ,15383
16
+ scmcp_shared/server/tl.py,sha256=qmWuSNplJtoa_92ivzAeCeyclGq2sW4Ao71_MHyk3es,18384
17
+ scmcp_shared/server/util.py,sha256=BGYbkbRKABlCgLAstqD1LutJwfiES0GfIOqMSpLw4FI,12205
18
+ scmcp_shared-0.3.6.dist-info/METADATA,sha256=byQeLeLTMtp_77wrbPORvmY4KLVKSRWxpDJW_Yo18PA,2355
19
+ scmcp_shared-0.3.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
20
+ scmcp_shared-0.3.6.dist-info/licenses/LICENSE,sha256=YNr1hpea195yq-wGtB8j-2dGtt7A5G00WENmxa7JGco,1495
21
+ scmcp_shared-0.3.6.dist-info/RECORD,,
@@ -1,21 +0,0 @@
1
- scmcp_shared/__init__.py,sha256=nSn3YFzkE-BAmUSmif33CxdohNxkgmLE9cYFNbjEu_E,24
2
- scmcp_shared/cli.py,sha256=NU31Vv-xev8yGtl1KHZhVswJNbK18x2AVzhhH9MR03M,3325
3
- scmcp_shared/logging_config.py,sha256=eCuLuyxMmbj8A1E0VqYWoKA5JPTSbo6cmjS4LOyd0RQ,872
4
- scmcp_shared/util.py,sha256=vxmR6_iOBa5jaBNBWl3QBysJ14kXRrqrENDRl3_TChQ,9339
5
- scmcp_shared/schema/__init__.py,sha256=Kwkc7kPLjExOlxt1sWEy_5qa96MvOS8sNCMlZa6yRg8,737
6
- scmcp_shared/schema/io.py,sha256=ZKJpKkKazDE3_ZX3GtMIT08kSaiNmy0qVaxivhN7Dx4,4744
7
- scmcp_shared/schema/pl.py,sha256=rzE09wHMY3JR56HZc-QfIUUM0fGXRKd-7Dh3CrQrFB0,29547
8
- scmcp_shared/schema/pp.py,sha256=48F6oKf-I8IZuNQDfq_Lpp3fLLKA4PruqRje_ZrtTyw,21664
9
- scmcp_shared/schema/tl.py,sha256=0HlZ_WQkgnc93LfIYapRCijWBBaFAdM5SV3Ioht_1wI,34281
10
- scmcp_shared/schema/util.py,sha256=x_2GPsmliHabi9V5C6YEv_M8ZHJsinDZJ6ePWrLPmcI,4815
11
- scmcp_shared/server/__init__.py,sha256=4KE2Y_gDenF0ZyTGicQW0fTgJfMIQYZfpRP4hQ4rFYs,416
12
- scmcp_shared/server/base.py,sha256=kaOfi4yHLWr_AdBdpKzDrJiwRmbHF2jbsfI5g2qqgRA,6576
13
- scmcp_shared/server/io.py,sha256=yrQXdkAsPvk_62xQk5-SRmc5-jAvI-d3sE0QqHDXfMM,3424
14
- scmcp_shared/server/pl.py,sha256=HdhjrZfEx-IzCkZ03IGCW-mjUItfNvKdSOFbJ2_-2XQ,14854
15
- scmcp_shared/server/pp.py,sha256=neyRV3yEZ2a08eO-COI-t-PFFvntRzNmu19SQ77do_4,15406
16
- scmcp_shared/server/tl.py,sha256=2vfl5FrWQgQlPTB4-QLFMuMrtCux6ppmFttKOrryhF0,18320
17
- scmcp_shared/server/util.py,sha256=L51fFL7Nb84JCQrFYyZIGsfmNFlA9uGzTV93hvc9mfI,12025
18
- scmcp_shared-0.3.0.dist-info/METADATA,sha256=M8NokyJHPjAVnN-JYmprlFhAfDq_XvAAU1l-kiH8LOA,2099
19
- scmcp_shared-0.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
20
- scmcp_shared-0.3.0.dist-info/licenses/LICENSE,sha256=YNr1hpea195yq-wGtB8j-2dGtt7A5G00WENmxa7JGco,1495
21
- scmcp_shared-0.3.0.dist-info/RECORD,,