Skip to content

Conversation

@Steepspace
Copy link
Contributor

@Steepspace Steepspace commented Dec 18, 2025

Modernize path handling, datetime logic, and job tracking

  • Migrated to 'from datetime import datetime' to fix AttributeError and standardize timestamp formatting across the script.
  • Replaced unsafe Path concatenation with f-string interpolation and explicit Path casting to resolve TypeError during directory naming.
  • Added 'create_symlink' utility to replicate 'ln -sfn' behavior, ensuring calibration tags safely overwrite existing links.
  • Introduced a blocking job-progress monitor in 'generate_condor' that polls the output directory until all expected jobs are finished.
  • Enhanced output directory structure by adding an optional calibration tags directory and automated daily symlinking.
  • Improved 'generate_condor' to include job counting and cleaner log directory cleanup using 'shutil.rmtree' with 'ignore_errors'.

CaloCDB: Refactor runProd.py

Motivation & Context

This pull request refactors the calibration production script to fix critical bugs, standardize code patterns, and support new run types. The changes address a datetime-related AttributeError, unsafe file path operations, and add more robust job management capabilities for the production pipeline.

Key Changes

  • DateTime & Timestamp Fixes: Standardized import pattern (from datetime import datetime) and updated timestamp formatting to ISO format (yyyy-mm-dd-HH-MM-SS) with also updated log display format (mm-dd-yy)
  • Path Handling: Replaced unsafe Path concatenation with f-string interpolation and explicit Path casting to prevent TypeError in directory naming
  • Symlink Utility: Added create_symlink(target_path, link_path) function that safely handles symbolic link creation/overwriting (replicates ln -sfn behavior), enabling calibration tags to update existing links
  • New Run Type Support: Added "run3oo" run type (now default) with adjusted run ranges for run3pp (ending at 81668 instead of 200000)
  • Job Progress Monitoring: Introduced blocking progress monitor inside generate_condor that polls the output directory every 15 seconds until all expected jobs complete
  • Enhanced Output Structure: Added optional calibration tags directory (-o2 / --output-calib-tags CLI option) with automated daily symlink creation
  • Job Accounting: Added job counting from dataset list files with results written to jobs.list
  • Log Cleanup: Improved log directory cleanup using shutil.rmtree(ignore_errors=True) for cleaner, more robust deletion

Potential Risk Areas

  • Timestamp Format Changes: DateTime format updates (especially ISO format for output suffixes) may affect downstream scripts or log parsing tools that expect previous formats
  • Symlink Behavior Changes: New symlink creation logic with automatic overwriting could break workflows expecting atomic link creation or older link values
  • Job Progress Polling: The blocking 15-second polling loop may impact script responsiveness under heavy job loads or network delays
  • Output Directory Structure: Extended layout with calibration tags directory is a breaking change for any downstream tools expecting the previous directory structure
  • Run Type Migration: Changing default from run3pp to run3oo may affect batch submission defaults and could cause unintended behavior if configuration scripts assume the old default

Possible Future Improvements

  • Make job progress polling interval configurable rather than hard-coded at 15 seconds
  • Consider adding retry logic or timeout mechanisms to the job progress monitor
  • Evaluate whether the blocking progress monitor should be optional or run asynchronously
  • Document migration path for users with downstream dependencies on the old output directory structure

Note: AI-generated summaries can contain inaccuracies. Please review the actual code changes and commit history to verify implementation details.

Modernize path handling, datetime logic, and job tracking

- Migrated to 'from datetime import datetime' to fix AttributeError and
  standardize timestamp formatting across the script.
- Replaced unsafe Path concatenation with f-string interpolation and
  explicit Path casting to resolve TypeError during directory naming.
- Added 'create_symlink' utility to replicate 'ln -sfn' behavior,
  ensuring calibration tags safely overwrite existing links.
- Introduced a blocking job-progress monitor in 'generate_condor' that
  polls the output directory until all expected jobs are finished.
- Enhanced output directory structure by adding an optional calibration
  tags directory and automated daily symlinking.
- Improved 'generate_condor' to include job counting and cleaner
  log directory cleanup using 'shutil.rmtree' with 'ignore_errors'.
Copilot AI review requested due to automatic review settings December 18, 2025 03:00
@sphenix-jenkins-ci
Copy link

For repository maintainers, please start the CI check manually (feedback)

This is an automatic message to assist manually starting CI check for this pull request, commit 039d87830e2488ae9e67fc5d7fecb765508ab7ff. macros pull request require a manual start for CI checks, in particular selecting which coresoftware and calibrations versions to check against this macros pull request.

sPHENIX software maintainers: please make your input here and start the Build:

build

Note:

  1. if needed, fill in the pull request ID for the coresoftware pull request, e.g. origin/pr/1697/merge for PR#1697 in sha_coresoftware. Default is to check with the master branch.
  2. click Build button at the end of the long web page to start the test

Automatically generated by sPHENIX Jenkins continuous integration
sPHENIX             jenkins.io

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the runProd.py script to modernize path handling, datetime operations, and job monitoring. The changes aim to fix type errors in path concatenation, standardize datetime usage, add automated symlink management for calibration tags, and introduce blocking job progress monitoring for Condor submissions.

Key Changes:

  • Migrated from import datetime to from datetime import datetime to fix AttributeError issues
  • Replaced unsafe Path concatenation with f-string interpolation for timestamped directory naming
  • Added create_symlink() utility function and automated daily symlinking to calibration tags directory
  • Introduced blocking job-progress monitor that polls until all Condor jobs complete

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +382 to +390
while True:
finished_jobs = sum(1 for x in job_dir.iterdir() if x.is_dir())

if finished_jobs >= jobs:
logger.info(f"All Jobs Complete. {finished_jobs}/{jobs} Jobs.")
break

logger.info(f"Waiting for Jobs... {finished_jobs}/{jobs} done.")
time.sleep(15) # Check every 15 seconds
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The job monitoring loop assumes that each completed job creates a directory in 'output/', but this assumption is not validated. If jobs fail silently or create files instead of directories, the counter will be inaccurate and the loop may wait indefinitely. Consider adding error handling to check for job failures (e.g., by checking stderr files in the 'error/' directory) or adding a timeout mechanism to prevent infinite waiting.

Suggested change
while True:
finished_jobs = sum(1 for x in job_dir.iterdir() if x.is_dir())
if finished_jobs >= jobs:
logger.info(f"All Jobs Complete. {finished_jobs}/{jobs} Jobs.")
break
logger.info(f"Waiting for Jobs... {finished_jobs}/{jobs} done.")
time.sleep(15) # Check every 15 seconds
start_time = time.time()
# Maximum time to wait for all jobs to finish (in seconds)
max_wait_seconds = 6 * 60 * 60 # 6 hours
while True:
# Count both files and directories as completed job artifacts
finished_jobs = sum(1 for x in job_dir.iterdir() if x.is_dir() or x.is_file())
if finished_jobs >= jobs:
logger.info(f"All Jobs Complete. {finished_jobs}/{jobs} Jobs.")
break
# Timeout to avoid waiting indefinitely if jobs fail silently
if time.time() - start_time > max_wait_seconds:
logger.error(
"Timeout reached while waiting for Condor jobs: "
f"{finished_jobs}/{jobs} jobs appear to have produced output "
f"after waiting {max_wait_seconds} seconds."
)
break
logger.info(f"Waiting for Jobs... {finished_jobs}/{jobs} done.")
time.sleep(15) # Check every 15 seconds

Copilot uses AI. Check for mistakes.
if os.path.exists(condor_log_dir):
shutil.rmtree(condor_log_dir)
logger.info(f"Directory '{condor_log_dir}' and its contents removed.")
condor_log_dir.mkdir(parents=True, exist_ok=True)
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating the directory only to immediately delete it in the next line is redundant and inefficient. The first 'mkdir' call serves no purpose since 'shutil.rmtree' with 'ignore_errors=True' will silently succeed whether the directory exists or not. Remove line 337 to eliminate this unnecessary operation.

Suggested change
condor_log_dir.mkdir(parents=True, exist_ok=True)

Copilot uses AI. Check for mistakes.
Comment on lines +349 to +353
jobs = 0
with open(output / 'jobs.list', 'w', encoding="utf-8") as f:
for file_path in list_files:
f.write(str(file_path.resolve()) + '\n')
jobs += 1
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The job counting can be simplified by using 'len(list_files)' instead of maintaining a separate counter. This eliminates the need for the 'jobs' variable and the increment operation, making the code more concise and less error-prone.

Suggested change
jobs = 0
with open(output / 'jobs.list', 'w', encoding="utf-8") as f:
for file_path in list_files:
f.write(str(file_path.resolve()) + '\n')
jobs += 1
jobs = len(list_files)
with open(output / 'jobs.list', 'w', encoding="utf-8") as f:
for file_path in list_files:
f.write(str(file_path.resolve()) + '\n')

Copilot uses AI. Check for mistakes.
Comment on lines +327 to +331
print(f"Removed existing link/file at {link}")

# Create the new symlink
link.symlink_to(target)
print(f"Created symlink: {link} -> {target}")
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'create_symlink' function uses print statements instead of the logger that's used throughout the rest of the script. For consistency and proper log file integration, replace 'print()' calls with 'logger.info()' or 'logger.debug()' to ensure these messages are captured in the log file configured at line 437.

Suggested change
print(f"Removed existing link/file at {link}")
# Create the new symlink
link.symlink_to(target)
print(f"Created symlink: {link} -> {target}")
logger.info(f"Removed existing link/file at {link}")
# Create the new symlink
link.symlink_to(target)
logger.info(f"Created symlink: {link} -> {target}")

Copilot uses AI. Check for mistakes.
Comment on lines +379 to +383
job_dir = output / 'output'

# Check Job Progress
while True:
finished_jobs = sum(1 for x in job_dir.iterdir() if x.is_dir())
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The job monitoring starts immediately after submitting jobs without any initial delay, which could cause a race condition. If 'condor_submit' takes time to create the initial job directories, the first check may incorrectly show 0/N jobs completed. Consider adding a small initial delay (e.g., a few seconds) before starting the monitoring loop, or check that the job submission has completed successfully before beginning to poll.

Copilot uses AI. Check for mistakes.
Comment on lines +434 to +435
tag = output_calib_tags / CURRENT_DATE
create_symlink(output / 'output', tag)
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The symlink is created before the 'output/output' directory exists. The target directory 'output / 'output'' is only created later by the condor jobs in the 'generate_condor' function (line 360). This will cause the symlink to point to a non-existent directory at creation time, potentially resulting in a broken symlink. Consider moving this symlink creation to after the directory structure is set up in 'generate_condor', or create the output directory explicitly before creating the symlink.

Suggested change
tag = output_calib_tags / CURRENT_DATE
create_symlink(output / 'output', tag)
# Ensure the output subdirectory exists before creating the symlink
output_subdir = output / 'output'
output_subdir.mkdir(parents=True, exist_ok=True)
tag = output_calib_tags / CURRENT_DATE
create_symlink(output_subdir, tag)

Copilot uses AI. Check for mistakes.
jobs += 1

# list of subdirectories to create
subdirectories = ['stdout', 'error', 'output']
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The subdirectory name 'output' in the subdirectories list creates a path collision with the function parameter 'output'. This makes the code confusing because 'output / 'output'' refers to a subdirectory inside the output directory. Consider renaming the subdirectory to something more descriptive like 'results', 'job_output', or 'completed' to improve code clarity and avoid confusion.

Copilot uses AI. Check for mistakes.
args = parser.parse_args()
run_type = args.run_type
CURRENT_DATE = str(datetime.date.today())
CURRENT_DATE = datetime.now().strftime("%m-%d-%y")
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The date format was changed from YYYY-MM-DD to MM-DD-YY, which breaks chronological sorting. Directories and files named with this format will not sort correctly by name (e.g., '12-31-24' comes before '01-01-25' alphabetically but represents a later date). Revert to the ISO 8601 format '%Y-%m-%d' for proper chronological ordering, or use '%Y-%m-%d' if you need the full year.

Suggested change
CURRENT_DATE = datetime.now().strftime("%m-%d-%y")
CURRENT_DATE = datetime.now().strftime("%Y-%m-%d")

Copilot uses AI. Check for mistakes.
link = Path(link_path)

# Check if the link destination already exists
if link.exists() or link.is_symlink():
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function attempts to unlink a path that could be a non-empty directory. While the docstring mentions that 'link.unlink()' won't remove target directories, it will fail with 'IsADirectoryError' if 'link_path' is an actual directory (not a symlink). The current code doesn't handle this case. Consider using 'shutil.rmtree()' if the path is a directory, or explicitly check the path type before calling 'unlink()'.

Suggested change
if link.exists() or link.is_symlink():
if link.exists() or link.is_symlink():
# If link_path is a real directory (not a symlink), do not attempt to unlink it.
# This matches the documented behavior and avoids IsADirectoryError.
if link.is_dir() and not link.is_symlink():
raise OSError(f"Cannot overwrite existing directory at {link}")

Copilot uses AI. Check for mistakes.
Comment on lines +309 to +318
Replicates the behavior of 'ln -sfn' by removing the destination
if it already exists (including broken symlinks) before creating
the new link.

Args:
target_path (str or Path): The existing file or directory to point to.
link_path (str or Path): The path where the symlink should be created.

Raises:
OSError: If the link_path exists as a real directory and cannot be unlinked, or if permission is denied.
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring states that the function replicates 'ln -sfn' behavior, but the '-n' flag in 'ln -sfn' treats the destination as a normal file if it's a symlink to a directory. The current implementation doesn't replicate this behavior - it will follow symlinks when checking 'link.exists()'. For true 'ln -sfn' equivalence, use 'link.is_symlink()' check only, or document the deviation from '-n' behavior.

Suggested change
Replicates the behavior of 'ln -sfn' by removing the destination
if it already exists (including broken symlinks) before creating
the new link.
Args:
target_path (str or Path): The existing file or directory to point to.
link_path (str or Path): The path where the symlink should be created.
Raises:
OSError: If the link_path exists as a real directory and cannot be unlinked, or if permission is denied.
Approximates the behavior of ``ln -sfn`` by removing the destination
at ``link_path`` if it already exists (including broken symlinks)
before creating the new link.
Note:
This function uses :meth:`pathlib.Path.exists`, which follows
symlinks to directories, and unlinks any existing path at
``link_path``. As a result, its behavior may differ from the
exact semantics of ``ln -sfn`` (in particular the ``-n`` flag)
in some edge cases.
Args:
target_path (str or Path): The existing file or directory to point to.
link_path (str or Path): The path where the symlink should be created.
Raises:
OSError: If the link_path exists and cannot be unlinked, or if
permission is denied.

Copilot uses AI. Check for mistakes.
@Steepspace Steepspace marked this pull request as draft December 18, 2025 03:11
- Add new run type: run3oo (set as default)
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 1, 2026

📝 Walkthrough

Walkthrough

Modified production script for calorimeter calibration database to add run3oo run type support, new calibration tag output option, symlink creation utility, improved job submission with progress polling, and enhanced timestamp handling in output paths.

Changes

Cohort / File(s) Summary
Run Configuration and CLI Options
calibrations/calo/calo_cdb/scripts/runProd.py
Added run3oo as new run type with adjusted run ranges (run3pp end: 81668; run3oo added). New CLI option -o2/--output-calib-tags for specifying calibration tag output directory. Default run type changed from run3pp to run3oo.
Utility Functions and Output Management
calibrations/calo/calo_cdb/scripts/runProd.py
Introduced create_symlink(target_path, link_path) function to safely create symlinks with existing destination removal and logging. Output directory structure now includes timestamped suffixes (yyyy-mm-dd-HH-MM-SS format) when condor submission enabled. Created output\_calib\_tags directory with symlink tag pointing to current output.
Job Submission and Monitoring
calibrations/calo/calo_cdb/scripts/runProd.py
Refactored condor\_log\_dir cleanup using mkdir followed by rmtree with ignore\_errors. Implemented job counting from dataset list files written to jobs.list. Added progress polling loop (15-second intervals) to monitor job completion by checking output directory contents.
Logging and Timestamp Handling
calibrations/calo/calo_cdb/scripts/runProd.py
Updated imports to use from datetime import datetime and added time module. CURRENT\_DATE format changed to mm-dd-yy. Enhanced logging timestamp display using datetime.now().

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sphenix-jenkins-ci
Copy link

For repository maintainers, please start the CI check manually (feedback)

This is an automatic message to assist manually starting CI check for this pull request, commit db0870a3a218cff213368a754d9c9faecc4dd469. macros pull request require a manual start for CI checks, in particular selecting which coresoftware and calibrations versions to check against this macros pull request.

sPHENIX software maintainers: please make your input here and start the Build:

build

Note:

  1. if needed, fill in the pull request ID for the coresoftware pull request, e.g. origin/pr/1697/merge for PR#1697 in sha_coresoftware. Default is to check with the master branch.
  2. click Build button at the end of the long web page to start the test

Automatically generated by sPHENIX Jenkins continuous integration
sPHENIX             jenkins.io

@Steepspace
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 1, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
calibrations/calo/calo_cdb/scripts/runProd.py (3)

337-341: Redundant directory creation pattern.

The current logic creates the directory, immediately deletes it, then creates it again. This is unnecessarily complex.

♻️ Simplified cleanup
-    condor_log_dir.mkdir(parents=True, exist_ok=True)
-    shutil.rmtree(condor_log_dir, ignore_errors=True)
-
-    # Setup Condor Log Dir
-    condor_log_dir.mkdir(parents=True, exist_ok=True)
+    # Clean and recreate Condor Log Dir
+    shutil.rmtree(condor_log_dir, ignore_errors=True)
+    condor_log_dir.mkdir(parents=True, exist_ok=True)

374-374: Remove extraneous f-prefix.

This f-string has no placeholders. The static analysis tool flagged this correctly.

🔧 Quick fix
-    command = f'condor_submit genStatus.sub -queue "input_run from jobs.list"'
+    command = 'condor_submit genStatus.sub -queue "input_run from jobs.list"'

445-445: Static analysis: use conversion flag.

The static analyzer suggests using an f-string conversion flag instead of explicit str() call. This is a minor style preference.

🔧 Quick fix
-    logger.info(f'LOGGING: {str(datetime.now())}')
+    logger.info(f'LOGGING: {datetime.now()!s}')

Alternatively, since datetime.now() already has a sensible __str__, you can simply use:

logger.info(f'LOGGING: {datetime.now()}')

Comment on lines +305 to +331
def create_symlink(target_path, link_path):
"""
Creates a symbolic link pointing to target_path named link_path.

Replicates the behavior of 'ln -sfn' by removing the destination
if it already exists (including broken symlinks) before creating
the new link.

Args:
target_path (str or Path): The existing file or directory to point to.
link_path (str or Path): The path where the symlink should be created.

Raises:
OSError: If the link_path exists as a real directory and cannot be unlinked, or if permission is denied.
"""
target = Path(target_path)
link = Path(link_path)

# Check if the link destination already exists
if link.exists() or link.is_symlink():
# link.unlink() removes the symlink or file, but not the target directory
link.unlink()
print(f"Removed existing link/file at {link}")

# Create the new symlink
link.symlink_to(target)
print(f"Created symlink: {link} -> {target}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Minor issue: unlink() fails on real directories.

If link_path is an existing real directory (not a symlink), link.unlink() at line 326 will raise IsADirectoryError. The docstring acknowledges this but doesn't handle it. If this scenario is possible in your workflow, consider using shutil.rmtree() for directories.

Also, for consistency with the rest of the module, consider using logger.info() instead of print() for the status messages.

🛠️ Optional fix for directory handling and logging
 def create_symlink(target_path, link_path):
     """
     Creates a symbolic link pointing to target_path named link_path.
 
     Replicates the behavior of 'ln -sfn' by removing the destination 
     if it already exists (including broken symlinks) before creating 
     the new link.
 
     Args:
         target_path (str or Path): The existing file or directory to point to.
         link_path (str or Path): The path where the symlink should be created.
 
     Raises:
         OSError: If the link_path exists as a real directory and cannot be unlinked, or if permission is denied.
     """
     target = Path(target_path)
     link = Path(link_path)
 
     # Check if the link destination already exists
     if link.exists() or link.is_symlink():
-        # link.unlink() removes the symlink or file, but not the target directory
-        link.unlink()
-        print(f"Removed existing link/file at {link}")
+        if link.is_symlink() or link.is_file():
+            link.unlink()
+        else:
+            shutil.rmtree(link)
+        logger.info(f"Removed existing link/file at {link}")
 
     # Create the new symlink
     link.symlink_to(target)
-    print(f"Created symlink: {link} -> {target}")
+    logger.info(f"Created symlink: {link} -> {target}")

Comment on lines +379 to +390
job_dir = output / 'output'

# Check Job Progress
while True:
finished_jobs = sum(1 for x in job_dir.iterdir() if x.is_dir())

if finished_jobs >= jobs:
logger.info(f"All Jobs Complete. {finished_jobs}/{jobs} Jobs.")
break

logger.info(f"Waiting for Jobs... {finished_jobs}/{jobs} done.")
time.sleep(15) # Check every 15 seconds
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Potential infinite loop if jobs fail.

This polling loop has no timeout mechanism. If condor jobs fail without creating output directories, the script will hang indefinitely. For a production cron job, this could block subsequent runs.

Consider adding:

  1. A maximum wait time / timeout
  2. Checking for job failures via condor_q or error files
  3. At minimum, logging a warning after extended waiting periods
🛡️ Suggested timeout mechanism
         job_dir = output / 'output'
 
+        max_wait_seconds = 3600 * 6  # 6 hour timeout
+        elapsed = 0
         # Check Job Progress
         while True:
             finished_jobs = sum(1 for x in job_dir.iterdir() if x.is_dir())
 
             if finished_jobs >= jobs:
                 logger.info(f"All Jobs Complete. {finished_jobs}/{jobs} Jobs.")
                 break
 
+            if elapsed >= max_wait_seconds:
+                logger.error(f"Timeout reached. Only {finished_jobs}/{jobs} jobs completed.")
+                break
+
             logger.info(f"Waiting for Jobs... {finished_jobs}/{jobs} done.")
             time.sleep(15) # Check every 15 seconds
+            elapsed += 15

Comment on lines +432 to +435
output_calib_tags.mkdir(parents=True, exist_ok=True)

tag = output_calib_tags / CURRENT_DATE
create_symlink(output / 'output', tag)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Symlink created before target directory exists.

At line 435, create_symlink(output / 'output', tag) is called, but the output/output directory is only created later at line 360 in generate_condor(). This creates a symlink pointing to a non-existent target.

While symlinks to non-existent paths are technically valid (dangling symlinks), this may cause confusion or errors if something tries to follow the symlink before jobs complete.

Consider either:

  1. Moving the symlink creation to after generate_condor() completes
  2. Creating the output/output directory earlier in main()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant