Source code for schrodinger.ui.qt.appframework2.jobnames

"""
Functions used for updating job names.  `update_jobname` is intended for use
outside of AF2.
"""

import enum
import os
import re

import schrodinger

maestro = schrodinger.get_maestro()

# A regex used to classify job names.  This regex will capture four groups:
#  1. The modified job name prefix
#  2. The standard job name
#  3. The modified job name suffix
#  4. The entire custom job name
MOD_JOBNAME_RE = r"""
    (?:(?:(.*)    # An optional prefix
    (%s)          # The standard job name (to be interpolated later)
    (.*?))        # An optional suffix.  Note that this is a non-greedy match
                  # so that it doesn't consume the uniquifying digits.
    |(.*?))       # A custom job name if we can't match the standard job name
    """
# An optional trailing underscore and uniquifying digits
MOD_JOBNAME_RE_UNIQUIFY = r"""(?:_[\d]+)?"""


[docs]class JobnameType(enum.Enum): """ Constants describing the three categories of job names """ Standard = 1 """The standard job name generated by the panel""" Modified = 2 """The standard job name plus a user-added prefix or suffix (or both)""" Custom = 3 """A user-generated job name that doesn't contain the standard job name"""
def _is_increment_job_name_set(): """ Default behavior is to increment the job name. Don't increment if running from maestro and its increment preference is off. """ return not (maestro and maestro.get_command_option( "prefer", "incrementjobname") == "False")
[docs]def uniquify(jobname, jobtype, uniquify_custom=True, omit_one_from_standard=False, name_list=None): """ Uniquify a job name by adding a trailing integer to ensure that there are no conflicting file names in the current working directory. Standard job names will always have an integer added (e.g. jobname_1, jobname_2, jobname_3). Modified job names (and custom job names if `uniquify_custom` is True) will only have an integer added if necessary (e.g. jobname, jobname_2, jobname_3 - note that there is no "_1"). :param jobname: The job name to uniquify :type jobname: basestring :param jobtype: The job name type, which will determine the uniquifying behavior :type jobtype: `JobnameType` :param uniquify_custom: Whether we should uniquify custom job name by adding integers to the end. If False, only standard and modified job names will be uniquified. :type uniquify_custom: bool :param omit_one_from_standard: If True, standard job names will only have an integer added if necessary (i.e. <jobname> instead of <jobname>_1) :type omit_one_from_standard: bool :param name_list: Optional list of names to uniquify against. If not given, the name will be compared against the directory listing of the CWD :type name_list: list of basestring :return: The uniquified job name :rtype: basestring """ if jobtype is JobnameType.Standard: jobname = get_next_jobname(jobname, omit_one_from_standard, name_list=name_list) elif jobtype is JobnameType.Modified or uniquify_custom: jobname = get_next_jobname(jobname, True, name_list=name_list) return jobname
[docs]def determine_jobtype(current_jobname, old_standard_jobname, new_standard_jobname=None, trim_custom=False): """ Classify the current job name type and generate the new non-unique job name. Note that, as a special case, blank job names will be classified as - and replaced with - the standard job name. :param current_jobname: The job name to update and classify :type current_jobname: basestring :param old_standard_jobname: The standard job name used for classifying the current job name :type old_standard_jobname: basestring :param new_standard_jobname: The standard job name used for generating the new job name. If not given, `old_standard_jobname` will be used. :type new_standard_jobname: basestring :param trim_custom: If True, any trailing uniquifying integer will be removed from custom job names. If False, custom job names will not be modified. :type trim_custom: bool :return: A tuple of - The new non-unique job name (basestring) - The job name type (`JobnameType`) :rtype: tuple """ if new_standard_jobname is None: new_standard_jobname = old_standard_jobname if not current_jobname: return new_standard_jobname, JobnameType.Standard jobname_re = MOD_JOBNAME_RE % re.escape(old_standard_jobname) # If incrementing the jobname, strip off any appended digits if _is_increment_job_name_set(): jobname_re += MOD_JOBNAME_RE_UNIQUIFY jobname_re += "$" match = re.match(jobname_re, current_jobname, re.IGNORECASE | re.VERBOSE) pre, std, post, custom = match.groups() if std and not (pre or post): return new_standard_jobname, JobnameType.Standard elif std: jobname = pre + new_standard_jobname + post return jobname, JobnameType.Modified elif trim_custom: return custom, JobnameType.Custom else: return current_jobname, JobnameType.Custom
[docs]def update_jobname(current_jobname, standard_jobname, uniquify_custom=True, name_list=None): """ Update the job name by adding new uniquifying digits at the end :param current_jobname: The job name to update :type current_jobname: basestring :param standard_jobname: The standard job name for the panel :type old_standard_jobname: basestring :param uniquify_custom: Whether we should uniquify custom job name by adding integers to the end. If False, only standard and modified job names will be uniquified. :type uniquify_custom: bool :param name_list: Optional list of names to uniquify against. If not given, the name will be compared against the directory listing of the CWD :type name_list: list of basestring :return: The updated job name :rtype: basestring """ new_jobname, jobtype = determine_jobtype(current_jobname, standard_jobname, trim_custom=uniquify_custom) return uniquify(new_jobname, jobtype, uniquify_custom, name_list=name_list)
[docs]def get_next_jobname(jobname, omit_one=False, name_list=None): """ Given a job name, choose the next available unique job name based on the names of existing files in the current working directory :param jobname: The job name to uniquify :type jobname: basestring :param omit_one: If `jobname` is unique by itself, should we omit appending the "_1" :type omit_one: bool :param name_list: Optional list of names to uniquify against. If not given, the name will be compared against the directory listing of the CWD :type name_list: list of basestring :return: The new job name :rtype: basestring :note: This method will not return <jobname>_1 if a <jobname> file exists. Instead, it will return <jobname>_2 (or whatever the next available integer is). In other words, <jobname> and <jobname>_1 are assumed to be equivalent. """ if not _is_increment_job_name_set(): return jobname jobname_re = re.escape(jobname) + r""" (?:_([\d]+))? # A trailing underscore and uniquifying digits (?:\..*)?$ # An optional period and file extension """ if name_list is None: name_list = os.listdir(".") digits = [0] for cur_name in name_list: match = re.match(jobname_re, cur_name, re.IGNORECASE | re.VERBOSE) if match: cur_digit = match.group(1) if cur_digit is not None: cur_digit = int(cur_digit) else: cur_digit = 1 digits.append(cur_digit) suffix = max(digits) + 1 if suffix == 1 and omit_one: return jobname else: return "%s_%i" % (jobname, suffix)