Package: ts-task-script-utils
ts-task-script-utilsVersionv2.1.0Table of ContentsSummaryInstallationUsageParsing NumbersParsing DatetimesDatetimeParserUsageGenerating Random UUIDs for Task ScriptsUsing Python'sloggingmodule in Task ScriptsWellPositionChangelogv2.1.0v2.0.1v2.0.0v1.9.0v1.8.1v1.8.0v1.7.0v1.6.0v1.5.0v1.4.0v1.3.1v1.3.0v1.2.0v1.1.1v1.1.0SummaryUtility functions for Tetra Task ScriptsInstallationpip install ts-task-script-utilsUsageParsing Numbersfromtask_script_utils.parseimportto_intstring_value='1.0'int_value=to_int(string_value)# `int_value` now has the parsed value of the stringassertisinstance(int_value,int)assertint_value==1# it returns `None` if the value is unparseablestring_value='not an int'int_value=to_int(string_value)assertint_valueisNoneParsing Datetimes[!WARNING]DEPRECATIONDo not use the old datetime parsing functions:convert_datetime_to_ts_formatfromtask_script_utils.convert_datetime_to_ts_formatparsefromtask_script_utils.datetime_parserUse theDatetimeParserfromtask_script_utils.datetime_parserto parse datetimes.DatetimeParsertakes a list of formats used for parsing datetimes.DatetimeParserdoes not infer the structure of a datetime string, formats must be provided.DatetimeParserUsageUsingDatetimeParserwith a list of formatsfromtask_script_utils.datetime_parserimportDatetimeParserdatetime_parser=DatetimeParser(formats=["YYYY-MM-DD[T]hh:mm A Z"])ts_formatted_datetime:str|None=datetime_parser.to_tsformat("2004-12-23T12:30 AM +05:30")UsingDatetimeParserwith a timezone mapping and a list of formatsfromtask_script_utils.datetime_parserimportDatetimeParserformats=["YYYY-MM-DD[T]hh:mm A zz"]tz_dict={"EST":"-05:00"}datetime_parser=DatetimeParser(formats=formats,tz_dict=tz_dict)ts_formatted_datetime:str|None=datetime_parser.to_tsformat("2004-12-23T12:30 AM EST")If you need theTSDatetimeobject, you can useDatetimeParser.parse() -> TSDatetime.TSDatetimegives access toTSDatetime.datetimewhich can be used as a regular python datetime object.You can read more about the datetime parserhere.Generating Random UUIDs for Task ScriptsTo generate standard and random UUIDs, Python'suuidmodule can be used (uuid1for standard anduuid4for random).
However, to get UUIDs that are reproducible for a given task script and input file, a custom UUID generator is provided:task_script_utils.random.TaskScriptUUIDGenerator.frompathlibimportPathfromtask_script_utils.randomimportTaskScriptUUIDGeneratorinput_file=Path(...)file_content=input_file.read_bytes()rand=TaskScriptUUIDGenerator("common/my-task-script:v1.0.0",file_content)# Get 3 random bytes:random_bytes=rand.randbytes(3)# Get a random UUID:uuid=rand.uuid()It's also possible to use a class method and provide the task script identifiers separately:frompathlibimportPathfromtask_script_utils.randomimportTaskScriptUUIDGeneratorinput_file=Path(...)file_content=input_file.read_bytes()rand=TaskScriptUUIDGenerator.from_task_script_identifier_parts("common","my-task-script","v1.0.0",file_content)The class uses a pattern similar to the singleton pattern that allows to create an instance once and then "get the last created" instance later without passing the instance around.
This is achieved with theget_last_createdmethod:frompathlibimportPathfromtask_script_utils.randomimportTaskScriptUUIDGeneratorinput_file=Path(...)file_content=input_file.read_bytes()rand1=TaskScriptUUIDGenerator("common/my-task-script:v1.0.0",file_content)rand2=TaskScriptUUIDGenerator.get_last_created()assertrand1isrand2If no instance has been created before,NoPreviouslyCreatedInstanceErrorwill be raised.Note that the arguments used to create aTaskScriptUUIDGeneratormakes up the seed for the RNG and two instances made with the same seed will go through the same sequence of UUIDs.
That is usually unintentional in the context of a Task Script where the UUIDs should be unique.frompathlibimportPathfromtask_script_utils.randomimportTaskScriptUUIDGeneratorinput_file=Path(...)file_content=input_file.read_bytes()rand1=TaskScriptUUIDGenerator("common/my-task-script:v1.0.0",file_content)rand2=TaskScriptUUIDGenerator("common/my-task-script:v1.0.0",file_content)assertrand1.uuid()==rand2.uuid()assertrand1.uuid()==rand2.uuid()Using Python'sloggingmodule in Task ScriptsTask Scripts can write workflow logs which are visible to users on TDP, but only if the logs are written via the logger provided by thecontextobject. Thecontextlogger is documented here:context.get_logger.This utility is a wrapper for thecontextlogger which allows Task Scripts to use Python'sloggingmodule for creating TDP workflow logs, instead of directly using thecontextlogger object. This means thecontextlogger object doesn't need to be passed around to each function which needs to do logging, and Task Script code can benefit from other features of the Pythonloggingmodule such asintegration withpytest.To log warning messages on the platform from a task script do the following:Setup the log handler inmain.py:fromtask_script_utils.workflow_loggingimport(setup_ts_log_handler,)Then within the function called by the protocol:setup_ts_log_handler(context.get_logger(),"main")In a module where you wish to log a warning:importlogginglogger=logging.getLogger("main."+__name__)Log a warning message with:logger.warning("This is a warning message")WellPositionFor plate readers, you can parse the well label usingtask_script_utils.plate_reader.WellPosition.WellPositionencapsulates row and column indexes for a well on a plate.You can useWellPosition.from_well_labelto parse thewell_label: strand get theWellPositionobject.For example:fromplate_readerimportWellPositionWellPosition.from_well_label("P45")# returns WellPosition(row=16, column=45)Awell_labelmust satisfy following conditions:It must start with a letterIt can contain at max two lettersWhen it contains two letters, they must both be uppercaseLetter(s) must be followed by at least one and at max two digitsIf the label cannot be parsed,InvalidWellLabelErroris raised.eg,A45, a45, A01, A1, z1, z01, AC23are valid well labelsFollowing are the example of invalid well labels:A245:well_labelwith more than 2 digits is not supportedAoraoraa:well_labeldoesn't contain any digit. Hence it is not supported.aB02, Ab02, ab02: Both letters must be uppercase.Parsing forwell_labelcontaining a single letter is case sensitive ie. well labels A02 and a02 represent different wells on the plateParsing forwell_labelcontaining two letters is limited to uppercase only ie. AB01 is supported but ab01, Ab01 and aB01 are not supportedThe following are the only supported sequence of rows for a plate:A -> Z and then a -> zA -> Z and then AA -> AZForwell_labelwith single letter, even though well labels starting withw,x,y, andzare supported by the parser, in real life this is not possible as the largest plate contains3456 wellswhich is48x72, so the last well label is going to bev72.Similarly, forwell_labelwith two letters, in real life the largest possiblewell_labelwould beAV72for a plate with 3456 wells. However,well_labelbeyondAV72are also supported by parser.Changelogv2.1.0Deprecate datetime parsing functionparse(), replaced by objectDatetimeParserAddDatetimeParserUpdate to pendulum 3.0.0 and adapt to breaking changesv2.0.1Restrict pendulum to<3.0.0v2.0.0Python minimum requirement is now 3.9Removed parquet supportMade dependencies less restrictivev1.9.0Addtask_script_utils.plate_reader.WellPosition.to_labelfor converting aWellPositionto a well labelAddtask_script_utils.plate_reader.create_well_to_pk_mapfor creating a map ofWellPositionto primary keys from a list of samplesv1.8.1Update to python dependency to >=3.7.2,<4v1.8.0Addtask_script_utils.plate_reader.WellPositionfor parsing well labelsUpdatetask_script_utils.random.Singletonused byTaskScriptUUIDGeneratorand rename totask_script_utils.random.CacheLastCacheLastno longer provides singleton behavior, but it still provides the methodget_last_createdInstantiatingTaskScriptUUIDGeneratoralways seeds the random generator. A second instance will repeat the same sequence of UUIDs as the first instance (if instantiated with the same arguments).RenameNoPreviouslyCreatedSingletonErrortoNoPreviouslyCreatedInstanceErrorAdd type information toget_last_createdv1.7.0Addtask_script_utils.workflow_loggingfor logging warning messages in task scriptsv1.6.0Addtask_script_utils.datacubes.parquetfor creating Parquet file representations of datacubesv1.5.0AddTaskScriptUUIDGeneratorclass for generating random UUIDs and random bytes.v1.4.0Addextract-to-decoratefunctionsv1.3.1Update datetime parser usage in README.mdv1.3.0Added string parsing functionsv1.2.0Add boolean config parameterrequire_unambiguous_formatstoDatetimeConfigAdd logic toparser._parse_with_formatsto be used whenDatetimeConfig.require_unambiguous_formatsis set toTrueAmbiguousDatetimeFormatsErroris raised if mutually ambiguous formats are detected and differing datetimes are parsedAdd parameter typing throughout repositoryRefactordatetime_parserpackageAdd base classDateTimeInfoSegregate parsing logic intoShortDateTimeInfoandLongDateTimeInfov1.1.1Removeconvert_to_ts_iso8601()methodv1.1.0Adddatetime_parserpackage