opencue-cuecmd 1.13.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.
cuecmd/__init__.py ADDED
@@ -0,0 +1,33 @@
1
+ # Copyright Contributors to the OpenCue Project
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ """OpenCue Cuecmd command execution tool."""
17
+
18
+ try:
19
+ from importlib.metadata import PackageNotFoundError, version
20
+
21
+ try:
22
+ __version__ = version("opencue_cuecmd")
23
+ except PackageNotFoundError:
24
+ # Package is not installed
25
+ __version__ = "1.0.0"
26
+ except ImportError:
27
+ # Python < 3.8
28
+ try:
29
+ import pkg_resources
30
+
31
+ __version__ = pkg_resources.get_distribution("opencue_cuecmd").version
32
+ except Exception:
33
+ __version__ = "1.0.0"
cuecmd/__main__.py ADDED
@@ -0,0 +1,41 @@
1
+ # Copyright Contributors to the OpenCue Project
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ """Entrypoint for Cuecmd tool."""
17
+
18
+
19
+ from __future__ import absolute_import, division, print_function
20
+
21
+ import logging
22
+ import sys
23
+ import warnings
24
+
25
+ from cuecmd import main as opencuecmd
26
+
27
+ # Suppress protobuf version warnings
28
+ warnings.filterwarnings(
29
+ "ignore", category=UserWarning, module="google.protobuf.runtime_version"
30
+ )
31
+
32
+ logger = logging.getLogger("opencue.tools.cuecmd")
33
+
34
+
35
+ def main():
36
+ """Main entry point for cuecmd."""
37
+ opencuecmd.main(sys.argv)
38
+
39
+
40
+ if __name__ == "__main__":
41
+ main()
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Copyright Contributors to the OpenCue Project
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ """Helper script to execute commands from a file based on frame number and chunk size."""
18
+
19
+ import argparse
20
+ import subprocess
21
+ import sys
22
+
23
+
24
+ def main():
25
+ """Execute commands from a file based on frame number and chunk size."""
26
+ parser = argparse.ArgumentParser(
27
+ description="Execute commands from a file based on frame number and chunk size."
28
+ )
29
+ parser.add_argument("command_file", help="Path to the file containing commands")
30
+ parser.add_argument(
31
+ "chunk_size", type=int, help="Number of commands to execute per frame"
32
+ )
33
+ parser.add_argument(
34
+ "--frame", type=int, required=True, help="Frame number to execute"
35
+ )
36
+
37
+ args = parser.parse_args()
38
+
39
+ # Read all commands from the file
40
+ with open(args.command_file, "r", encoding="utf-8") as f:
41
+ commands = [line.strip() for line in f if line.strip()]
42
+
43
+ # Calculate which commands to run for this frame
44
+ start_idx = (args.frame - 1) * args.chunk_size
45
+ end_idx = min(start_idx + args.chunk_size, len(commands))
46
+
47
+ if start_idx >= len(commands):
48
+ print(f"Frame {args.frame} is beyond the available commands")
49
+ return 0
50
+
51
+ # Execute each command in the chunk
52
+ for idx in range(start_idx, end_idx):
53
+ cmd = commands[idx]
54
+ print(f"Executing command {idx + 1}: {cmd}")
55
+
56
+ # Execute the command
57
+ result = subprocess.run(cmd, shell=True, check=False)
58
+
59
+ if result.returncode != 0:
60
+ print(f"Command failed with return code {result.returncode}: {cmd}")
61
+ sys.exit(result.returncode)
62
+
63
+ return 0
64
+
65
+
66
+ if __name__ == "__main__":
67
+ main()
cuecmd/main.py ADDED
@@ -0,0 +1,239 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Copyright Contributors to the OpenCue Project
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ """
18
+ Cuecmd - Execute a list of commands on the OpenCue render farm.
19
+
20
+ This tool reads a file containing a list of commands and submits them as
21
+ frames to be executed on the render farm. Commands can be chunked together
22
+ to run multiple commands per frame.
23
+ """
24
+
25
+ import argparse
26
+ import math
27
+ import os
28
+ import shutil
29
+ import sys
30
+ import tempfile
31
+ import traceback
32
+ from pathlib import Path
33
+
34
+ import outline
35
+ from outline.modules.shell import Shell
36
+
37
+
38
+ def parse_arguments(argv):
39
+ """Parse command-line arguments."""
40
+ parser = argparse.ArgumentParser(
41
+ description="Execute a list of commands on the OpenCue render farm.",
42
+ formatter_class=argparse.RawDescriptionHelpFormatter,
43
+ epilog="""
44
+ Examples:
45
+ %(prog)s commands.txt
46
+ %(prog)s commands.txt --chunk 5 --cores 2 --memory 4
47
+ %(prog)s commands.txt --pause --pretend
48
+ """,
49
+ )
50
+
51
+ parser.add_argument(
52
+ "command_file", help="A file with a list of commands to run (one per line)"
53
+ )
54
+
55
+ parser.add_argument(
56
+ "-c",
57
+ "--chunk",
58
+ type=int,
59
+ default=1,
60
+ help="Number of commands to chunk per frame (Default: 1)",
61
+ )
62
+
63
+ parser.add_argument(
64
+ "--cores",
65
+ type=float,
66
+ default=1.0,
67
+ help="Number of cores required per frame (Default: 1.0)",
68
+ )
69
+
70
+ parser.add_argument(
71
+ "--memory",
72
+ type=float,
73
+ default=1.0,
74
+ help="Amount of RAM in GB required per frame (Default: 1.0)",
75
+ )
76
+
77
+ parser.add_argument(
78
+ "-p", "--pause", action="store_true", help="Launch the job in the paused state"
79
+ )
80
+
81
+ parser.add_argument(
82
+ "--pretend",
83
+ action="store_true",
84
+ help="Generate the outline and print the launch info without submitting",
85
+ )
86
+
87
+ parser.add_argument(
88
+ "-s",
89
+ "--shot",
90
+ default=os.environ.get("SHOT", "default"),
91
+ help='Shot name for the job (Default: from $SHOT or "default")',
92
+ )
93
+
94
+ parser.add_argument(
95
+ "--show",
96
+ default=os.environ.get("SHOW", "default"),
97
+ help='Show name for the job (Default: from $SHOW or "default")',
98
+ )
99
+
100
+ parser.add_argument(
101
+ "--user",
102
+ default=os.environ.get("USER", "unknown"),
103
+ help='User name for the job (Default: from $USER or "unknown")',
104
+ )
105
+
106
+ parser.add_argument(
107
+ "--job-name", help="Custom job name (Default: auto-generated from file name)"
108
+ )
109
+
110
+ return parser.parse_args(argv[1:])
111
+
112
+
113
+ def count_commands(command_file):
114
+ """Count the number of non-empty commands in the file."""
115
+ count = 0
116
+ with open(command_file, "r", encoding="utf-8") as f:
117
+ for line in f:
118
+ if line.strip():
119
+ count += 1
120
+ return count
121
+
122
+
123
+ def get_frame_range(command_count, chunk_size):
124
+ """Calculate the frame range based on command count and chunk size."""
125
+ num_frames = math.ceil(command_count / chunk_size)
126
+ return f"1-{num_frames}"
127
+
128
+
129
+ def copy_to_temp(command_file):
130
+ """Copy the command file to a temporary location that will be accessible during execution."""
131
+ # Create a temporary directory
132
+ temp_dir = tempfile.mkdtemp(prefix="cuecmd_")
133
+ basename = Path(command_file).stem
134
+ temp_file = os.path.join(temp_dir, f"{basename}.cmds")
135
+ shutil.copyfile(command_file, temp_file)
136
+ return temp_file
137
+
138
+
139
+ def create_outline(args, command_file, frame_range):
140
+ """Create an outline for executing the commands."""
141
+ # Get the path to the execute_commands.py script
142
+ execute_script = os.path.join(os.path.dirname(__file__), "execute_commands.py")
143
+
144
+ # Create the job name
145
+ if args.job_name:
146
+ job_name = args.job_name
147
+ else:
148
+ basename = Path(args.command_file).stem
149
+ job_name = f"{args.show}_{args.shot}_{args.user}_{basename}"
150
+
151
+ # Create the outline
152
+ ol = outline.Outline(job_name, shot=args.shot, show=args.show, user=args.user)
153
+
154
+ # Create the shell command that will execute the commands
155
+ # Use python3 explicitly
156
+ cmd = f"python3 {execute_script} {command_file} {args.chunk} --frame #IFRAME#"
157
+
158
+ # Create the layer
159
+ layer = Shell(
160
+ "cuecmd",
161
+ command=cmd,
162
+ chunk=1,
163
+ threads=args.cores,
164
+ threadable=1,
165
+ range=frame_range,
166
+ memory=f"{int(args.memory * 1024)}MB",
167
+ )
168
+
169
+ ol.add_layer(layer)
170
+ return ol
171
+
172
+
173
+ def main(argv=None):
174
+ """Main entry point for cuecmd."""
175
+ if argv is None:
176
+ argv = sys.argv
177
+
178
+ args = parse_arguments(argv)
179
+
180
+ # Validate the command file exists
181
+ if not os.path.isfile(args.command_file):
182
+ print(f"Error: Command file not found: {args.command_file}", file=sys.stderr)
183
+ sys.exit(1)
184
+
185
+ # Get absolute path to the command file
186
+ command_file = os.path.abspath(args.command_file)
187
+
188
+ # Count commands and calculate range
189
+ command_count = count_commands(command_file)
190
+ if command_count == 0:
191
+ print("Error: No commands found in the command file", file=sys.stderr)
192
+ sys.exit(1)
193
+
194
+ print(f"Found {command_count} commands in {command_file}")
195
+
196
+ frame_range = get_frame_range(command_count, args.chunk)
197
+ print(f"Frame range with chunking of {args.chunk}: {frame_range}")
198
+
199
+ # Copy command file to a temporary location
200
+ temp_command_file = copy_to_temp(command_file)
201
+ print(f"Copied commands to: {temp_command_file}")
202
+
203
+ # Create the outline
204
+ ol = create_outline(args, temp_command_file, frame_range)
205
+
206
+ if args.pretend:
207
+ print("\n=== Pretend Mode ===")
208
+ print(f"Job name: {ol.get_name()}")
209
+ print(f"Shot: {ol.get_shot()}")
210
+ print(f"Show: {ol.get_show()}")
211
+ print(f"User: {ol.get_user()}")
212
+ print(f"Frame range: {frame_range}")
213
+ print(f"Chunk size: {args.chunk}")
214
+ print(f"Cores per frame: {args.cores}")
215
+ print(f"Memory per frame: {args.memory}GB")
216
+ print(f"Command file: {temp_command_file}")
217
+ print("\nWould launch the job with the above settings.")
218
+ return 0
219
+
220
+ # Launch the job
221
+ try:
222
+ jobs = outline.cuerun.launch(ol, pause=args.pause, use_pycuerun=True)
223
+ if jobs:
224
+ print(f"\nSuccessfully launched job: {ol.get_name()}")
225
+ if args.pause:
226
+ print("Job is paused. Use cueadmin to unpause it.")
227
+ else:
228
+ print("Failed to launch job", file=sys.stderr)
229
+ sys.exit(1)
230
+ except Exception as e:
231
+ print(f"Error launching job: {e}", file=sys.stderr)
232
+ traceback.print_exc()
233
+ sys.exit(1)
234
+
235
+ return 0
236
+
237
+
238
+ if __name__ == "__main__":
239
+ sys.exit(main())
@@ -0,0 +1,403 @@
1
+ Metadata-Version: 2.1
2
+ Name: opencue_cuecmd
3
+ Version: 1.13.6
4
+ Summary: Cuecmd is a command-line tool for OpenCue that executes a list of commands as frames on the render farm. It enables batch processing by chunking commands and submitting them as OpenCue jobs.
5
+ Requires-Python: >3.7
6
+ Requires-Dist: opencue-pycue
7
+ Requires-Dist: opencue-pyoutline
8
+ Provides-Extra: dev
9
+ Requires-Dist: black; extra == 'dev'
10
+ Requires-Dist: isort; extra == 'dev'
11
+ Requires-Dist: mock==2.0.0; extra == 'dev'
12
+ Requires-Dist: pyfakefs==5.2.3; extra == 'dev'
13
+ Requires-Dist: pylint; extra == 'dev'
14
+ Requires-Dist: pytest; extra == 'dev'
15
+ Requires-Dist: pytest-cov; extra == 'dev'
16
+ Requires-Dist: pytest-mock; extra == 'dev'
17
+ Provides-Extra: test
18
+ Requires-Dist: mock==2.0.0; extra == 'test'
19
+ Requires-Dist: pyfakefs==5.2.3; extra == 'test'
20
+ Requires-Dist: pytest; extra == 'test'
21
+ Requires-Dist: pytest-cov; extra == 'test'
22
+ Requires-Dist: pytest-mock; extra == 'test'
23
+ Description-Content-Type: text/markdown
24
+
25
+ # OpenCue Cuecmd
26
+
27
+ Cuecmd is a command-line tool for OpenCue that executes a list of commands as frames on the render farm. It enables batch processing by chunking commands and submitting them as OpenCue jobs.
28
+
29
+ ## Table of Contents
30
+
31
+ 1. [Overview](#overview)
32
+ 2. [Features](#features)
33
+ 3. [Installation](#installation)
34
+ 4. [Quick Start](#quick-start)
35
+ 5. [Usage](#usage)
36
+ 6. [Options](#options)
37
+ 7. [Examples](#examples)
38
+ 8. [Environment Variables](#environment-variables)
39
+ 9. [How It Works](#how-it-works)
40
+ 10. [Running Tests](#running-tests)
41
+ 11. [Docker Support](#docker-support)
42
+ 12. [Contributing](#contributing)
43
+
44
+ ## Overview
45
+
46
+ `cuecmd` is a tool for executing arbitrary shell commands on the OpenCue render farm. It takes a text file containing a list of commands (one per line) and distributes them across multiple frames for parallel execution.
47
+
48
+ ### About Cuecmd
49
+
50
+ The name "cuecmd" combines:
51
+ - **"Cue"** - From OpenCue, the render farm management system
52
+ - **"cmd"** - Short for command, representing its purpose of executing commands
53
+
54
+ The `cuecmd` provides a simple way to parallelize any batch of shell commands using the OpenCue infrastructure.
55
+
56
+ ## Features
57
+
58
+ - **Command batching**: Execute any list of shell commands on the render farm
59
+ - **Chunking**: Group multiple commands per frame for efficient resource usage
60
+ - **Resource control**: Specify cores and memory requirements per frame
61
+ - **Job management**: Launch jobs paused or test with pretend mode
62
+ - **Flexible configuration**: Override show, shot, and user from command line
63
+ - **Simple input format**: Plain text file with one command per line
64
+
65
+ ## Installation
66
+
67
+ ### Prerequisites
68
+ - OpenCue server running and accessible
69
+ - Python 3.7 or higher
70
+ - OpenCue Python packages installed
71
+
72
+ ### Install Methods
73
+
74
+ Install as part of the OpenCue Python packages:
75
+
76
+ ```bash
77
+ pip install opencue-cuecmd
78
+ ```
79
+
80
+ Or install from source:
81
+
82
+ ```bash
83
+ cd OpenCue/cuecmd
84
+ pip install .
85
+ ```
86
+
87
+ ### Configuration
88
+ Set up your environment variables:
89
+ ```bash
90
+ export OPENCUE_HOSTS="your-cuebot-server:8443"
91
+ export OPENCUE_FACILITY="your-facility-code"
92
+ ```
93
+
94
+ ## Quick Start
95
+
96
+ 1. **Create a command file:**
97
+ ```bash
98
+ cat > commands.txt << EOF
99
+ echo "Processing file 1"
100
+ echo "Processing file 2"
101
+ echo "Processing file 3"
102
+ EOF
103
+ ```
104
+
105
+ 2. **Submit to OpenCue:**
106
+ ```bash
107
+ cuecmd commands.txt
108
+ ```
109
+
110
+ 3. **Monitor the job:**
111
+ ```bash
112
+ cueadmin -lj # List jobs
113
+ cueman -lf <job_name> # List frames
114
+ ```
115
+
116
+ ## Usage
117
+
118
+ ```bash
119
+ cuecmd [options] <command_file>
120
+ ```
121
+
122
+ ### Basic Usage
123
+
124
+ ```bash
125
+ # Submit a simple command list
126
+ cuecmd commands.txt
127
+
128
+ # Chunk 5 commands per frame
129
+ cuecmd commands.txt --chunk 5
130
+
131
+ # Specify resources
132
+ cuecmd commands.txt --cores 4 --memory 8
133
+
134
+ # Launch paused for review
135
+ cuecmd commands.txt --pause
136
+
137
+ # Test without submitting
138
+ cuecmd commands.txt --pretend
139
+ ```
140
+
141
+ ## Options
142
+
143
+ ### Required Arguments
144
+ - `command_file` - A text file with a list of commands to run (one per line)
145
+
146
+ ### Optional Arguments
147
+
148
+ #### Execution Options
149
+ - `-c, --chunk <N>` - Number of commands to chunk per frame (Default: 1)
150
+ - `--cores <N>` - Number of cores required per frame (Default: 1.0)
151
+ - `--memory <N>` - Amount of RAM in GB required per frame (Default: 1.0)
152
+
153
+ #### Job Control
154
+ - `-p, --pause` - Launch the job in the paused state
155
+ - `--pretend` - Generate the outline and print info without submitting
156
+
157
+ #### Job Metadata
158
+ - `--show <name>` - Show name for the job (Default: from $SHOW or "default")
159
+ - `-s, --shot <name>` - Shot name for the job (Default: from $SHOT or "default")
160
+ - `--user <name>` - User name for the job (Default: from $USER or "unknown")
161
+ - `--job-name <name>` - Custom job name (Default: auto-generated)
162
+
163
+ ## Examples
164
+
165
+ ### Example 1: Simple Command Execution
166
+ ```bash
167
+ # Create command file
168
+ cat > render_frames.txt << EOF
169
+ blender -b scene.blend -o /tmp/frame_#### -f 1
170
+ blender -b scene.blend -o /tmp/frame_#### -f 2
171
+ blender -b scene.blend -o /tmp/frame_#### -f 3
172
+ EOF
173
+
174
+ # Submit to OpenCue
175
+ cuecmd render_frames.txt
176
+ ```
177
+
178
+ ### Example 2: Chunked Execution
179
+ ```bash
180
+ # Process 1000 images, 10 per frame
181
+ for i in {1..1000}; do
182
+ echo "convert input_$i.jpg -resize 50% output_$i.jpg"
183
+ done > convert_images.txt
184
+
185
+ cuecmd convert_images.txt --chunk 10
186
+ # This creates 100 frames, each processing 10 images
187
+ ```
188
+
189
+ ### Example 3: Resource-Intensive Jobs
190
+ ```bash
191
+ # Heavy computation requiring more resources
192
+ cat > simulations.txt << EOF
193
+ python simulate.py --scene 1
194
+ python simulate.py --scene 2
195
+ python simulate.py --scene 3
196
+ EOF
197
+
198
+ cuecmd simulations.txt --cores 8 --memory 32
199
+ ```
200
+
201
+ ### Example 4: Testing Before Launch
202
+ ```bash
203
+ # Test the job configuration without submitting
204
+ cuecmd commands.txt --chunk 5 --cores 2 --memory 4 --pretend
205
+
206
+ # Output shows:
207
+ # - Job name
208
+ # - Frame range
209
+ # - Resource requirements
210
+ # - Command file location
211
+ ```
212
+
213
+ ### Example 5: Custom Job Configuration
214
+ ```bash
215
+ cuecmd commands.txt \
216
+ --show "my_project" \
217
+ --shot "sequence_010" \
218
+ --user "artist" \
219
+ --job-name "batch_processing" \
220
+ --chunk 10 \
221
+ --cores 4 \
222
+ --memory 8 \
223
+ --pause
224
+ ```
225
+
226
+ ### Example 6: Data Processing Pipeline
227
+ ```bash
228
+ # Generate processing commands
229
+ cat > data_pipeline.txt << EOF
230
+ python extract.py data1.csv
231
+ python extract.py data2.csv
232
+ python extract.py data3.csv
233
+ python transform.py data1.json
234
+ python transform.py data2.json
235
+ python transform.py data3.json
236
+ EOF
237
+
238
+ cuecmd data_pipeline.txt --chunk 2 --cores 2 --memory 4
239
+ ```
240
+
241
+ ## Environment Variables
242
+
243
+ Cuecmd respects the following environment variables:
244
+
245
+ - `OPENCUE_HOSTS` - Comma-separated list of OpenCue servers
246
+ - `OPENCUE_FACILITY` - Default facility code
247
+ - `SHOW` - Default show name
248
+ - `SHOT` - Default shot name
249
+ - `USER` - Default user name
250
+
251
+ These can be overridden using command-line arguments.
252
+
253
+ ## How It Works
254
+
255
+ 1. **Command File Reading**: Cuecmd reads your text file containing commands
256
+ 2. **Chunking**: Commands are divided into chunks based on the `--chunk` parameter
257
+ 3. **Frame Range Calculation**: A frame range is calculated (1 to ceil(commands/chunk))
258
+ 4. **Outline Creation**: An OpenCue outline is created with a Shell layer
259
+ 5. **Job Submission**: The job is submitted to OpenCue for execution
260
+ 6. **Frame Execution**: Each frame executes its assigned chunk of commands
261
+
262
+ ### Technical Details
263
+
264
+ - Commands are copied to a temporary location for access during execution
265
+ - Each frame executes a helper script (`execute_commands.py`) that:
266
+ - Reads the command file
267
+ - Calculates which commands to run based on frame number and chunk size
268
+ - Executes each command in sequence
269
+ - Reports success/failure
270
+
271
+ ## Running Tests
272
+
273
+ The `cuecmd` includes a comprehensive test suite.
274
+
275
+ ### Quick Start
276
+
277
+ ```bash
278
+ # Install with test dependencies
279
+ pip install -e ".[test]"
280
+
281
+ # Run all tests
282
+ pytest
283
+
284
+ # Run with coverage
285
+ pytest --cov=cuecmd --cov-report=term-missing
286
+ ```
287
+
288
+ ### Test Types
289
+
290
+ - **Unit tests** - Test individual functions (`tests/test_main.py`, `tests/test_execute_commands.py`)
291
+ - **Integration tests** - Test complete workflows (`tests/integration_tests.py`, `tests/test_integration_workflows.py`)
292
+
293
+ ### Running Tests
294
+
295
+ ```bash
296
+ # Basic test run
297
+ pytest tests/
298
+
299
+ # Verbose output
300
+ pytest -v
301
+
302
+ # Run specific test file
303
+ pytest tests/test_main.py
304
+
305
+ # Run with coverage and HTML report
306
+ pytest --cov=cuecmd --cov-report=html --cov-report=term-missing
307
+ ```
308
+
309
+ ### CI/CD Integration
310
+
311
+ Cuecmd is integrated into OpenCue's CI/CD pipeline:
312
+
313
+ ```bash
314
+ # In OpenCue root directory
315
+ ./ci/run_python_tests.sh # Includes cuecmd tests
316
+ ./ci/run_python_lint.sh # Includes cuecmd linting
317
+ ```
318
+
319
+ ## Docker Support
320
+
321
+ ### Building the Docker Image
322
+
323
+ From the OpenCue root directory:
324
+ ```bash
325
+ docker build -f cuecmd/Dockerfile -t cuecmd .
326
+ ```
327
+
328
+ ### Running the Docker Container
329
+
330
+ **Show help:**
331
+ ```bash
332
+ docker run --rm cuecmd cuecmd --help
333
+ ```
334
+
335
+ **Test with commands:**
336
+ ```bash
337
+ # Create test commands
338
+ echo "echo 'test 1'" > /tmp/commands.txt
339
+ echo "echo 'test 2'" >> /tmp/commands.txt
340
+
341
+ # Run in pretend mode
342
+ docker run --rm -v /tmp:/data cuecmd cuecmd /data/commands.txt --pretend
343
+ ```
344
+
345
+ ## Contributing
346
+
347
+ ### Development Setup
348
+
349
+ ```bash
350
+ # Clone and setup
351
+ git clone https://github.com/<username>/OpenCue.git
352
+ cd OpenCue/cuecmd
353
+
354
+ # Install with development dependencies
355
+ pip install -e ".[dev]"
356
+ ```
357
+
358
+ ### Testing and Quality
359
+
360
+ ```bash
361
+ # Run tests
362
+ pytest --cov=cuecmd --cov-report=term-missing
363
+
364
+ # Code formatting and linting
365
+ black cuecmd tests
366
+ isort cuecmd tests
367
+ pylint cuecmd tests
368
+ ```
369
+
370
+ ### Guidelines
371
+
372
+ - Add tests for new features
373
+ - Update documentation for API changes
374
+ - Ensure all tests pass before submitting PRs
375
+
376
+ ## Troubleshooting
377
+
378
+ ### Common Issues
379
+
380
+ **Command file not found:**
381
+ ```bash
382
+ # Make sure file exists and path is correct
383
+ ls -l commands.txt
384
+ cuecmd $(pwd)/commands.txt # Use absolute path
385
+ ```
386
+
387
+ **No commands found:**
388
+ ```bash
389
+ # Check file has content and is not all blank lines
390
+ cat commands.txt
391
+ ```
392
+
393
+ **Job fails to launch:**
394
+ ```bash
395
+ # Check OpenCue connection
396
+ echo $OPENCUE_HOSTS
397
+ cueadmin -lj # Test connection
398
+ ```
399
+
400
+ **Commands fail during execution:**
401
+ - Check command syntax is correct
402
+ - Verify commands have access to required files/paths
403
+ - Ensure sufficient resources (cores/memory) are allocated
@@ -0,0 +1,8 @@
1
+ cuecmd/__init__.py,sha256=Am7VgCcHrbnaZcPLWkkrjEUq3yPCCHhReTf0vCtGPns,1085
2
+ cuecmd/__main__.py,sha256=8Xqzz6hfotBFgEROLZKCmkmV43zoPiUkAuiBrOuu1eQ,1104
3
+ cuecmd/execute_commands.py,sha256=1PCNeSY13nnCbdb1IBN0z2SpPTjLExBMyOKhWqCXDA0,2243
4
+ cuecmd/main.py,sha256=Hs37g4YgKHgHq8ISP_p9ZA7goPQbHpCP4v6SNNV0DPY,7148
5
+ opencue_cuecmd-1.13.6.dist-info/METADATA,sha256=CbdDjU82UgVzVTuj9I1lAczTWeICE1Fjih4ONKjyTmU,10006
6
+ opencue_cuecmd-1.13.6.dist-info/WHEEL,sha256=KGYbc1zXlYddvwxnNty23BeaKzh7YuoSIvIMO4jEhvw,87
7
+ opencue_cuecmd-1.13.6.dist-info/entry_points.txt,sha256=-iHfU6EuZIXryO6cp0IqDWbBul8PJkB_Ohzg58CAjOw,48
8
+ opencue_cuecmd-1.13.6.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.17.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ cuecmd = cuecmd.__main__:main