Skip to content

Commit e2ea4d5

Browse files
srsaggamDmitry-A
authored andcommitted
Enabling new command line args (dotnet#183)
* fix package name * initial commit * added more commandline args * fixed tests * added headers * fix tests * fix test
1 parent 8d575ba commit e2ea4d5

14 files changed

+280
-137
lines changed

src/mlnet.Test/ApprovalTests/ConsoleCodeGeneratorTests.GeneratedTrainCodeTest.approved.txt

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-

1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
25
using System;
36
using System.IO;
47
using System.Linq;
@@ -105,7 +108,7 @@ namespace MyNamespace
105108
var resultprediction = predEngine.Predict(sample);
106109

107110
Console.WriteLine($"=============== Single Prediction ===============");
108-
Console.WriteLine($"Input: {sample} | Prediction: {resultprediction.Prediction}");
111+
Console.WriteLine($"Actual value: {sample.Label} | Predicted value: {resultprediction.Prediction}");
109112
Console.WriteLine($"==================================================");
110113
}
111114

src/mlnet.Test/ApprovalTests/ConsoleCodeGeneratorTests.cs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
using System.Collections.Generic;
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Collections.Generic;
26
using System.IO;
37
using ApprovalTests;
48
using ApprovalTests.Reporters;

src/mlnet.Test/CodeGenTests.cs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
using System.Collections.Generic;
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Collections.Generic;
26
using Microsoft.ML;
37
using Microsoft.ML.Auto;
48
using Microsoft.ML.CLI.CodeGenerator.CSharp;

src/mlnet.Test/CommandLineTests.cs

+86-27
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
using System.CommandLine.Builder;
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.CommandLine.Builder;
26
using System.CommandLine.Invocation;
37
using System.IO;
4-
using Microsoft.ML.Auto;
58
using Microsoft.ML.CLI.Commands;
9+
using Microsoft.ML.CLI.Data;
610
using Microsoft.VisualStudio.TestTools.UnitTesting;
711

812
namespace mlnet.Test
@@ -16,8 +20,8 @@ public void TestCommandLineArgs()
1620
bool parsingSuccessful = false;
1721

1822
// Create handler outside so that commandline and the handler is decoupled and testable.
19-
var handler = CommandHandler.Create<FileInfo, FileInfo, FileInfo, TaskKind, string, uint, uint>(
20-
(trainDataset, validationDataset, testDataset, mlTask, labelColumnName, maxExplorationTime, labelColumnIndex) =>
23+
var handler = CommandHandler.Create<NewCommandOptions>(
24+
(opt) =>
2125
{
2226
parsingSuccessful = true;
2327
});
@@ -28,10 +32,12 @@ public void TestCommandLineArgs()
2832
.UseDefaults()
2933
.Build();
3034

31-
var file = Path.GetTempFileName();
32-
string[] args = new[] { "new", "--ml-task", "BinaryClassification", "--train-dataset", file, "--label-column-name", "Label" };
35+
var trainDataset = Path.GetTempFileName();
36+
var testDataset = Path.GetTempFileName();
37+
string[] args = new[] { "new", "--ml-task", "binary-classification", "--train-dataset", trainDataset, "--test-dataset", testDataset, "--label-column-name", "Label" };
3338
parser.InvokeAsync(args).Wait();
34-
File.Delete(file);
39+
File.Delete(trainDataset);
40+
File.Delete(testDataset);
3541
Assert.IsTrue(parsingSuccessful);
3642
}
3743

@@ -42,8 +48,8 @@ public void TestCommandLineArgsFailTest()
4248
bool parsingSuccessful = false;
4349

4450
// Create handler outside so that commandline and the handler is decoupled and testable.
45-
var handler = CommandHandler.Create<FileInfo, FileInfo, FileInfo, TaskKind, string, uint, uint>(
46-
(trainDataset, validationDataset, testDataset, mlTask, labelColumnName, maxExplorationTime, labelColumnIndex) =>
51+
var handler = CommandHandler.Create<NewCommandOptions>(
52+
(opt) =>
4753
{
4854
parsingSuccessful = true;
4955
});
@@ -55,46 +61,56 @@ public void TestCommandLineArgsFailTest()
5561
.Build();
5662

5763
// Incorrect mltask test
58-
var file = Path.GetTempFileName();
59-
string[] args = new[] { "new", "--ml-task", "BinaryClass", "--train-dataset", file, "--label-column-name", "Label" };
64+
var trainDataset = Path.GetTempFileName();
65+
var testDataset = Path.GetTempFileName();
66+
67+
//wrong value to ml-task
68+
string[] args = new[] { "new", "--ml-task", "bad-value", "--train-dataset", trainDataset, "--label-column-name", "Label" };
6069
parser.InvokeAsync(args).Wait();
6170
Assert.IsFalse(parsingSuccessful);
6271

6372
// Incorrect invocation
64-
args = new[] { "new", "BinaryClassification", "--train-dataset", file, "--label-column-name", "Label" };
73+
args = new[] { "new", "binary-classification", "--train-dataset", trainDataset, "--label-column-name", "Label" };
6574
parser.InvokeAsync(args).Wait();
6675
Assert.IsFalse(parsingSuccessful);
6776

6877
// Non-existent file test
69-
args = new[] { "new", "--ml-task", "BinaryClassification", "--train-dataset", "blah.csv", "--label-column-name", "Label" };
78+
args = new[] { "new", "--ml-task", "binary-classification", "--train-dataset", "nonexistentfile.csv", "--label-column-name", "Label" };
7079
parser.InvokeAsync(args).Wait();
7180
Assert.IsFalse(parsingSuccessful);
7281

7382
// No label column or index test
74-
args = new[] { "new", "--ml-task", "BinaryClassification", "--train-dataset", "blah.csv" };
83+
args = new[] { "new", "--ml-task", "binary-classification", "--train-dataset", trainDataset, "--test-dataset", testDataset };
7584
parser.InvokeAsync(args).Wait();
85+
File.Delete(trainDataset);
86+
File.Delete(testDataset);
7687
Assert.IsFalse(parsingSuccessful);
77-
7888
}
7989

8090
[TestMethod]
8191
public void TestCommandLineArgsValuesTest()
8292
{
8393
bool parsingSuccessful = false;
84-
var file1 = Path.GetTempFileName();
85-
var file2 = Path.GetTempFileName();
94+
var trainDataset = Path.GetTempFileName();
95+
var testDataset = Path.GetTempFileName();
96+
var validDataset = Path.GetTempFileName();
8697
var labelName = "Label";
98+
var name = "testname";
99+
var outputPath = ".";
87100

88101
// Create handler outside so that commandline and the handler is decoupled and testable.
89-
var handler = CommandHandler.Create<FileInfo, FileInfo, FileInfo, TaskKind, string, uint, uint>(
90-
(trainDataset, validationDataset, testDataset, mlTask, labelColumnName, maxExplorationTime, labelColumnIndex) =>
102+
var handler = CommandHandler.Create<NewCommandOptions>(
103+
(opt) =>
91104
{
92105
parsingSuccessful = true;
93-
Assert.AreEqual(mlTask, TaskKind.BinaryClassification);
94-
Assert.AreEqual(trainDataset, file1);
95-
Assert.AreEqual(testDataset, file2);
96-
Assert.AreEqual(labelColumnName, labelName);
97-
Assert.AreEqual(maxExplorationTime, 5);
106+
Assert.AreEqual(opt.MlTask, "binary-classification");
107+
Assert.AreEqual(opt.TrainDataset, trainDataset);
108+
Assert.AreEqual(opt.TestDataset, testDataset);
109+
Assert.AreEqual(opt.ValidationDataset, validDataset);
110+
Assert.AreEqual(opt.LabelColumnName, labelName);
111+
Assert.AreEqual(opt.MaxExplorationTime, 5);
112+
Assert.AreEqual(opt.Name, name);
113+
Assert.AreEqual(opt.OutputPath, outputPath);
98114
});
99115

100116
var parser = new CommandLineBuilder()
@@ -104,12 +120,55 @@ public void TestCommandLineArgsValuesTest()
104120
.Build();
105121

106122
// Incorrect mltask test
107-
string[] args = new[] { "new", "--ml-task", "BinaryClassification", "--train-dataset", file1, "--label-column-name", labelName, "--test-dataset", file2, "--max-exploration-time", "5" };
123+
string[] args = new[] { "new", "--ml-task", "binary-classification", "--train-dataset", trainDataset, "--label-column-name", labelName, "--validation-dataset", validDataset, "--test-dataset", testDataset, "--max-exploration-time", "5", "--name", name, "--output-path", outputPath };
108124
parser.InvokeAsync(args).Wait();
109-
File.Delete(file1);
110-
File.Delete(file2);
125+
File.Delete(trainDataset);
126+
File.Delete(testDataset);
127+
File.Delete(validDataset);
111128
Assert.IsTrue(parsingSuccessful);
112129

113130
}
131+
132+
[TestMethod]
133+
public void TestCommandLineArgsMutuallyExclusiveArgsTest()
134+
{
135+
bool parsingSuccessful = false;
136+
var dataset = Path.GetTempFileName();
137+
var trainDataset = Path.GetTempFileName();
138+
var testDataset = Path.GetTempFileName();
139+
var labelName = "Label";
140+
141+
// Create handler outside so that commandline and the handler is decoupled and testable.
142+
var handler = CommandHandler.Create<NewCommandOptions>(
143+
(opt) =>
144+
{
145+
parsingSuccessful = true;
146+
});
147+
148+
var parser = new CommandLineBuilder()
149+
// Parser
150+
.AddCommand(CommandDefinitions.New(handler))
151+
.UseDefaults()
152+
.Build();
153+
154+
// Incorrect arguments : specifying dataset and train-dataset
155+
string[] args = new[] { "new", "--ml-task", "BinaryClassification", "--dataset", dataset, "--train-dataset", trainDataset, "--label-column-name", labelName, "--test-dataset", testDataset, "--max-exploration-time", "5" };
156+
parser.InvokeAsync(args).Wait();
157+
Assert.IsFalse(parsingSuccessful);
158+
159+
// Incorrect arguments : specifying train-dataset and not specifying test-dataset
160+
args = new[] { "new", "--ml-task", "BinaryClassification", "--train-dataset", trainDataset, "--label-column-name", labelName, "--max-exploration-time", "5" };
161+
parser.InvokeAsync(args).Wait();
162+
Assert.IsFalse(parsingSuccessful);
163+
164+
// Incorrect arguments : specifying label column name and index
165+
args = new[] { "new", "--ml-task", "BinaryClassification", "--train-dataset", trainDataset, "--label-column-name", labelName, "--label-column-index", "0", "--test-dataset", testDataset, "--max-exploration-time", "5" };
166+
parser.InvokeAsync(args).Wait();
167+
File.Delete(trainDataset);
168+
File.Delete(testDataset);
169+
File.Delete(dataset);
170+
Assert.IsFalse(parsingSuccessful);
171+
172+
}
114173
}
115174
}

src/mlnet/Commands/CommandDefinitions.cs

+25-12
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ internal static System.CommandLine.Command New(ICommandHandler handler)
1919
{
2020
var newCommand = new System.CommandLine.Command("new", "ML.NET CLI tool for code generation", handler: handler)
2121
{
22-
//Dataset(),
22+
Dataset(),
2323
TrainDataset(),
2424
ValidationDataset(),
2525
TestDataset(),
@@ -29,14 +29,22 @@ internal static System.CommandLine.Command New(ICommandHandler handler)
2929
LabelColumnIndex(),
3030
Verbosity(),
3131
Name(),
32-
OutputBaseDir()
32+
OutputPath()
3333
};
3434

3535
newCommand.Argument.AddValidator((sym) =>
3636
{
37-
if (sym.Children["--train-dataset"] == null)
37+
if (sym.Children["--dataset"] == null && sym.Children["--train-dataset"] == null)
3838
{
39-
return "Option required : --train-dataset";
39+
return "Option required : --dataset";
40+
}
41+
if (sym.Children["--dataset"] != null && sym.Children["--train-dataset"] != null)
42+
{
43+
return "The following options are mutually exclusive please provide only one : --data-set, --train-dataset";
44+
}
45+
if (sym.Children["--train-dataset"] != null && sym.Children["--test-dataset"] == null)
46+
{
47+
return "Option required : --test-dataset";
4048
}
4149
if (sym.Children["--ml-task"] == null)
4250
{
@@ -46,14 +54,19 @@ internal static System.CommandLine.Command New(ICommandHandler handler)
4654
{
4755
return "Option required : --label-column-name or --label-column-index";
4856
}
57+
if (sym.Children["--label-column-name"] != null && sym.Children["--label-column-index"] != null)
58+
{
59+
return "The following options are mutually exclusive please provide only one : --label-column-name, --label-column-index";
60+
}
61+
4962
return null;
5063
});
5164

5265
return newCommand;
5366

54-
/*Option Dataset() =>
67+
Option Dataset() =>
5568
new Option("--dataset", "Dataset file path.",
56-
new Argument<FileInfo>().ExistingOnly()); */
69+
new Argument<FileInfo>().ExistingOnly());
5770

5871
Option TrainDataset() =>
5972
new Option("--train-dataset", "Train dataset file path.",
@@ -69,7 +82,7 @@ Option TestDataset() =>
6982

7083
Option MlTask() =>
7184
new Option("--ml-task", "Type of ML task.",
72-
new Argument<TaskKind>().WithSuggestions(GetMlTaskSuggestions()));
85+
new Argument<string>().FromAmong(GetMlTaskSuggestions()));
7386

7487
Option LabelName() =>
7588
new Option("--label-column-name", "Name of the label column.",
@@ -85,21 +98,21 @@ Option MaxExplorationTime() =>
8598

8699
Option Verbosity() =>
87100
new Option(new List<string>() { "--verbosity" }, "Verbosity of the output to be shown by the tool.",
88-
new Argument<string>(defaultValue: "m").WithSuggestions(GetVerbositySuggestions()));
101+
new Argument<string>(defaultValue: "m").FromAmong(GetVerbositySuggestions()));
89102

90103
Option Name() =>
91104
new Option(new List<string>() { "--name" }, "Name of the output files(project and folder).",
92105
new Argument<string>(defaultValue: "Sample"));
93106

94-
Option OutputBaseDir() =>
95-
new Option(new List<string>() { "--output" }, "Output folder path.",
96-
new Argument<string>(defaultValue: ".\\Sample"));
107+
Option OutputPath() =>
108+
new Option(new List<string>() { "--output-path" }, "Output folder path.",
109+
new Argument<DirectoryInfo>(defaultValue: new DirectoryInfo(".\\Sample")));
97110

98111
}
99112

100113
private static string[] GetMlTaskSuggestions()
101114
{
102-
return Enum.GetValues(typeof(TaskKind)).Cast<TaskKind>().Select(v => v.ToString()).ToArray();
115+
return new[] { "binary-classification", "regression" };
103116
}
104117

105118
private static string[] GetVerbositySuggestions()

0 commit comments

Comments
 (0)