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

Make modality required for all extractions #2045

Merged
merged 29 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
57cf5b5
fix for windows and avoid extra subprocess call
rkm Dec 9, 2024
b39efc4
make modality a required input for all extractions
rkm Dec 9, 2024
5ff968c
add modality to CTP messages
rkm Dec 9, 2024
75a1416
delete old tests
rkm Dec 9, 2024
6bf4b3d
add missing modality
rkm Dec 9, 2024
e82d2c9
add missing modalities
rkm Dec 9, 2024
1cbc850
re-add missing test class
rkm Dec 9, 2024
70f1146
add missing modalities
rkm Dec 9, 2024
dfd38fd
add missing modality
rkm Dec 9, 2024
ba46bef
fixup default options
rkm Dec 9, 2024
87d97dd
add missing modalities
rkm Dec 9, 2024
160119c
add missing modalities
rkm Dec 9, 2024
b299684
Merge branch 'change/require-modality' of github.com:smi/SmiServices …
rkm Dec 9, 2024
6b7f2d3
add missing modalities
rkm Dec 9, 2024
2501ec1
remove test assert
rkm Dec 9, 2024
8a761f0
add news file
rkm Dec 9, 2024
4e46312
inline test class into test project
rkm Dec 9, 2024
bfab6ca
Merge branch 'change/require-modality' of github.com:smi/SmiServices …
rkm Dec 9, 2024
e7cd4dc
add missing modalities
rkm Dec 9, 2024
9607729
try with MR not CT
rkm Dec 9, 2024
f3cdff9
try CT
rkm Dec 10, 2024
a21de2c
ensure modality specified
rkm Dec 10, 2024
8596d14
add unit tests for FromCataloguesExtractionRequestFulfiller
rkm Dec 10, 2024
8a6ad83
remove unused IAuditExtractions
rkm Dec 11, 2024
703ac32
typo
rkm Dec 11, 2024
d5bf0be
add more tests for FromCataloguesExtractionRequestFulfiller
rkm Dec 11, 2024
759e12e
move test rejectors out of src
rkm Dec 11, 2024
c16b1f7
restore RejectAll
rkm Dec 11, 2024
9b47aec
use var instead of type
rkm Dec 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion bin/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import functools
import hashlib
import os
import shlex
import subprocess
from collections.abc import Sequence

Expand Down Expand Up @@ -37,7 +38,7 @@ def run(
if env is None:
env = {}

subprocess.check_call(("echo", "$", *cmd), cwd=cwd)
print(shlex.join(("$", *cmd)))
subprocess.check_call(cmd, cwd=cwd, env={**os.environ, **env})


Expand Down
2 changes: 1 addition & 1 deletion data/microserviceConfigs/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ CohortExtractorOptions:
#RejectColumnInfos: [105,110]

AuditorType: "SmiServices.Microservices.CohortExtractor.Audit.NullAuditExtractions"
RequestFulfillerType: "SmiServices.Microservices.CohortExtractor.RequestFulfillers.FromCataloguesExtractionRequestFulfiller"
RequestFulfillerType: "FromCataloguesExtractionRequestFulfiller"
ProjectPathResolverType: "StudySeriesSOPProjectPathResolver"
ExtractAnonRoutingKey: anon
ExtractIdentRoutingKey: ident
Expand Down
1 change: 1 addition & 0 deletions news/2045-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Make modality required for all extractions
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,11 @@ public class ExtractImagesCliOptions : CliOptions
HelpText = "The CSV file containing IDs of the cohort for extraction")]
public string CohortCsvFile { get; set; } = null!;

// Optional
[Option(shortName: 'm', longName: "modality", Required = true,
HelpText = "The modality to extract. Any non-matching IDs from the input list are ignored")]
public string Modality { get; set; } = null!;

[Option(shortName: 'm', longName: "modalities", Required = false,
HelpText =
"[Optional] List of modalities to extract. Any non-matching IDs from the input list are ignored")]
public string? Modalities { get; set; }
// Optional

[Option(shortName: 'i', longName: "identifiable-extraction", Required = false,
HelpText = "Extract without performing anonymisation")]
Expand Down Expand Up @@ -56,7 +55,7 @@ public static IEnumerable<Example> Examples
{
CohortCsvFile = "my.csv",
ProjectId = "1234-5678",
Modalities = "CT",
Modality = "CT",
IsIdentifiableExtraction = true
});
yield return new Example(helpText: "Extract without applying any rejection filters",
Expand All @@ -72,7 +71,7 @@ public override string ToString()
sb.Append(base.ToString());
sb.Append($"ProjectId={ProjectId},");
sb.Append($"CohortCsvFile={CohortCsvFile},");
sb.Append($"Modalities={Modalities},");
sb.Append($"Modality={Modality},");
sb.Append($"IdentifiableExtraction={IsIdentifiableExtraction},");
sb.Append($"NoFiltersExtraction={IsNoFiltersExtraction},");
sb.Append($"NonInteractive={NonInteractive},");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class ExtractionMessageSender : IExtractionMessageSender
private readonly int _maxIdentifiersPerMessage;

private readonly string _projectId;
private readonly string[]? _modalities;
private readonly string _modality;
private readonly bool _isIdentifiableExtraction;
private readonly bool _isNoFiltersExtraction;
private readonly bool _isPooledExtraction;
Expand Down Expand Up @@ -60,7 +60,7 @@ IConsoleInput consoleInput
throw new ArgumentOutOfRangeException(nameof(options));

_projectId = (!string.IsNullOrWhiteSpace(cliOptions.ProjectId)) ? cliOptions.ProjectId : throw new ArgumentOutOfRangeException(nameof(cliOptions));
_modalities = cliOptions.Modalities?.ToUpper().Split(',', StringSplitOptions.RemoveEmptyEntries);
_modality = (!string.IsNullOrWhiteSpace(cliOptions.Modality)) ? cliOptions.Modality : throw new ArgumentOutOfRangeException(nameof(cliOptions));
_isIdentifiableExtraction = cliOptions.IsIdentifiableExtraction;
_isNoFiltersExtraction = cliOptions.IsNoFiltersExtraction;
_isPooledExtraction = cliOptions.IsPooledExtraction;
Expand All @@ -75,8 +75,6 @@ public void SendMessages(ExtractionKey extractionKey, List<string> idList)
var jobId = Guid.NewGuid();
DateTime now = _dateTimeProvider.UtcNow();

// TODO(rkm 2021-04-01) Change this to a string[] in both messages below
string? modalitiesString = _modalities == null ? null : string.Join(',', _modalities);
string userName = Environment.UserName;

var erm = new ExtractionRequestMessage
Expand All @@ -92,7 +90,7 @@ public void SendMessages(ExtractionKey extractionKey, List<string> idList)
// TODO(rkm 2021-04-01) Change this to an ExtractionKey type
KeyTag = extractionKey.ToString(),

Modalities = modalitiesString,
Modality = _modality,

// NOTE(rkm 2021-04-01) Set below
ExtractionIdentifiers = null!,
Expand All @@ -113,6 +111,7 @@ public void SendMessages(ExtractionKey extractionKey, List<string> idList)
ExtractionJobIdentifier = jobId,
ProjectNumber = _projectId,
ExtractionDirectory = _extractionDir,
Modality = _modality,
JobSubmittedAt = now,
IsIdentifiableExtraction = _isIdentifiableExtraction,
IsNoFilterExtraction = _isNoFiltersExtraction,
Expand All @@ -121,7 +120,6 @@ public void SendMessages(ExtractionKey extractionKey, List<string> idList)
KeyTag = extractionKey.ToString(),
KeyValueCount = idList.Count,
UserName = userName,
ExtractionModality = modalitiesString,
};

if (_nonInteractive)
Expand All @@ -136,11 +134,11 @@ public void SendMessages(ExtractionKey extractionKey, List<string> idList)
sb.AppendLine($"Submitted: {now:u}");
sb.AppendLine($"ProjectNumber: {_projectId}");
sb.AppendLine($"ExtractionDirectory: {_extractionDir}");
sb.AppendLine($"Modality: {_modality}");
sb.AppendLine($"ExtractionKey: {extractionKey}");
sb.AppendLine($"IsIdentifiableExtraction: {_isIdentifiableExtraction}");
sb.AppendLine($"IsNoFilterExtraction: {_isNoFiltersExtraction}");
sb.AppendLine($"IsPooledExtraction: {_isPooledExtraction}");
sb.AppendLine($"ExtractionModality: {modalitiesString ?? "<unspecified>"}");
sb.AppendLine($"UserName: {userName}");
sb.AppendLine($"KeyValueCount: {idList.Count}");
sb.AppendLine($"ExtractionRequestMessage count: {ermList.Count}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ public class ExtractFileMessage : ExtractMessage, IFileReferenceMessage
[JsonProperty(Required = Required.Always)]
public string OutputPath { get; set; } = null!;

/// <summary>
/// The modality of the specified file
/// </summary>
[JsonProperty(Required = Required.AllowNull)]
public string Modality { get; set; } = null!;


[JsonConstructor]
public ExtractFileMessage() { }
Expand Down
7 changes: 7 additions & 0 deletions src/SmiServices/Common/Messages/Extraction/ExtractMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ public abstract class ExtractMessage : MemberwiseEquatable<ExtractMessage>, IExt
[JsonProperty(Required = Required.Always)]
public string ExtractionDirectory { get; set; } = null!;

[JsonProperty(Required = Required.Always)]
public string Modality { get; set; } = null!;

[JsonProperty(Required = Required.Always)]
public DateTime JobSubmittedAt { get; set; }

Expand All @@ -39,6 +42,7 @@ protected ExtractMessage(
Guid extractionJobIdentifier,
string projectNumber,
string extractionDirectory,
string modality,
DateTime jobSubmittedAt,
bool isIdentifiableExtraction,
bool isNoFilterExtraction,
Expand All @@ -49,6 +53,7 @@ bool isPooledExtraction
ExtractionJobIdentifier = extractionJobIdentifier;
ProjectNumber = projectNumber;
ExtractionDirectory = extractionDirectory;
Modality = modality;
JobSubmittedAt = jobSubmittedAt;
IsIdentifiableExtraction = isIdentifiableExtraction;
IsNoFilterExtraction = isNoFilterExtraction;
Expand All @@ -60,6 +65,7 @@ protected ExtractMessage(IExtractMessage request)
request.ExtractionJobIdentifier,
request.ProjectNumber,
request.ExtractionDirectory,
request.Modality,
request.JobSubmittedAt,
request.IsIdentifiableExtraction,
request.IsNoFilterExtraction,
Expand All @@ -71,6 +77,7 @@ public override string ToString() =>
$"ExtractionJobIdentifier={ExtractionJobIdentifier}, " +
$"ProjectNumber={ProjectNumber}, " +
$"ExtractionDirectory={ExtractionDirectory}, " +
$"Modality={Modality}, " +
$"JobSubmittedAt={JobSubmittedAt:s}, " +
$"IsIdentifiableExtraction={IsIdentifiableExtraction}, " +
$"IsNoFilterExtraction={IsNoFilterExtraction}, " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,13 @@ public class ExtractionRequestInfoMessage : ExtractMessage
[JsonProperty(Required = Required.Always)]
public string UserName { get; set; } = null!;

[JsonProperty(Required = Required.Default)]
public string? ExtractionModality { get; set; }

[JsonConstructor]
public ExtractionRequestInfoMessage() { }

public override string ToString()
{
return base.ToString() + $",KeyTag={KeyTag},KeyValueCount={KeyValueCount},UserName={UserName},ExtractionModality={ExtractionModality}";
return base.ToString() + $",KeyTag={KeyTag},KeyValueCount={KeyValueCount},UserName={UserName}";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,6 @@ public class ExtractionRequestMessage : ExtractMessage
[JsonProperty(Required = Required.Always)]
public string KeyTag { get; set; } = null!;

/// <summary>
/// Optional list of modalities to extract when <see cref="KeyTag"/> could include multiple modalities
/// (e.g. extracting based on patient or study (study can include e.g. CT + SR).
/// </summary>
[JsonProperty(Required = Required.AllowNull)]
public string? Modalities { get; set; }

/// <summary>
/// The unique set of identifiers of Type <see cref="KeyTag"/> which should be extracted
/// </summary>
Expand All @@ -41,14 +34,12 @@ public ExtractionRequestMessage(ExtractionRequestMessage other)
: base(other)
{
KeyTag = other.KeyTag;
Modalities = other.Modalities;
ExtractionIdentifiers = other.ExtractionIdentifiers;
}

public override string ToString()
=> base.ToString() + ", " +
$"KeyTag={KeyTag}, " +
$"Modality={Modalities ?? "Unspecified"}, " +
$"nIdentifiers={ExtractionIdentifiers.Count}";
}
}
6 changes: 6 additions & 0 deletions src/SmiServices/Common/Messages/Extraction/IExtractMessage.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Newtonsoft.Json;
using System;

namespace SmiServices.Common.Messages.Extraction
Expand All @@ -22,6 +23,11 @@ public interface IExtractMessage : IMessage
/// </summary>
string ExtractionDirectory { get; }

/// <summary>
/// The modality to extract
/// </summary>
public string Modality { get; }

/// <summary>
/// DateTime the job was submitted at
/// </summary>
Expand Down
6 changes: 2 additions & 4 deletions src/SmiServices/Common/Options/GlobalOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -363,15 +363,13 @@ public string AuditorType
/// The Type of a class implementing IProjectPathResolver which is responsible for deciding the folder hierarchy to output into
/// </summary>
public string? ProjectPathResolverType { get; set; }

public const string DefaultModalityRoutingRegex = "^([A-Z]+)_.*$";


/// <summary>
/// Controls how modalities are matched to Catalogues. Must contain a single capture group which
/// returns a modality code (e.g. CT) when applies to a Catalogue name. E.g. ^([A-Z]+)_.*$ would result
/// in Modalities being routed based on the start of the table name e.g. CT => CT_MyTable and MR=> MR_MyTable
/// </summary>
public string? ModalityRoutingRegex { get; set; } = DefaultModalityRoutingRegex;
public string? ModalityRoutingRegex { get; set; }

/// <summary>
/// The Type of a class implementing IRejector which is responsible for deciding individual records/images are not extractable (after fetching from database)
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ private static int OnParse(GlobalOptions globals, CliOptions opts)
var bootstrapper = new MicroserviceHostBootstrapper(
() => new CohortExtractorHost(
globals,
auditor: null,
fulfiller: null
)
);
Expand Down
Loading
Loading