dasmixer-cli 0.6.0a2__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,3 @@
1
+ """CLI package for DASMixer."""
2
+
3
+ # CLI implementation will be added in stage 3
@@ -0,0 +1,3 @@
1
+ """CLI command modules."""
2
+
3
+ __all__ = ['project', 'subset', 'import_data']
@@ -0,0 +1,269 @@
1
+ """CLI commands for importing data files."""
2
+
3
+ import typer
4
+ from pathlib import Path
5
+ import asyncio
6
+ from typing import Annotated
7
+ from dasmixer.api.project.project import Project
8
+ from dasmixer.api.inputs.registry import registry
9
+ from dasmixer.api.config import config
10
+ from dasmixer.utils.seek_files import seek_files
11
+
12
+ app = typer.Typer(help="Import data files")
13
+
14
+
15
+ @app.command()
16
+ def mgf_pattern(
17
+ project_path: Annotated[str, typer.Argument(help="Path to .dasmix project file")],
18
+ folder: Annotated[str, typer.Option("--folder", "-f", help="Folder to search")] = ...,
19
+ file_pattern: Annotated[str, typer.Option("--pattern", "-p", help="File pattern (e.g., *.mgf)")] = "*.mgf",
20
+ id_pattern: Annotated[str, typer.Option("--id-pattern", "-i", help="Sample ID pattern (e.g., {id}_*.mgf)")] = "{id}*.mgf",
21
+ parser: Annotated[str, typer.Option("--parser", help="Parser name")] = "MGF",
22
+ group: Annotated[str, typer.Option("--group", "-g", help="Group to assign samples")] = "Control"
23
+ ):
24
+ """
25
+ Import MGF files using pattern matching.
26
+
27
+ Example:
28
+ dasmixer project.dasmix import mgf-pattern \\
29
+ --folder /data/spectra \\
30
+ --pattern "*.mgf" \\
31
+ --id-pattern "{id}_run*.mgf" \\
32
+ --group Control
33
+ """
34
+ project_path = Path(project_path)
35
+
36
+ if not project_path.exists():
37
+ typer.echo(f"Error: Project file not found: {project_path}", err=True)
38
+ raise typer.Exit(1)
39
+
40
+ folder_path = Path(folder)
41
+ if not folder_path.exists():
42
+ typer.echo(f"Error: Folder not found: {folder}", err=True)
43
+ raise typer.Exit(1)
44
+
45
+ # Find files
46
+ try:
47
+ files = seek_files(folder_path, file_pattern, id_pattern)
48
+ except Exception as e:
49
+ typer.echo(f"Error searching files: {e}", err=True)
50
+ raise typer.Exit(1)
51
+
52
+ if not files:
53
+ typer.echo("No files found matching pattern", err=True)
54
+ raise typer.Exit(1)
55
+
56
+ # Show found files
57
+ typer.echo(f"\nFound {len(files)} file(s):")
58
+ typer.echo("-" * 60)
59
+ for file_path, sample_id in files:
60
+ display_id = sample_id or "UNKNOWN"
61
+ typer.echo(f" {file_path.name} → Sample ID: {display_id}")
62
+
63
+ if not typer.confirm("\nProceed with import?"):
64
+ typer.echo("Cancelled")
65
+ raise typer.Exit(0)
66
+
67
+ # Get parser
68
+ try:
69
+ parser_class = registry.get_parser(parser, "spectra")
70
+ except KeyError as e:
71
+ typer.echo(f"Error: {e}", err=True)
72
+ raise typer.Exit(1)
73
+
74
+ # Import files
75
+ async def _import():
76
+ async with Project(path=project_path, create_if_not_exists=False) as project:
77
+ # Get or create group
78
+ subsets = await project.get_subsets()
79
+ subset = next((s for s in subsets if s.name == group), None)
80
+
81
+ if not subset:
82
+ subset = await project.add_subset(group)
83
+ typer.echo(f"✓ Created group: {group}")
84
+
85
+ # Import with progress
86
+ with typer.progressbar(
87
+ files,
88
+ label="Importing",
89
+ show_pos=True
90
+ ) as progress:
91
+ for file_path, sample_id in progress:
92
+ # Use filename as sample_id if not detected
93
+ if not sample_id:
94
+ sample_id = file_path.stem
95
+
96
+ try:
97
+ # Parse file
98
+ parser_instance = parser_class(str(file_path))
99
+ spectra_df = await parser_instance.parse_batch()
100
+
101
+ # Add sample if not exists
102
+ sample = await project.get_sample_by_name(sample_id)
103
+ if not sample:
104
+ sample = await project.add_sample(
105
+ sample_id,
106
+ subset_id=subset.id
107
+ )
108
+
109
+ # Add spectra file
110
+ spectra_file_id = await project.add_spectra_file(
111
+ sample.id,
112
+ parser,
113
+ str(file_path)
114
+ )
115
+
116
+ # Add spectra
117
+ await project.add_spectra_batch(spectra_file_id, spectra_df)
118
+
119
+ except Exception as e:
120
+ typer.echo(f"\n Error importing {file_path.name}: {e}", err=True)
121
+
122
+ typer.echo(f"\n✓ Imported {len(files)} file(s) successfully")
123
+
124
+ try:
125
+ asyncio.run(_import())
126
+ config.update_last_import_folder(folder)
127
+ except Exception as e:
128
+ typer.echo(f"\nError during import: {e}", err=True)
129
+ raise typer.Exit(1)
130
+
131
+
132
+ @app.command()
133
+ def mgf_file(
134
+ project_path: Annotated[str, typer.Argument(help="Path to .dasmix project file")],
135
+ file: Annotated[str, typer.Option("--file", "-f", help="Path to MGF file")] = ...,
136
+ sample_id: Annotated[str, typer.Option("--sample-id", "-s", help="Sample ID")] = ...,
137
+ parser: Annotated[str, typer.Option("--parser", help="Parser name")] = "MGF",
138
+ group: Annotated[str, typer.Option("--group", "-g", help="Group to assign sample")] = "Control"
139
+ ):
140
+ """
141
+ Import single MGF file.
142
+
143
+ Example:
144
+ dasmixer project.dasmix import mgf-file \\
145
+ --file /data/sample1.mgf \\
146
+ --sample-id "Sample1" \\
147
+ --group Control
148
+ """
149
+ project_path = Path(project_path)
150
+ file_path = Path(file)
151
+
152
+ if not project_path.exists():
153
+ typer.echo(f"Error: Project file not found: {project_path}", err=True)
154
+ raise typer.Exit(1)
155
+
156
+ if not file_path.exists():
157
+ typer.echo(f"Error: File not found: {file}", err=True)
158
+ raise typer.Exit(1)
159
+
160
+ # Get parser
161
+ try:
162
+ parser_class = registry.get_parser(parser, "spectra")
163
+ except KeyError as e:
164
+ typer.echo(f"Error: {e}", err=True)
165
+ raise typer.Exit(1)
166
+
167
+ # Import file
168
+ async def _import():
169
+ async with Project(path=project_path, create_if_not_exists=False) as project:
170
+ # Get or create group
171
+ subsets = await project.get_subsets()
172
+ subset = next((s for s in subsets if s.name == group), None)
173
+
174
+ if not subset:
175
+ subset = await project.add_subset(group)
176
+ typer.echo(f"✓ Created group: {group}")
177
+
178
+ typer.echo(f"Importing {file_path.name}...")
179
+
180
+ # Parse file
181
+ parser_instance = parser_class(str(file_path))
182
+ spectra_df = await parser_instance.parse_batch()
183
+
184
+ # Add sample if not exists
185
+ sample = await project.get_sample_by_name(sample_id)
186
+ if not sample:
187
+ sample = await project.add_sample(
188
+ sample_id,
189
+ subset_id=subset.id
190
+ )
191
+
192
+ # Add spectra file
193
+ spectra_file_id = await project.add_spectra_file(
194
+ sample.id,
195
+ parser,
196
+ str(file_path)
197
+ )
198
+
199
+ # Add spectra
200
+ await project.add_spectra_batch(spectra_file_id, spectra_df)
201
+
202
+ typer.echo(f"✓ Imported {len(spectra_df)} spectra from {file_path.name}")
203
+ typer.echo(f" Sample: {sample_id}")
204
+ typer.echo(f" Group: {group}")
205
+
206
+ try:
207
+ asyncio.run(_import())
208
+ config.update_last_import_folder(str(file_path.parent))
209
+ except Exception as e:
210
+ typer.echo(f"Error importing file: {e}", err=True)
211
+ raise typer.Exit(1)
212
+
213
+
214
+ # Note: ident-pattern and ident-file commands will be similar but for identifications
215
+ # They require knowledge of which tool and spectra file to link to
216
+ # Implementation will be added when identification parsers are registered
217
+
218
+ @app.command()
219
+ def ident_pattern(
220
+ project_path: Annotated[str, typer.Argument(help="Path to .dasmix project file")],
221
+ folder: Annotated[str, typer.Option("--folder", "-f", help="Folder to search")] = ...,
222
+ file_pattern: Annotated[str, typer.Option("--pattern", "-p", help="File pattern")] = "*.csv",
223
+ id_pattern: Annotated[str, typer.Option("--id-pattern", "-i", help="Sample ID pattern")] = "{id}*.csv",
224
+ parser: Annotated[str, typer.Option("--parser", help="Parser name (e.g., PowerNovo2)")] = ...,
225
+ tool: Annotated[str, typer.Option("--tool", help="Tool name (will be created if not exists)")] = ...
226
+ ):
227
+ """
228
+ Import identification files using pattern matching.
229
+
230
+ Note: This command requires that corresponding spectra files
231
+ are already imported for the samples.
232
+
233
+ Example:
234
+ dasmixer project.dasmix import ident-pattern \\
235
+ --folder /data/results \\
236
+ --pattern "*.csv" \\
237
+ --id-pattern "{id}_powernovo.csv" \\
238
+ --parser PowerNovo2 \\
239
+ --tool PowerNovo2
240
+ """
241
+ typer.echo("This command will be implemented when identification parsers are ready.")
242
+ typer.echo("Coming in next development phase.")
243
+ raise typer.Exit(0)
244
+
245
+
246
+ @app.command()
247
+ def ident_file(
248
+ project_path: Annotated[str, typer.Argument(help="Path to .dasmix project file")],
249
+ file: Annotated[str, typer.Option("--file", "-f", help="Path to identification file")] = ...,
250
+ sample_id: Annotated[str, typer.Option("--sample-id", "-s", help="Sample ID")] = ...,
251
+ parser: Annotated[str, typer.Option("--parser", help="Parser name")] = ...,
252
+ tool: Annotated[str, typer.Option("--tool", help="Tool name")] = ...
253
+ ):
254
+ """
255
+ Import single identification file.
256
+
257
+ Note: This command requires that corresponding spectra file
258
+ is already imported for the sample.
259
+
260
+ Example:
261
+ dasmixer project.dasmix import ident-file \\
262
+ --file /data/sample1_powernovo.csv \\
263
+ --sample-id "Sample1" \\
264
+ --parser PowerNovo2 \\
265
+ --tool PowerNovo2
266
+ """
267
+ typer.echo("This command will be implemented when identification parsers are ready.")
268
+ typer.echo("Coming in next development phase.")
269
+ raise typer.Exit(0)
@@ -0,0 +1,75 @@
1
+ """CLI command for importing/merging another project."""
2
+
3
+ import typer
4
+ from pathlib import Path
5
+ from typing import Annotated
6
+ import asyncio
7
+ from dasmixer.api.project.project import Project
8
+
9
+ app = typer.Typer(help="Merge another project into this one")
10
+
11
+
12
+ @app.command()
13
+ def import_project(
14
+ project_path: Annotated[str, typer.Argument(help="Target project (.dasmix)")],
15
+ source_path: Annotated[str, typer.Argument(help="Source project to import from (.dasmix)")],
16
+ tool_match: Annotated[str, typer.Option(help="Tool merge strategy: 'parser'|'name'|'none'")] = "parser",
17
+ no_subset_match: Annotated[bool, typer.Option("--no-subset-match", help="Do not merge subsets by name")] = False,
18
+ no_sample_match: Annotated[bool, typer.Option("--no-sample-match", help="Do not merge samples by name")] = False,
19
+ update_settings: Annotated[bool, typer.Option("--update-settings", help="Replace target settings with source")] = False,
20
+ conflict_suffix: Annotated[str, typer.Option(help="Suffix for conflicting names")] = "_1",
21
+ ):
22
+ """Merge another project into target project."""
23
+ tgt = Path(project_path)
24
+ src = Path(source_path)
25
+
26
+ if not tgt.exists():
27
+ typer.echo(f"Error: target project not found: {tgt}", err=True)
28
+ raise typer.Exit(1)
29
+
30
+ if not src.exists():
31
+ typer.echo(f"Error: source project not found: {src}", err=True)
32
+ raise typer.Exit(1)
33
+
34
+ # Convert tool_match
35
+ if tool_match == "none":
36
+ tool_match_value = None
37
+ elif tool_match == "name":
38
+ tool_match_value = "name"
39
+ else:
40
+ tool_match_value = "parser"
41
+
42
+ # Show summary
43
+ typer.echo(f"Target: {tgt}")
44
+ typer.echo(f"Source: {src}")
45
+ typer.echo(f"Tool match: {tool_match_value}")
46
+ typer.echo(f"Merge subsets: {not no_subset_match}")
47
+ typer.echo(f"Merge samples: {not no_sample_match}")
48
+ typer.echo(f"Update settings: {update_settings}")
49
+ typer.echo(f"Conflict suffix: {conflict_suffix}")
50
+
51
+ if not typer.confirm("Proceed with merge?"):
52
+ typer.echo("Cancelled")
53
+ raise typer.Exit(0)
54
+
55
+ async def _run():
56
+ async with Project(path=tgt, create_if_not_exists=False) as project:
57
+ def status_callback(table: str, fraction: float):
58
+ typer.echo(f" [{fraction*100:3.0f}%] Importing {table}...")
59
+
60
+ await project.import_project(
61
+ source_path=src,
62
+ tool_match=tool_match_value,
63
+ subset_match=not no_subset_match,
64
+ sample_match=not no_sample_match,
65
+ project_settings_match=update_settings,
66
+ conflict_suffix=conflict_suffix,
67
+ status_callback=status_callback,
68
+ )
69
+
70
+ try:
71
+ asyncio.run(_run())
72
+ typer.echo("✓ Import complete")
73
+ except Exception as e:
74
+ typer.echo(f"Error during import: {e}", err=True)
75
+ raise typer.Exit(1)
@@ -0,0 +1,54 @@
1
+ """CLI commands for portable project utilities (checkpoint, vacuum)."""
2
+
3
+ import typer
4
+ from pathlib import Path
5
+ from typing import Annotated
6
+ import asyncio
7
+ from dasmixer.api.project.project import Project
8
+
9
+ app = typer.Typer(help="Portable project utilities")
10
+
11
+
12
+ @app.command()
13
+ def checkpoint(
14
+ project_path: Annotated[str, typer.Argument(help="Path to .dasmix project file")],
15
+ ):
16
+ """Save uncommitted WAL changes into the main database file."""
17
+ path = Path(project_path)
18
+ if not path.exists():
19
+ typer.echo(f"Error: file not found: {path}", err=True)
20
+ raise typer.Exit(1)
21
+
22
+ async def _run():
23
+ async with Project(path=path, create_if_not_exists=False) as project:
24
+ await project.save(checkpoint=True)
25
+
26
+ try:
27
+ asyncio.run(_run())
28
+ typer.echo(f"✓ Checkpoint done: {path}")
29
+ except Exception as e:
30
+ typer.echo(f"Error during checkpoint: {e}", err=True)
31
+ raise typer.Exit(1)
32
+
33
+
34
+ @app.command()
35
+ def vacuum(
36
+ project_path: Annotated[str, typer.Argument(help="Path to .dasmix project file")],
37
+ ):
38
+ """Compact the database file by running SQLite VACUUM."""
39
+ path = Path(project_path)
40
+ if not path.exists():
41
+ typer.echo(f"Error: file not found: {path}", err=True)
42
+ raise typer.Exit(1)
43
+
44
+ async def _run():
45
+ async with Project(path=path, create_if_not_exists=False) as project:
46
+ await project.save(checkpoint=True)
47
+ await project.vacuum()
48
+
49
+ try:
50
+ asyncio.run(_run())
51
+ typer.echo(f"✓ Vacuum complete: {path}")
52
+ except Exception as e:
53
+ typer.echo(f"Error during vacuum: {e}", err=True)
54
+ raise typer.Exit(1)
@@ -0,0 +1,49 @@
1
+ """CLI commands for project management."""
2
+
3
+ import typer
4
+ from pathlib import Path
5
+ from typing import Annotated
6
+ import asyncio
7
+ from dasmixer.api.project.project import Project
8
+ from dasmixer.api.config import config
9
+
10
+ app = typer.Typer(help="Create new project")
11
+
12
+
13
+ @app.callback(invoke_without_command=True)
14
+ def create_project(
15
+ ctx: typer.Context,
16
+ project_path: Annotated[
17
+ str,
18
+ typer.Argument(help="Path to .dasmix project file to create"),
19
+ ],
20
+ ):
21
+ """
22
+ Create new empty project with default Control group.
23
+ """
24
+ path = Path(project_path)
25
+
26
+ # Check if file exists
27
+ if path.exists():
28
+ if not typer.confirm(f"File {path} exists. Overwrite?"):
29
+ typer.echo("Cancelled")
30
+ raise typer.Exit(0)
31
+ path.unlink()
32
+
33
+ # Create project
34
+ async def _create():
35
+ async with Project(path=path, create_if_not_exists=True) as project:
36
+ await project.add_subset(
37
+ "Control",
38
+ details="Default control group",
39
+ display_color="#3B82F6",
40
+ )
41
+ typer.echo(f"✓ Created project: {path}")
42
+ typer.echo("✓ Added default group: Control")
43
+
44
+ try:
45
+ asyncio.run(_create())
46
+ config.add_recent_project(str(path))
47
+ except Exception as e:
48
+ typer.echo(f"Error creating project: {e}", err=True)
49
+ raise typer.Exit(1)
@@ -0,0 +1,130 @@
1
+ """CLI commands for managing comparison groups (subsets)."""
2
+
3
+ import typer
4
+ from pathlib import Path
5
+ import asyncio
6
+ from dasmixer.api.project.project import Project
7
+ from typing import Annotated
8
+
9
+ app = typer.Typer(help="Manage comparison groups")
10
+
11
+
12
+ @app.command()
13
+ def add(
14
+ project_path: Annotated[str, typer.Argument(help="Path to .dasmix project file")],
15
+ name: Annotated[str, typer.Option("--name", "-n", help="Group name")] = ...,
16
+ details: Annotated[
17
+ str | None,
18
+ typer.Option("--details", "-d", help="Group description")
19
+ ] = None,
20
+ color: Annotated[
21
+ str | None,
22
+ typer.Option("--color", "-c", help="Display color (hex, e.g., #FF5733)")
23
+ ] = None
24
+ ):
25
+ """Add new comparison group to project."""
26
+ project_path = Path(project_path)
27
+
28
+ if not project_path.exists():
29
+ typer.echo(f"Error: Project file not found: {project_path}", err=True)
30
+ raise typer.Exit(1)
31
+
32
+ async def _add():
33
+ async with Project(path=project_path, create_if_not_exists=False) as project:
34
+ subset = await project.add_subset(name, details, color)
35
+ typer.echo(f"✓ Added group: {subset.name} (id={subset.id})")
36
+ if details:
37
+ typer.echo(f" Description: {details}")
38
+ if color:
39
+ typer.echo(f" Color: {color}")
40
+
41
+ try:
42
+ asyncio.run(_add())
43
+ except ValueError as e:
44
+ typer.echo(f"Error: {e}", err=True)
45
+ raise typer.Exit(1)
46
+ except Exception as e:
47
+ typer.echo(f"Error adding group: {e}", err=True)
48
+ raise typer.Exit(1)
49
+
50
+
51
+ @app.command()
52
+ def delete(
53
+ project_path: Annotated[str, typer.Argument(help="Path to .dasmix project file")],
54
+ name: Annotated[str, typer.Option("--name", "-n", help="Group name to delete")] = ...
55
+ ):
56
+ """Delete comparison group from project."""
57
+ project_path = Path(project_path)
58
+
59
+ if not project_path.exists():
60
+ typer.echo(f"Error: Project file not found: {project_path}", err=True)
61
+ raise typer.Exit(1)
62
+
63
+ async def _delete():
64
+ async with Project(path=project_path, create_if_not_exists=False) as project:
65
+ # Find subset by name
66
+ subsets = await project.get_subsets()
67
+ subset = next((s for s in subsets if s.name == name), None)
68
+
69
+ if not subset:
70
+ typer.echo(f"Error: Group '{name}' not found", err=True)
71
+ raise typer.Exit(1)
72
+
73
+ # Confirm deletion
74
+ if not typer.confirm(f"Delete group '{name}'?"):
75
+ typer.echo("Cancelled")
76
+ raise typer.Exit(0)
77
+
78
+ await project.delete_subset(subset.id)
79
+ typer.echo(f"✓ Deleted group: {name}")
80
+
81
+ try:
82
+ asyncio.run(_delete())
83
+ except ValueError as e:
84
+ typer.echo(f"Error: {e}", err=True)
85
+ raise typer.Exit(1)
86
+ except typer.Exit:
87
+ raise
88
+ except Exception as e:
89
+ typer.echo(f"Error deleting group: {e}", err=True)
90
+ raise typer.Exit(1)
91
+
92
+
93
+ @app.command("list")
94
+ def list_subsets(
95
+ project_path: Annotated[str, typer.Argument(help="Path to .dasmix project file")]
96
+ ):
97
+ """List all comparison groups in project."""
98
+ project_path = Path(project_path)
99
+
100
+ if not project_path.exists():
101
+ typer.echo(f"Error: Project file not found: {project_path}", err=True)
102
+ raise typer.Exit(1)
103
+
104
+ async def _list():
105
+ async with Project(path=project_path, create_if_not_exists=False) as project:
106
+ subsets = await project.get_subsets()
107
+
108
+ if not subsets:
109
+ typer.echo("No groups found in project")
110
+ return
111
+
112
+ typer.echo("\nComparison Groups:")
113
+ typer.echo("=" * 60)
114
+
115
+ for subset in subsets:
116
+ typer.echo(f"\n{subset.name} (ID: {subset.id})")
117
+ if subset.details:
118
+ typer.echo(f" Description: {subset.details}")
119
+ if subset.display_color:
120
+ typer.echo(f" Color: {subset.display_color}")
121
+
122
+ # Count samples in this group
123
+ samples = await project.get_samples(subset_id=subset.id)
124
+ typer.echo(f" Samples: {len(samples)}")
125
+
126
+ try:
127
+ asyncio.run(_list())
128
+ except Exception as e:
129
+ typer.echo(f"Error listing groups: {e}", err=True)
130
+ raise typer.Exit(1)
dasmixer/cli/main.py ADDED
@@ -0,0 +1,47 @@
1
+ """
2
+ DASMixer CLI — entry point for the `dasmixer-cli` command.
3
+
4
+ Provides command-line tools for project management without GUI.
5
+ """
6
+
7
+ import typer
8
+ from typing import Annotated
9
+ from pathlib import Path
10
+
11
+ from dasmixer.versions import APP_VERSION
12
+ from dasmixer.cli.commands import project, subset, import_data
13
+ from dasmixer.cli.commands import portable
14
+ from dasmixer.cli.commands import import_project as import_project_cmd
15
+
16
+ app = typer.Typer(
17
+ name="dasmixer-cli",
18
+ help="DASMixer CLI — manage projects without GUI",
19
+ add_completion=False,
20
+ )
21
+
22
+
23
+ @app.callback(invoke_without_command=True)
24
+ def main(
25
+ ctx: typer.Context,
26
+ version: Annotated[
27
+ bool,
28
+ typer.Option("--version", "-v", help="Show version and exit"),
29
+ ] = False,
30
+ ):
31
+ """DASMixer CLI — управление проектами без GUI."""
32
+ if version:
33
+ typer.echo(f"DASMixer CLI {APP_VERSION}")
34
+ raise typer.Exit(0)
35
+ if ctx.invoked_subcommand is None:
36
+ typer.echo(ctx.get_help())
37
+
38
+
39
+ app.add_typer(project.app, name="create", help="Create new project")
40
+ app.add_typer(subset.app, name="subset", help="Manage comparison groups")
41
+ app.add_typer(import_data.app, name="import", help="Import data files")
42
+ app.add_typer(portable.app, name="checkpoint", help="Save WAL to database file")
43
+ app.add_typer(portable.app, name="vacuum", help="Compact database file")
44
+ app.add_typer(import_project_cmd.app, name="import-project", help="Merge another project into this one")
45
+
46
+ if __name__ == "__main__":
47
+ app()
@@ -0,0 +1,51 @@
1
+ Metadata-Version: 2.4
2
+ Name: dasmixer-cli
3
+ Version: 0.6.0a2
4
+ Summary: DASMixer CLI — command-line tools for project management
5
+ Author: gluck
6
+ Author-email: glucksistemi@gmail.com
7
+ Requires-Python: <4.0, >=3.11
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Programming Language :: Python :: 3.14
13
+ Requires-Dist: dasmixer-core (==0.5.0)
14
+ Project-URL: Homepage, https://github.com/protdb/dasmixer
15
+ Description-Content-Type: text/markdown
16
+
17
+ # DASMixer CLI
18
+
19
+ Command-line tools for managing DASMixer projects without a graphical interface.
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ pip install dasmixer-cli
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ```bash
30
+ dasmixer-cli --help
31
+ dasmixer-cli create path/to/project.dasmix
32
+ dasmixer-cli subset list path/to/project.dasmix
33
+ dasmixer-cli subset add path/to/project.dasmix --name "Treatment" --color "#FF5733"
34
+ dasmixer-cli import mgf-file path/to/project.dasmix --sample "Sample1" --file spectra.mgf
35
+ dasmixer-cli import mgf-pattern path/to/project.dasmix --sample "Sample1" --folder ./spectra/ --pattern "*.mgf"
36
+ ```
37
+
38
+ ## Commands
39
+
40
+ | Command | Description |
41
+ |---|---|
42
+ | `create <project>` | Create a new empty project |
43
+ | `subset list <project>` | List comparison groups |
44
+ | `subset add <project> --name` | Add a comparison group |
45
+ | `subset delete <project> --name` | Delete a comparison group |
46
+ | `import mgf-file <project>` | Import a single MGF file |
47
+ | `import mgf-pattern <project>` | Batch import MGF files by pattern |
48
+ | `import ident-file <project>` | Import an identification file |
49
+ | `import ident-pattern <project>` | Batch import identification files |
50
+
51
+ Documentation: https://github.com/protdb/dasmixer
@@ -0,0 +1,12 @@
1
+ dasmixer/cli/__init__.py,sha256=gR3zobxDodV8MRqOYZi5q79IfxtsZiJc8Kuh85cIFCs,79
2
+ dasmixer/cli/commands/__init__.py,sha256=UUXhyaTxmBs62aQzk21wEnjbeV7ieB8WI6yEonAg_yE,75
3
+ dasmixer/cli/commands/import_data.py,sha256=h1VflVla2xSStURSMaOFkf5WIAanjhD_DX0H8UuIgOU,10259
4
+ dasmixer/cli/commands/import_project.py,sha256=XmeLNGVa_yzyg_VBjXzcD0aIu28qe-eSOhfk_7LVSzw,2924
5
+ dasmixer/cli/commands/portable.py,sha256=s8wG0tc25paW4f6Clhem7T4RKB4stQNROUsWdrG9-4I,1665
6
+ dasmixer/cli/commands/project.py,sha256=GoIXrZljp3U0vZFGE4AvncqEEaeBVBXy6w0LE0fYeDQ,1389
7
+ dasmixer/cli/commands/subset.py,sha256=qUL25wsVD3iCph1uPyIy1THBim7tN6sKDiY9X3vpDtc,4463
8
+ dasmixer/cli/main.py,sha256=Kq7Nu4rd-B_K6C6wcMNv5DiXkL3aFb5uf8ArbNXOtPA,1518
9
+ dasmixer_cli-0.6.0a2.dist-info/METADATA,sha256=74ZauIAkmuCi7-HzWN7pX22rZgnhX-4yg5HByOyVKWo,1768
10
+ dasmixer_cli-0.6.0a2.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
11
+ dasmixer_cli-0.6.0a2.dist-info/entry_points.txt,sha256=a4KExsoM5TAa1-M7059iMIH3u9VerPOAyCF4mQz-so0,54
12
+ dasmixer_cli-0.6.0a2.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 2.2.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ dasmixer-cli=dasmixer.cli.main:app
3
+