Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement default submission template #338

Merged
merged 21 commits into from
Sep 28, 2024
Merged

Implement default submission template #338

merged 21 commits into from
Sep 28, 2024

Conversation

jan-janssen
Copy link
Member

@jan-janssen jan-janssen commented Sep 28, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced render_submission_template method across multiple job scheduler classes (Flux, LSF, Moab, SGE, SLURM, Torque) for generating dynamic job submission scripts.
    • Enhanced job submission templates with placeholders for various parameters such as job name, memory limits, and runtime limits.
    • Added enable_reservation_command property to SchedulerCommands class to support job reservation functionality.
    • Added a new CoreQueueAdapter class to streamline job submission and management across various queuing systems.
  • Refactor

    • Updated job submission handling in the SchedulerCommands class to improve abstraction and enforce implementation in subclasses.
    • Streamlined the BasisQueueAdapter class by removing redundant methods and leveraging functionality from the superclass.
  • Bug Fixes

    • Improved type annotations in the check_queue_parameters function for better clarity on expected output.

Copy link

coderabbitai bot commented Sep 28, 2024

Warning

Rate limit exceeded

@jan-janssen has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 9 minutes and 15 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Files that changed from the base of the PR and between ffd620b and d7c33c3.

Walkthrough

The changes introduce a new render_submission_template method across various command classes in the pysqa package, streamlining the generation of job submission scripts using Jinja2 templates. Modifications were made to the BasisQueueAdapter class, which now inherits from CoreQueueAdapter, and several redundant methods were removed. A new CoreQueueAdapter class was also introduced, encapsulating job submission and management logic, enhancing the overall structure and maintainability of the code.

Changes

Files Change Summary
pysqa/utils/basic.py Updated BasisQueueAdapter to inherit from CoreQueueAdapter, removed several methods, and modified _job_submission_template to utilize the new render_submission_template.
pysqa/wrapper/abstract.py Added enable_reservation_command as an abstract property and render_submission_template static method for job submission template generation in SchedulerCommands.
pysqa/wrapper/flux.py Introduced render_submission_template method in FluxCommands class for generating job submission scripts using Jinja2 templates with various parameters.
pysqa/wrapper/generic.py Added enable_reservation_command as an abstract property, changed get_queue_status_command to an abstract method, and introduced render_submission_template static method for job submission template generation.
pysqa/wrapper/lsf.py Added render_submission_template method to LsfCommands class for generating job submission scripts using a Jinja2 template based on provided parameters.
pysqa/wrapper/moab.py Introduced a new job submission template and added render_submission_template method to MoabCommands class for script generation using Jinja2 templates.
pysqa/wrapper/sge.py Added a job submission template and render_submission_template method to SunGridEngineCommands class for generating submission scripts dynamically.
pysqa/wrapper/slurm.py Introduced a job submission template and render_submission_template method in SlurmCommands class for generating SLURM job submission scripts.
pysqa/wrapper/torque.py Added a new job submission template and render_submission_template method to TorqueCommands class for generating job submission scripts based on defined parameters.
tests/test_scheduler_commands.py Updated import statement for SchedulerCommands to be sourced from pysqa.wrapper.abstract instead of pysqa.wrapper.generic.
pysqa/utils/core.py Introduced CoreQueueAdapter class with methods for job submission and management, including submit_job, enable_reservation, delete_job, and get_queue_status.

Possibly related PRs

  • add ruff formatter #297: The changes in pysqa/wrapper/lsf.py involve updates to the convert_queue_status function, which may relate to the queue management functionalities being streamlined in the main PR.
  • Add docstrings and typehints with github co-pilot #317: The enhancements to the command_line function in pysqa/cmd.py and the Executor class in pysqa/executor/executor.py include improvements in documentation and type safety, which could be relevant to the overall maintainability and clarity goals of the main PR.

🐇 In the code we hop and play,
New templates brighten up the day!
With scripts that dance and twirl so free,
Job submissions made with glee!
Let's celebrate this joyful change,
In our coding burrow, we rearrange! 🐰✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@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: 27

🧹 Outside diff range and nitpick comments (8)
pysqa/utils/basic.py (1)

514-523: LGTM! Consider adding type hints for improved code clarity.

The refactoring to use render_submission_template improves modularity and separates concerns. This change enhances maintainability and potentially allows for easier customization of submission templates for different queue systems.

Consider adding type hints to the render_submission_template method call for improved code clarity and maintainability. For example:

return self._commands.render_submission_template(
    command: str = command,
    submission_template: Template = active_queue["template"],
    working_directory: str = working_directory,
    job_name: str = job_name,
    cores: Optional[int] = cores,
    memory_max: Optional[int] = memory_max,
    run_time_max: Optional[int] = run_time_max,
    dependency_list: Optional[List[int]] = dependency_list,
    **kwargs
)
pysqa/wrapper/moab.py (1)

24-35: Include working directory change in the submission script

The working_directory parameter is accepted but not used in the submission script. To ensure the job executes in the correct working directory, include a command to change to that directory before executing the main command.

Consider adding the following line before {{command}}:

 {%- endif %}

+cd {{ working_directory }}
 {{command}}

This ensures the job runs in the intended directory.

pysqa/wrapper/flux.py (1)

101-101: Update docstring type for submission_template parameter

The submission_template parameter is typed as Union[str, Template] in the function signature but is documented as (str) in the docstring. For consistency and clarity, update the docstring to reflect the correct type.

Correct the docstring as follows:

- submission_template (str): Submission script template pysqa.wrapper.flux.template
+ submission_template (Union[str, Template], optional): Submission script template. Defaults to `template`.
pysqa/wrapper/lsf.py (1)

100-101: Document the usage of **kwargs in the method

The method accepts **kwargs, which are passed to the template rendering. However, there is no explanation in the docstring about what additional keyword arguments can be provided. To enhance clarity, consider updating the docstring to inform users about the possibility of passing extra parameters to the template.

Suggested addition to the docstring:

     **kwargs,
 ) -> str:
     """
     Generate the job submission template.

     Args:
         ...
+        **kwargs: Additional keyword arguments to be passed to the template rendering.
pysqa/wrapper/sge.py (3)

31-38: Validation for memory_max and run_time_max units

The template uses {{memory_max}} and {{run_time_max}} directly, but it's unclear what units are expected (e.g., bytes, kilobytes, megabytes, seconds, minutes). This might lead to incorrect resource requests.

Consider adding unit validation or documentation to clarify the expected units for memory_max and run_time_max.


105-105: Default working_directory might not be intuitive

The default value for working_directory is os.path.abspath("."), which resolves to the current working directory when the script is run. This may not be the intended directory for job execution.

Consider requiring the user to specify working_directory, or clarify in the documentation that it defaults to the directory from which the script is executed.


114-127: Improve docstring formatting and consistency

The docstring has some inconsistencies and could be formatted more clearly for better readability.

  • Ensure all parameter descriptions are aligned and consistently formatted.
  • Correct any typos or mismatches in parameter names and descriptions.

Suggested changes:

     """
     Generate the job submission template.

     Args:
         command (str): The command to be executed.
         job_name (str, optional): The job name. Defaults to "pysqa".
         working_directory (str, optional): The working directory. Defaults to the current directory.
         cores (int, optional): The number of cores. Defaults to 1.
         memory_max (int, optional): The maximum memory in megabytes. Defaults to None.
         run_time_max (int, optional): The maximum run time in seconds. Defaults to None.
         dependency_list (list[int], optional): The list of dependency job IDs. Defaults to None.
-        submission_template (str): Submission script template.
+        submission_template (Union[str, Template], optional): The submission script template. Defaults to the class-defined template.
         **kwargs: Additional template variables.

     Returns:
         str: The rendered job submission script.
     """
pysqa/wrapper/torque.py (1)

25-41: Add usage of working_directory in the template or remove the parameter

The working_directory parameter is currently not used within the submission template.

If the working directory needs to be set, consider adding it to the template:

+#PBS -d {{ working_directory }}

Alternatively, if setting the working directory is handled elsewhere, you might consider removing the working_directory parameter from the method signature to avoid confusion.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between ad35248 and 2a60f35.

📒 Files selected for processing (8)
  • pysqa/utils/basic.py (1 hunks)
  • pysqa/wrapper/flux.py (2 hunks)
  • pysqa/wrapper/generic.py (3 hunks)
  • pysqa/wrapper/lsf.py (3 hunks)
  • pysqa/wrapper/moab.py (3 hunks)
  • pysqa/wrapper/sge.py (3 hunks)
  • pysqa/wrapper/slurm.py (3 hunks)
  • pysqa/wrapper/torque.py (3 hunks)
🔇 Additional comments (9)
pysqa/utils/basic.py (2)

514-523: Summary: Improved modularity in job submission template rendering.

The changes in this file are minimal but impactful. By introducing the render_submission_template method, the code now has better separation of concerns and improved modularity. This refactoring allows for easier customization of submission templates for different queue systems without affecting the overall functionality of the BasisQueueAdapter class.

Key points:

  1. The public API of the class remains unchanged.
  2. The change is localized to the _job_submission_template method.
  3. The new implementation delegates template rendering to a separate method, likely implemented in subclasses of SchedulerCommands.

These changes align well with best practices for maintainable and extensible code.


514-523: Verify the implementation of render_submission_template in the SchedulerCommands subclass.

The refactoring introduces a new method render_submission_template which is called on self._commands. Ensure that this method is properly implemented in the appropriate subclass of SchedulerCommands for each supported queue system.

Run the following script to verify the implementation of render_submission_template:

pysqa/wrapper/generic.py (2)

6-6: Imports added for new functionality

The addition of List, Optional, and Union from the typing module and Template from jinja2 is appropriate and necessary for the new methods introduced.

Also applies to: 8-8


57-65: Changed get_queue_status_command from property to method

The get_queue_status_command was previously defined as a property with @property and @abstractmethod decorators. It has now been changed to an abstract method by removing the @property decorator. This alteration changes how subclasses implement this method and may impact any code that accesses it as a property.

Run the following script to identify subclasses that may need updates:

Ensure that all subclasses and code accessing get_queue_status_command are updated to reflect this change.

✅ Verification successful

Verification Successful: No subclasses or instances are using get_queue_status_command as a property.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find subclasses of SchedulerCommands with get_queue_status_command defined as a property.

# Test: Search for subclasses using @property for get_queue_status_command.
ast-grep --lang python --pattern $'class $_(SchedulerCommands):\n    $$$\n    @property\n    def get_queue_status_command($_):\n        $$$\n    $$$'

Length of output: 145


Script:

#!/bin/bash
# Description: Find all instances where get_queue_status_command is defined as a property in Python files.

ast-grep --lang python --pattern $'@property\n    def get_queue_status_command($_):\n        $$$'

Length of output: 96

pysqa/wrapper/flux.py (2)

84-84: Unused parameter memory_max

The parameter memory_max is accepted by the function but is not used in the submission template. If memory_max is not needed, consider removing it from the function parameters. If it is required, include it in the template to set the maximum memory for the job.

Please verify whether memory_max should be included in the submission template. If Flux supports specifying memory limits, incorporate memory_max into the template accordingly.

Also applies to: 114-114


19-19: Verify time unit conversion for run_time_max

In the template, run_time_max is converted to minutes using integer division by 60: {{ [1, run_time_max // 60]|max }}. Please verify that run_time_max is provided in seconds and that the -t option expects time in minutes.

pysqa/wrapper/lsf.py (1)

34-34: Verify that run_time_max and memory_max are in the correct units

In the template directives #BSUB -W {{run_time_max}} and #BSUB -M {{memory_max}}, ensure that the values provided for run_time_max and memory_max are in the units expected by LSF. Typically:

  • -W expects the run time in minutes.
  • -M expects the memory limit in kilobytes.

Adjust the parameter units or include unit conversions if necessary to prevent scheduling issues.

Also applies to: 37-37

pysqa/wrapper/torque.py (1)

30-31: Validate units for the memory_max parameter

Ensure that the memory_max parameter is provided in gigabytes as an integer. If users provide memory in other units or as a string, it could result in scheduling errors.

Consider adding validation in the render_submission_template method to confirm the memory_max is an integer representing gigabytes.

pysqa/wrapper/slurm.py (1)

33-33: Verify the calculation of run_time_max for SLURM's --time directive

The calculation {{ [1, run_time_max // 60]|max }} may not correctly reflect SLURM's expected time format. SLURM expects the --time parameter in the format minutes, hours:minutes:seconds, or days-hours. Ensure that run_time_max is converted appropriately.

Run the following script to verify the correct handling of run_time_max:

memory_max (int, optional): The maximum memory. Defaults to None.
run_time_max (int, optional): The maximum run time. Defaults to None.
dependency_list (list[int], optional): The list of dependency job IDs. Defaults to None.
submission_template (str): Submission script template pysqa.wrapper.torque.template
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Update the docstring to reference the correct template

The docstring for the submission_template parameter refers to pysqa.wrapper.torque.template, which is incorrect for the Moab scheduler. It should reference the Moab template to avoid confusion.

Please correct the docstring as follows:

-    submission_template (str): Submission script template pysqa.wrapper.torque.template
+    submission_template (str): Submission script template for Moab scheduler
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
submission_template (str): Submission script template pysqa.wrapper.torque.template
submission_template (str): Submission script template for Moab scheduler

#MSUB -l pmem={{ memory_max| int }}gb
{%- endif %}
{%- if run_time_max %}
#$ -l walltime={{run_time_max}}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Correct the resource directive prefix for consistency

The resource directive on line 31 uses #$, which is inconsistent with the other Moab directives that use #MSUB. This inconsistency may lead to the scheduler ignoring the line or causing unexpected behavior.

Please update the line to use the correct Moab directive prefix:

-#$ -l walltime={{run_time_max}}
+#MSUB -l walltime={{ run_time_max }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#$ -l walltime={{run_time_max}}
#MSUB -l walltime={{ run_time_max }}

Comment on lines +24 to +35
template = """\
#!/bin/bash
#MSUB -N {{job_name}}
{%- if memory_max %}
#MSUB -l pmem={{ memory_max| int }}gb
{%- endif %}
{%- if run_time_max %}
#$ -l walltime={{run_time_max}}
{%- endif %}

{{command}}
"""
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Include the number of cores in the submission template

The cores parameter is accepted by the render_submission_template method but is not utilized in the submission script. To ensure the scheduler allocates the correct number of cores, include the appropriate resource directive in the submission template.

Add the following to the template to request the specified number of cores:

 {%- if run_time_max %}
 #MSUB -l walltime={{ run_time_max }}
 {%- endif %}
+{%- if cores %}
+#MSUB -l nodes=1:ppn={{ cores }}
+{%- endif %}

 {{command}}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
template = """\
#!/bin/bash
#MSUB -N {{job_name}}
{%- if memory_max %}
#MSUB -l pmem={{ memory_max| int }}gb
{%- endif %}
{%- if run_time_max %}
#$ -l walltime={{run_time_max}}
{%- endif %}
{{command}}
"""
template = """\
#!/bin/bash
#MSUB -N {{job_name}}
{%- if memory_max %}
#MSUB -l pmem={{ memory_max| int }}gb
{%- endif %}
{%- if run_time_max %}
#MSUB -l walltime={{run_time_max}}
{%- endif %}
{%- if cores %}
#MSUB -l nodes=1:ppn={{ cores }}
{%- endif %}
{{command}}
"""

⚠️ Potential issue

Handle job dependencies in the submission template

The dependency_list parameter is accepted but not utilized in the submission script. To properly manage job dependencies, include directives that specify the job IDs this job depends on.

Add the following lines to handle job dependencies:

 {%- if run_time_max %}
 #MSUB -l walltime={{ run_time_max }}
 {%- endif %}
+{%- if dependency_list %}
+#MSUB -l depend={{ dependency_list | join(':') }}
+{%- endif %}

 {{command}}

This inclusion will ensure that the job submission respects any specified dependencies.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
template = """\
#!/bin/bash
#MSUB -N {{job_name}}
{%- if memory_max %}
#MSUB -l pmem={{ memory_max| int }}gb
{%- endif %}
{%- if run_time_max %}
#$ -l walltime={{run_time_max}}
{%- endif %}
{{command}}
"""
template = """\
#!/bin/bash
#MSUB -N {{job_name}}
{%- if memory_max %}
#MSUB -l pmem={{ memory_max| int }}gb
{%- endif %}
{%- if run_time_max %}
#MSUB -l walltime={{run_time_max}}
{%- endif %}
{%- if dependency_list %}
#MSUB -l depend={{ dependency_list | join(':') }}
{%- endif %}
{{command}}
"""

Comment on lines +24 to +32
@property
def enable_reservation_command(self) -> list[str]:
"""
Returns the command to enable job reservation on the scheduler.

Returns:
list[str]: The command to enable job reservation.
"""
raise NotImplementedError()
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Missing @abstractmethod decorator on enable_reservation_command

The enable_reservation_command property lacks the @abstractmethod decorator. Other abstract properties in the class, such as submit_job_command and delete_job_command, include both @property and @abstractmethod decorators. Adding the @abstractmethod decorator ensures consistency and enforces implementation in subclasses.

Apply this diff to add the decorator:

 @property
+@abstractmethod
 def enable_reservation_command(self) -> list[str]:
     """
     Returns the command to enable job reservation on the scheduler.

     Returns:
         list[str]: The command to enable job reservation.
     """
-    raise NotImplementedError()
+    pass
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@property
def enable_reservation_command(self) -> list[str]:
"""
Returns the command to enable job reservation on the scheduler.
Returns:
list[str]: The command to enable job reservation.
"""
raise NotImplementedError()
@property
@abstractmethod
def enable_reservation_command(self) -> list[str]:
"""
Returns the command to enable job reservation on the scheduler.
Returns:
list[str]: The command to enable job reservation.
"""
pass

Comment on lines 69 to 87
def render_submission_template(
command: str,
submission_template: Union[str, Template],
working_directory: str,
job_name: str = "pysqa",
cores: int = 1,
memory_max: Optional[int] = None,
run_time_max: Optional[int] = None,
dependency_list: Optional[List[int]] = None,
**kwargs,
) -> str:
"""
Returns the command to get the status of the job queue.
Generate the job submission template.

Args:
command (str, optional): The command to be executed.
job_name (str, optional): The job name. Defaults to "pysqa".
working_directory (str, optional): The working directory. Defaults to ".".
cores (int, optional): The number of cores. Defaults to 1.
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Inconsistencies between function signature and docstring in render_submission_template

There are discrepancies between the function signature and the docstring:

  • Parameter Order: The order of parameters in the docstring does not match the function signature.
  • Optional Parameters:
    • command: In the signature, it's required (command: str), but the docstring marks it as optional.
    • working_directory: Required in the signature but marked as optional in the docstring with a default value that isn't reflected in the signature.
  • Type Annotations:
    • submission_template: In the signature, it's Union[str, Template], but the docstring lists it as str.
  • Missing Parameters: **kwargs is not documented in the docstring.

Apply this diff to correct the docstring:

             """
             Generate the job submission template.

             Args:
-                command (str, optional): The command to be executed.
+                command (str): The command to be executed.
+                submission_template (Union[str, Template]): The submission script template.
                 working_directory (str): The working directory.
-                job_name (str, optional): The job name. Defaults to "pysqa".
-                working_directory (str, optional): The working directory. Defaults to ".".
+                job_name (str, optional): The job name. Defaults to "pysqa".
                 cores (int, optional): The number of cores. Defaults to 1.
                 memory_max (int, optional): The maximum memory. Defaults to None.
                 run_time_max (int, optional): The maximum run time. Defaults to None.
                 dependency_list (list[int], optional): The list of dependency job IDs. Defaults to None.
+                **kwargs: Additional keyword arguments.
-                submission_template (str): Submission script template pysqa.wrapper.torque.template

             Returns:
                 str: The rendered job submission template.
             """

Ensure that the function signature and docstring parameters are consistent, accurately reflect default values, and document all parameters.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def render_submission_template(
command: str,
submission_template: Union[str, Template],
working_directory: str,
job_name: str = "pysqa",
cores: int = 1,
memory_max: Optional[int] = None,
run_time_max: Optional[int] = None,
dependency_list: Optional[List[int]] = None,
**kwargs,
) -> str:
"""
Returns the command to get the status of the job queue.
Generate the job submission template.
Args:
command (str, optional): The command to be executed.
job_name (str, optional): The job name. Defaults to "pysqa".
working_directory (str, optional): The working directory. Defaults to ".".
cores (int, optional): The number of cores. Defaults to 1.
def render_submission_template(
command: str,
submission_template: Union[str, Template],
working_directory: str,
job_name: str = "pysqa",
cores: int = 1,
memory_max: Optional[int] = None,
run_time_max: Optional[int] = None,
dependency_list: Optional[List[int]] = None,
**kwargs,
) -> str:
"""
Generate the job submission template.
Args:
command (str): The command to be executed.
submission_template (Union[str, Template]): The submission script template.
working_directory (str): The working directory.
job_name (str, optional): The job name. Defaults to "pysqa".
cores (int, optional): The number of cores. Defaults to 1.
memory_max (int, optional): The maximum memory. Defaults to None.
run_time_max (int, optional): The maximum run time. Defaults to None.
dependency_list (list[int], optional): The list of dependency job IDs. Defaults to None.
**kwargs: Additional keyword arguments.
Returns:
str: The rendered job submission template.
"""

Comment on lines +36 to +38
{%- if dependency %}
#PBS -W depend=afterok:{{ dependency | join(':') }}
{%- endif %}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix variable name inconsistency between dependency_list and dependency

In the submission template, the variable dependency is used, but in the render_submission_template method, the parameter is named dependency_list. This inconsistency may cause a KeyError during template rendering.

Apply this diff to fix the inconsistency:

# In the template (lines 36-38):
-{%- if dependency %}
-#PBS -W depend=afterok:{{ dependency | join(':') }}
+{%- if dependency_list %}
+#PBS -W depend=afterok:{{ dependency_list | join(':') }}
 {%- endif %}

# In the `render_submission_template` method (line 165):
-                dependency_list=dependency_list,
+                dependency=dependency_list,

Also applies to: 165-165

memory_max (int, optional): The maximum memory. Defaults to None.
run_time_max (int, optional): The maximum run time. Defaults to None.
dependency_list (list[int], optional): The list of dependency job IDs. Defaults to None.
submission_template (str): Submission script template pysqa.wrapper.torque.template
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Update the docstring for submission_template parameter

The docstring for submission_template mentions pysqa.wrapper.torque.template, which is incorrect for the SLURM scheduler. Please update it to reflect the correct template.

Apply this diff to fix the docstring:

             submission_template (str): Submission script template
-                pysqa.wrapper.torque.template
+                Default SLURM submission script template.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
submission_template (str): Submission script template pysqa.wrapper.torque.template
submission_template (str): Submission script template
Default SLURM submission script template.

Comment on lines +35 to +37
{%- if dependency %}
#SBATCH --dependency=afterok:{{ dependency | join(',') }}
{%- endif %}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Inconsistent variable name dependency vs dependency_list

In the template, the variable dependency is used, but in the render_submission_template method, the parameter is named dependency_list. This inconsistency will lead to a KeyError when rendering the template. Please ensure that the variable names match between the template and the method.

Apply this diff to fix the issue:

-{%- if dependency %}
-#SBATCH --dependency=afterok:{{ dependency | join(',') }}
+{%- if dependency_list %}
+#SBATCH --dependency=afterok:{{ dependency_list | join(',') }}
 {%- endif %}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{%- if dependency %}
#SBATCH --dependency=afterok:{{ dependency | join(',') }}
{%- endif %}
{%- if dependency_list %}
#SBATCH --dependency=afterok:{{ dependency_list | join(',') }}
{%- endif %}

Comment on lines +25 to +44
template = """\
#!/bin/bash
#SBATCH --output=time.out
#SBATCH --job-name={{job_name}}
#SBATCH --chdir={{working_directory}}
#SBATCH --get-user-env=L
#SBATCH --partition={{partition}}
{%- if run_time_max %}
#SBATCH --time={{ [1, run_time_max // 60]|max }}
{%- endif %}
{%- if dependency %}
#SBATCH --dependency=afterok:{{ dependency | join(',') }}
{%- endif %}
{%- if memory_max %}
#SBATCH --mem={{memory_max}}G
{%- endif %}
#SBATCH --cpus-per-task={{cores}}

{{command}}
"""
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Undefined variable partition in the template

The partition variable is used in the submission template but is not provided to the render_submission_template method or passed during template rendering. This will cause a KeyError when rendering the template. Consider adding a partition parameter to the method and passing it to the template.

Apply this diff to fix the issue:

 def render_submission_template(
     command: str,
     job_name: str = "pysqa",
     working_directory: str = os.path.abspath("."),
     cores: int = 1,
     memory_max: Optional[int] = None,
     run_time_max: Optional[int] = None,
+    partition: str = "default",
     dependency_list: Optional[List[int]] = None,
     submission_template: Union[str, Template] = template,
     **kwargs,
 ) -> str:
     ...
     return submission_template.render(
         command=command,
         job_name=job_name,
         working_directory=working_directory,
         cores=cores,
         memory_max=memory_max,
         run_time_max=run_time_max,
+        partition=partition,
         dependency_list=dependency_list,
         **kwargs,
     )

Committable suggestion was skipped due to low confidence.


🛠️ Refactor suggestion

Enhance the submission template with optional email notifications

Consider adding optional parameters for email notifications to inform users about job start, completion, or failure events. This can improve user experience for long-running jobs.

Modify the template to include email options:

{%- if email %}
#SBATCH --mail-user={{ email }}
{%- endif %}
{%- if email_events %}
#SBATCH --mail-type={{ email_events | join(',') }}
{%- endif %}

Update the method parameters and rendering context:

 def render_submission_template(
     command: str,
     job_name: str = "pysqa",
     working_directory: Optional[str] = None,
     cores: int = 1,
     memory_max: Optional[int] = None,
     run_time_max: Optional[int] = None,
     dependency_list: Optional[List[int]] = None,
+    email: Optional[str] = None,
+    email_events: Optional[List[str]] = None,
     submission_template: Union[str, Template] = template,
     **kwargs,
 ) -> str:
+    if working_directory is None:
+        working_directory = os.path.abspath(".")
     ...
     return submission_template.render(
         command=command,
         job_name=job_name,
         working_directory=working_directory,
         cores=cores,
         memory_max=memory_max,
         run_time_max=run_time_max,
         dependency_list=dependency_list,
+        email=email,
+        email_events=email_events,
         **kwargs,
     )

Committable suggestion was skipped due to low confidence.


🛠️ Refactor suggestion

Consider simplifying the runtime calculation in the template

The expression {{ [1, run_time_max // 60]|max }} may be unnecessarily complex. If run_time_max is already provided in minutes or the appropriate SLURM time format, you can use it directly.

Modify the template line:

-#SBATCH --time={{ [1, run_time_max // 60]|max }}
+#SBATCH --time={{ run_time_max }}

Ensure that run_time_max is provided in the correct format expected by SLURM (e.g., minutes, hours:minutes:seconds, or days-hours).

Committable suggestion was skipped due to low confidence.

def render_submission_template(
command: str,
job_name: str = "pysqa",
working_directory: str = os.path.abspath("."),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid using function calls in default parameter values

The default value os.path.abspath(".") is evaluated at function definition time, which may not reflect the current working directory when the function is called. It's better to set the default to None and compute it inside the function.

Apply this diff to fix the issue:

 def render_submission_template(
     command: str,
     job_name: str = "pysqa",
-    working_directory: str = os.path.abspath("."),
+    working_directory: Optional[str] = None,
     cores: int = 1,
     memory_max: Optional[int] = None,
     run_time_max: Optional[int] = None,
     dependency_list: Optional[List[int]] = None,
     submission_template: Union[str, Template] = template,
     **kwargs,
 ) -> str:
+    if working_directory is None:
+        working_directory = os.path.abspath(".")
     ...
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
working_directory: str = os.path.abspath("."),
def render_submission_template(
command: str,
job_name: str = "pysqa",
working_directory: Optional[str] = None,
cores: int = 1,
memory_max: Optional[int] = None,
run_time_max: Optional[int] = None,
dependency_list: Optional[List[int]] = None,
submission_template: Union[str, Template] = template,
**kwargs,
) -> str:
if working_directory is None:
working_directory = os.path.abspath(".")
...

Copy link

@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: 2

🧹 Outside diff range and nitpick comments (2)
tests/test_scheduler_commands.py (1)

Line range hint 6-58: Consider expanding test coverage for SchedulerCommands.

While the existing tests cover basic functionality and error cases, the move to an abstract base class might introduce new methods or behaviors that require testing.

Consider the following improvements:

  1. Review the abstract SchedulerCommands class for any new methods or behaviors that aren't currently tested.
  2. Add tests for any new functionality introduced in the abstract class.
  3. Ensure that the TmpSchedularCommands class correctly implements all required methods from the abstract base class.

To help identify any new methods that might need testing, you can run:

#!/bin/bash
# Description: List methods in the SchedulerCommands class

# Test: Extract method names from the SchedulerCommands class
ast-grep --lang python --pattern 'class SchedulerCommands($_):
  $$$
  def $METHOD($_) {
    $$$
  }
  $$$
' pysqa/wrapper/abstract.py | grep -oP '(?<=def )\w+'

Compare the output with the existing tests and add coverage for any missing methods.

pysqa/wrapper/abstract.py (1)

68-107: LGTM with a minor suggestion: Consider improving submission_template parameter.

The render_submission_template method is well-implemented and documented. It enhances the class's functionality by allowing dynamic job submission template generation. The use of type hints and comprehensive docstring is commendable.

However, there's a minor inconsistency in the submission_template parameter:

Consider updating the type hint and docstring for the submission_template parameter to reflect that it can be either a string or a Template object. Here's a suggested change:

-    submission_template: Union[str, Template],
+    submission_template: Union[str, Template],
     job_name: str = "pysqa",
     working_directory: str = os.path.abspath("."),
     cores: int = 1,
     memory_max: Optional[int] = None,
     run_time_max: Optional[int] = None,
     dependency_list: Optional[List[int]] = None,
     **kwargs,
 ) -> str:
     """
     Generate the job submission template.

     Args:
         command (str, optional): The command to be executed.
         job_name (str, optional): The job name. Defaults to "pysqa".
         working_directory (str, optional): The working directory. Defaults to ".".
         cores (int, optional): The number of cores. Defaults to 1.
         memory_max (int, optional): The maximum memory. Defaults to None.
         run_time_max (int, optional): The maximum run time. Defaults to None.
         dependency_list (list[int], optional): The list of dependency job IDs. Defaults to None.
-        submission_template (str): Submission script template pysqa.wrapper.torque.template
+        submission_template (Union[str, Template]): Submission script template as a string or Template object.

This change would make the method signature and docstring more consistent with the actual implementation.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 2a60f35 and 8cf1ac6.

📒 Files selected for processing (9)
  • pysqa/utils/basic.py (2 hunks)
  • pysqa/wrapper/abstract.py (3 hunks)
  • pysqa/wrapper/flux.py (2 hunks)
  • pysqa/wrapper/lsf.py (3 hunks)
  • pysqa/wrapper/moab.py (3 hunks)
  • pysqa/wrapper/sge.py (3 hunks)
  • pysqa/wrapper/slurm.py (3 hunks)
  • pysqa/wrapper/torque.py (3 hunks)
  • tests/test_scheduler_commands.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • pysqa/utils/basic.py
  • pysqa/wrapper/flux.py
  • pysqa/wrapper/lsf.py
  • pysqa/wrapper/moab.py
  • pysqa/wrapper/sge.py
  • pysqa/wrapper/slurm.py
🔇 Additional comments (8)
pysqa/wrapper/abstract.py (3)

25-33: LGTM: Well-defined abstract property method.

The enable_reservation_command property method is correctly implemented as an abstract method. It follows the established pattern in the class, has appropriate type hints, and includes a clear docstring.


5-10: LGTM: Appropriate imports and consistent file structure.

The addition of the Jinja2 Template import is necessary for the new render_submission_template method. The overall file structure remains consistent with the abstract base class pattern, maintaining good coding practices.


Line range hint 1-108: Summary: Well-implemented enhancements to the SchedulerCommands class.

The changes to this file enhance the SchedulerCommands abstract base class by adding two new methods:

  1. enable_reservation_command: A new abstract property method for enabling job reservation.
  2. render_submission_template: A static method for generating job submission templates using Jinja2.

These additions improve the flexibility and functionality of the job scheduling system. The implementation maintains consistent coding style, proper use of type hints, and comprehensive documentation.

pysqa/wrapper/torque.py (5)

5-7: LGTM: Import statements are appropriate

The added import statements for os, re, and Union from typing are necessary for the new functionality and follow good practices.


9-10: LGTM: Additional imports are appropriate

The added import statements for pandas and Template from jinja2 are necessary for the new template rendering functionality and follow good practices.


128-166: LGTM: render_submission_template method is well-structured

The render_submission_template method is well-structured and properly uses super() to call the parent class's method. The method signature and docstring are appropriate for the job submission requirements.

However, please ensure that the previously mentioned issues are addressed:

  1. The inconsistency between dependency_list and dependency.
  2. The formatting of run_time_max to HH:MM:SS.

Line range hint 1-166: Summary: Good implementation with minor issues to address

The implementation of the default submission template for the Torque job scheduler is generally well-done. The new render_submission_template method and the template string enhance the functionality of the TorqueCommands class.

However, there are two main issues that need to be addressed:

  1. The inconsistency between dependency_list and dependency in the template and method signature.
  2. The potential incorrect formatting of run_time_max for Torque's walltime parameter.

Once these issues are resolved, the implementation will be robust and consistent with the requirements of the Torque job scheduler.


36-38: ⚠️ Potential issue

Fix variable name inconsistency between dependency_list and dependency

In the submission template, the variable dependency is used, but in the render_submission_template method, the parameter is named dependency_list. This inconsistency may cause a KeyError during template rendering.

Apply this diff to fix the inconsistency:

{%- if dependency %}
#PBS -W depend=afterok:{{ dependency | join(':') }}
{%- endif %}

to:

{%- if dependency_list %}
#PBS -W depend=afterok:{{ dependency_list | join(':') }}
{%- endif %}

Also, update the render_submission_template method accordingly:

-                dependency_list=dependency_list,
+                dependency=dependency_list,

Likely invalid or redundant comment.

@@ -1,5 +1,5 @@
import unittest
from pysqa.wrapper.generic import SchedulerCommands
from pysqa.wrapper.abstract import SchedulerCommands
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Update tests to use concrete SchedulerCommands subclasses.

The SchedulerCommands class has been refactored to an abstract base class in pysqa/wrapper/abstract.py, and several concrete subclasses (e.g., TorqueCommands, SlurmCommands) now inherit from it. Ensure that tests/test_scheduler_commands.py imports and utilizes these concrete implementations instead of the abstract class to maintain valid and comprehensive test coverage.

🔗 Analysis chain

Verify test coverage after import change.

The import statement has been updated to import SchedulerCommands from pysqa.wrapper.abstract instead of pysqa.wrapper.generic. This change might indicate a significant refactoring or relocation of the SchedulerCommands class.

Please ensure that:

  1. The existing tests are still valid and cover all necessary aspects of the refactored SchedulerCommands class.
  2. Any new methods or behaviors introduced in the abstract version are adequately tested.
  3. The TmpSchedularCommands class still correctly inherits from and implements the abstract SchedulerCommands.

To verify the changes in the SchedulerCommands class, you can run the following script:

This will help identify any changes in the class definition that might require updates to the tests.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Compare the old and new SchedulerCommands classes

# Test: Check the differences between the old and new SchedulerCommands classes
rg --type python -A 20 'class SchedulerCommands' pysqa/wrapper/

Length of output: 96


Script:

#!/bin/bash
# Description: Compare the old and new SchedulerCommands classes

# Test: Check the differences between the old and new SchedulerCommands classes
rg --type py -A 20 'class SchedulerCommands' pysqa/wrapper/

Length of output: 1169


Script:

#!/bin/bash
# Description: Find concrete implementations of SchedulerCommands

# Search for classes that inherit from SchedulerCommands and are not abstract
rg --type py 'class\s+\w+\(SchedulerCommands\):' pysqa/wrapper/

Length of output: 443

Comment on lines +33 to +34
#PBS -l walltime={{run_time_max}}
{%- endif %}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure run_time_max is formatted as HH:MM:SS for Torque's walltime

Torque's walltime parameter expects time in HH:MM:SS format. Currently, run_time_max might be provided as an integer (e.g., total seconds), which could lead to incorrect scheduling.

Consider converting run_time_max to the appropriate format before rendering the template. Here's how you can adjust the code:

# In the `render_submission_template` method before rendering:
if run_time_max is not None:
    run_time_max = "{:02d}:{:02d}:{:02d}".format(
        run_time_max // 3600,
        (run_time_max % 3600) // 60,
        run_time_max % 60
    )

Copy link

@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: 9

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 8cf1ac6 and 8f44370.

📒 Files selected for processing (2)
  • pysqa/utils/basic.py (4 hunks)
  • pysqa/utils/core.py (1 hunks)
🧰 Additional context used
🪛 Ruff
pysqa/utils/core.py

61-61: Use key in dict instead of key in dict.keys()

Remove .keys()

(SIM118)


84-87: Do not call getattr with a constant attribute value. It is not any safer than normal property access.

Replace getattr with attribute access

(B009)

🔇 Additional comments (1)
pysqa/utils/basic.py (1)

190-190: ⚠️ Potential issue

Ensure compatibility of submission_template parameter with superclass method

Adding the submission_template parameter to _job_submission_template may cause issues if the superclass method does not accept this parameter. This could lead to a TypeError when calling super()._job_submission_template().

Run the following script to verify if the superclass method accepts submission_template:

Comment on lines +40 to +42
super().__init__(
queue_type=config["queue_type"], execute_command=execute_command
)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure 'queue_type' key exists in config to avoid KeyError

The call to super().__init__ uses config["queue_type"]. If 'queue_type' is not present in the config dictionary, this will raise a KeyError. Consider adding error handling or providing a default value to prevent this issue.

Apply this diff to handle missing 'queue_type' key:

 def __init__(
     self,
     config: dict,
     directory: str = "~/.queues",
     execute_command: callable = execute_command,
 ):
+    queue_type = config.get("queue_type")
+    if queue_type is None:
+        raise ValueError("The 'queue_type' key is missing in the config dictionary.")
     super().__init__(
-        queue_type=config["queue_type"], execute_command=execute_command
+        queue_type=queue_type, execute_command=execute_command
     )

Alternatively, you can set a default queue_type if appropriate.

Committable suggestion was skipped due to low confidence.

Comment on lines +234 to +236
return super()._job_submission_template(
queue=None,
submission_template=active_queue["template"],
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure 'template' key exists in active_queue to avoid KeyError

The code accesses active_queue["template"]. If the 'template' key is missing in active_queue, this will raise a KeyError. Please ensure that all active queues have a 'template' defined or add error handling to manage missing templates.

Apply this diff to handle missing 'template' key:

 if queue not in self.queue_list:
     raise ValueError(
         "The queue "
         + queue
         + " was not found in the list of queues: "
         + str(self.queue_list)
     )
 active_queue = self._config["queues"][queue]
+if "template" not in active_queue:
+    raise ValueError("The active queue does not have a 'template' defined.")
 cores, run_time_max, memory_max = self.check_queue_parameters(
     queue=None,
     cores=cores,
     run_time_max=run_time_max,
     memory_max=memory_max,
     active_queue=active_queue,
 )
 return super()._job_submission_template(
     queue=None,
     submission_template=active_queue["template"],
     job_name=job_name,

Alternatively, provide a default template or handle this scenario gracefully.

Committable suggestion was skipped due to low confidence.

Comment on lines +245 to +250
df_selected = df[df["jobid"] == process_id]["status"]
if len(df_selected) != 0:
results_lst.append(df_selected.values[0])
else:
results_lst.append("finished")
return results_lst
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid assuming job status is 'finished' when not found

Setting the job status to "finished" when the job ID is not found may be inaccurate, as the job could be pending, failed, or cancelled. Consider setting the status to "unknown" or implementing additional checks.

Apply this diff:

                if len(df_selected) != 0:
                    results_lst.append(df_selected.values[0])
                else:
-                    results_lst.append("finished")
+                    results_lst.append("unknown")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
df_selected = df[df["jobid"] == process_id]["status"]
if len(df_selected) != 0:
results_lst.append(df_selected.values[0])
else:
results_lst.append("finished")
return results_lst
df_selected = df[df["jobid"] == process_id]["status"]
if len(df_selected) != 0:
results_lst.append(df_selected.values[0])
else:
results_lst.append("unknown")
return results_lst

os.makedirs(working_directory)
queue_script_path = os.path.join(working_directory, "run_queue.sh")
with open(queue_script_path, "w") as f:
f.writelines(queue_script)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Use write() instead of writelines() when writing a string

The writelines() method expects an iterable of strings, but queue_script is a single string. Use write() to correctly write the content.

Apply this diff:

            with open(queue_script_path, "w") as f:
-                f.writelines(queue_script)
+                f.write(queue_script)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
f.writelines(queue_script)
with open(queue_script_path, "w") as f:
f.write(queue_script)

Comment on lines 84 to 87
self._submission_template = getattr(
importlib.import_module(queue_type_dict[queue_type]["module_name"]),
"template",
)
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid unnecessary use of getattr with a constant attribute

Since 'template' is a constant attribute name, you can access it directly for better readability.

Apply this diff:

-            self._submission_template = getattr(
-                importlib.import_module(queue_type_dict[queue_type]["module_name"]),
-                "template",
-            )
+            module = importlib.import_module(queue_type_dict[queue_type]["module_name"])
+            self._submission_template = module.template
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
self._submission_template = getattr(
importlib.import_module(queue_type_dict[queue_type]["module_name"]),
"template",
)
module = importlib.import_module(queue_type_dict[queue_type]["module_name"])
self._submission_template = module.template
🧰 Tools
🪛 Ruff

84-87: Do not call getattr with a constant attribute value. It is not any safer than normal property access.

Replace getattr with attribute access

(B009)

Copy link

@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: 6

🧹 Outside diff range and nitpick comments (2)
pysqa/wrapper/gent.py (2)

21-22: Consider renaming the module-level template variable.

The assignment of template_slurm to a new variable named template is correct and likely part of a standardization effort. However, this creates a potential naming confusion since template is now both a module-level variable and an imported name.

To improve clarity, consider renaming the module-level variable to something more specific, such as gent_template or default_template.

Here's a suggested change:

- template = template_slurm
+ gent_template = template_slurm

This change would make the code more explicit and reduce the potential for confusion.


Line range hint 26-95: Consider updating GentCommands to use the new template.

The introduction of the template object from the slurm module suggests a move towards standardization of job submission templates. However, the GentCommands class doesn't currently use this new template.

To fully implement this change:

  1. Consider adding a render_submission_template method to GentCommands that uses the new template.
  2. Update existing methods in GentCommands to use the new template where appropriate.

This would ensure consistency with the apparent goal of standardizing template usage across different queue adapters.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 8f44370 and ffd620b.

📒 Files selected for processing (3)
  • pysqa/queueadapter.py (2 hunks)
  • pysqa/utils/core.py (1 hunks)
  • pysqa/wrapper/gent.py (2 hunks)
🧰 Additional context used
🪛 Ruff
pysqa/utils/core.py

61-61: Use key in dict instead of key in dict.keys()

Remove .keys()

(SIM118)


85-88: Do not call getattr with a constant attribute value. It is not any safer than normal property access.

Replace getattr with attribute access

(B009)

🔇 Additional comments (5)
pysqa/wrapper/gent.py (1)

8-8: LGTM: Import statement for template looks good.

The import statement correctly brings in the template object from the slurm module and aliases it as template_slurm. This prepares for its usage later in the file.

pysqa/queueadapter.py (2)

5-5: LGTM: Import statement updated correctly.

The import statement has been appropriately updated to include Tuple and Union from the typing module. This change is necessary to support the new type annotation in the check_queue_parameters method and follows best practices for type hinting in Python.


Line range hint 1-391: Overall assessment: Improvements in type safety with minor documentation update needed.

The changes in this file enhance type safety and specificity, particularly in the check_queue_parameters method. The updated import statement and method signature are well-implemented. The only remaining task is to update the method's docstring to reflect the new return type accurately.

These changes contribute to better code quality and maintainability. Great job on improving the type annotations!

pysqa/utils/core.py (2)

343-343: ⚠️ Potential issue

Use write() instead of writelines() for writing a single string

The writelines() method expects an iterable of strings, but queue_script is a single string.

Use write() to correctly write the content. Apply this diff:

        with open(queue_script_path, "w") as f:
-            f.writelines(queue_script)
+            f.write(queue_script)

Likely invalid or redundant comment.


246-251: ⚠️ Potential issue

Reconsider default status for jobs not found in queue

Setting the job status to "finished" when the job ID is not found may be inaccurate. The job could be in various states like pending, failed, or cancelled.

Consider setting the status to "unknown" or implementing additional checks to determine the actual status. Apply this diff as a starting point:

            if len(df_selected) != 0:
                results_lst.append(df_selected.values[0])
            else:
-                results_lst.append("finished")
+                results_lst.append("unknown")

Likely invalid or redundant comment.

Comment on lines +329 to +331
) -> Tuple[
Union[float, int, None], Union[float, int, None], Union[float, int, None]
]:
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Approve signature change and update docstring.

The method signature update improves type safety and code readability by providing a more specific return type annotation. This change is beneficial for maintainability and helps catch potential type-related errors early.

However, the method's docstring still mentions returning a List, which is now inconsistent with the new Tuple return type.

Please update the docstring to reflect the new return type. For example:

"""
...
Returns:
    Tuple[Union[float, int, None], Union[float, int, None], Union[float, int, None]]: A tuple containing the checked parameters (cores, run_time_max, memory_max).
"""

Also, ensure that the method implementation returns a tuple that matches this new type annotation.

Returns:
SchedulerCommands: queuing system commands class instance
"""
if queue_type in queue_type_dict.keys():
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Simplify dictionary membership check

The current check if queue_type in queue_type_dict.keys(): can be simplified to improve readability and performance slightly.

Apply this diff to simplify the dictionary membership check:

-if queue_type in queue_type_dict.keys():
+if queue_type in queue_type_dict:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if queue_type in queue_type_dict.keys():
if queue_type in queue_type_dict:
🧰 Tools
🪛 Ruff

61-61: Use key in dict instead of key in dict.keys()

Remove .keys()

(SIM118)

process_id (int): The process ID.

Returns:
str: The status of the job.results_lst.append(df_selected.values[0])
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Correct the docstring return description in get_status_of_job

The return description includes an unintended code snippet, which may confuse users.

Apply this diff to fix the docstring:

-            str: The status of the job.results_lst.append(df_selected.values[0])
+            str: The status of the job.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
str: The status of the job.results_lst.append(df_selected.values[0])
str: The status of the job.

Comment on lines +84 to +88
if queue_type_dict[queue_type]["module_name"] is not None:
self._submission_template = getattr(
importlib.import_module(queue_type_dict[queue_type]["module_name"]),
"template",
)
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Simplify attribute access for template

The use of getattr with a constant attribute name can be simplified for better readability.

Apply this diff to simplify the attribute access:

-        self._submission_template = getattr(
-            importlib.import_module(queue_type_dict[queue_type]["module_name"]),
-            "template",
-        )
+        module = importlib.import_module(queue_type_dict[queue_type]["module_name"])
+        self._submission_template = module.template
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if queue_type_dict[queue_type]["module_name"] is not None:
self._submission_template = getattr(
importlib.import_module(queue_type_dict[queue_type]["module_name"]),
"template",
)
if queue_type_dict[queue_type]["module_name"] is not None:
module = importlib.import_module(queue_type_dict[queue_type]["module_name"])
self._submission_template = module.template
🧰 Tools
🪛 Ruff

85-88: Do not call getattr with a constant attribute value. It is not any safer than normal property access.

Replace getattr with attribute access

(B009)

Comment on lines +375 to +377
if queue is not None:
raise ValueError()
if submission_template is None:
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Improve error handling when queue is specified

Raising a ValueError without a message when queue is not None can be unclear to users.

Consider providing a clear error message or removing the queue parameter if it's not supported. Here's an example of adding an informative error message:

        if queue is not None:
-            raise ValueError()
+            raise ValueError("Specifying 'queue' is not supported in this context.")

Alternatively, if the queue parameter is not used at all, consider removing it from the method signature and any references within the method.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if queue is not None:
raise ValueError()
if submission_template is None:
if queue is not None:
raise ValueError("Specifying 'queue' is not supported in this context.")
if submission_template is None:

Comment on lines +323 to +325
if isinstance(command, list):
command = "".join(command)
if working_directory is None:
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Use appropriate separator when joining commands

Using "".join(command) concatenates the commands without any separators, which may result in invalid command strings.

Consider joining with a newline or space, depending on your specific use case. Apply this diff to join commands with newlines:

        if isinstance(command, list):
-            command = "".join(command)
+            command = "\n".join(command)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if isinstance(command, list):
command = "".join(command)
if working_directory is None:
if isinstance(command, list):
command = "\n".join(command)
if working_directory is None:

# Conflicts:
#	pysqa/utils/basic.py
#	pysqa/wrapper/abstract.py
#	pysqa/wrapper/flux.py
#	pysqa/wrapper/gent.py
#	pysqa/wrapper/lsf.py
#	pysqa/wrapper/moab.py
#	pysqa/wrapper/sge.py
#	pysqa/wrapper/slurm.py
#	pysqa/wrapper/torque.py
@jan-janssen jan-janssen merged commit 5e5caa9 into main Sep 28, 2024
18 checks passed
@jan-janssen jan-janssen deleted the submission_template branch September 28, 2024 14:28
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