Skip to content

Commit 0fc4a6d

Browse files
cc_model_filename no longer ignored
1 parent 6037019 commit 0fc4a6d

4 files changed

Lines changed: 231 additions & 1 deletion

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/build
2+
/build_test
23
/.vscode
34
*.so
45
*__pycache__/

src/model_config_utils.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1273,7 +1273,8 @@ AutoCompleteBackendFields(
12731273
}
12741274
}
12751275
if (config->backend() == kPythonBackend) {
1276-
if (config->default_model_filename().empty()) {
1276+
if (config->default_model_filename().empty() &&
1277+
config->cc_model_filenames().empty()) {
12771278
config->set_default_model_filename(kPythonFilename);
12781279
}
12791280
return Status::Success;

src/test/CMakeLists.txt

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,56 @@ install(
439439
RUNTIME DESTINATION bin
440440
)
441441

442+
#
443+
# Unit test for AutoCompleteBackendFields in model_config_utils
444+
#
445+
add_executable(
446+
model_config_utils_test
447+
model_config_utils_test.cc
448+
../model_config_utils.cc
449+
../status.cc
450+
../filesystem/api.cc
451+
../model_config_utils.h
452+
../status.h
453+
../filesystem/api.h
454+
)
455+
456+
set_target_properties(
457+
model_config_utils_test
458+
PROPERTIES
459+
SKIP_BUILD_RPATH TRUE
460+
BUILD_WITH_INSTALL_RPATH TRUE
461+
INSTALL_RPATH_USE_LINK_PATH FALSE
462+
INSTALL_RPATH ""
463+
)
464+
465+
target_include_directories(
466+
model_config_utils_test
467+
PRIVATE
468+
${CMAKE_CURRENT_SOURCE_DIR}/..
469+
${CMAKE_CURRENT_SOURCE_DIR}/../../include
470+
${GTEST_INCLUDE_DIRS}
471+
${Boost_INCLUDE_DIRS}
472+
)
473+
474+
target_link_libraries(
475+
model_config_utils_test
476+
PRIVATE
477+
triton-common-error # from repo-common
478+
triton-common-model-config # from repo-common
479+
triton-common-json # from repo-common
480+
triton-common-logging # from repo-common
481+
proto-library # from repo-common
482+
GTest::gtest
483+
GTest::gtest_main
484+
protobuf::libprotobuf
485+
)
486+
487+
install(
488+
TARGETS model_config_utils_test
489+
RUNTIME DESTINATION bin
490+
)
491+
442492

443493
if(${TRITON_ENABLE_METRICS})
444494
#
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
// Copyright 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
//
3+
// Redistribution and use in source and binary forms, with or without
4+
// modification, are permitted provided that the following conditions
5+
// are met:
6+
// * Redistributions of source code must retain the above copyright
7+
// notice, this list of conditions and the following disclaimer.
8+
// * Redistributions in binary form must reproduce the above copyright
9+
// notice, this list of conditions and the following disclaimer in the
10+
// documentation and/or other materials provided with the distribution.
11+
// * Neither the name of NVIDIA CORPORATION nor the names of its
12+
// contributors may be used to endorse or promote products derived
13+
// from this software without specific prior written permission.
14+
//
15+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
16+
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18+
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
19+
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20+
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21+
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22+
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23+
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
27+
#include "model_config_utils.h"
28+
29+
#include <sys/stat.h>
30+
31+
#include <fstream>
32+
#include <string>
33+
34+
#include "constants.h"
35+
#include "filesystem/api.h"
36+
#include "gtest/gtest.h"
37+
38+
namespace tc = triton::core;
39+
40+
namespace {
41+
42+
// Helper to create a temporary model directory with a version subdirectory
43+
// and an optional file inside it.
44+
class TempModelDir {
45+
public:
46+
TempModelDir()
47+
{
48+
auto status =
49+
tc::MakeTemporaryDirectory(tc::FileSystemType::LOCAL, &root_path_);
50+
EXPECT_TRUE(status.IsOk()) << status.AsString();
51+
}
52+
53+
~TempModelDir()
54+
{
55+
// Best-effort cleanup
56+
std::string cmd = "rm -rf " + root_path_;
57+
(void)system(cmd.c_str());
58+
}
59+
60+
// Create version subdir (e.g., "1") and optionally place a file in it.
61+
void AddVersionWithFile(
62+
const std::string& version, const std::string& filename)
63+
{
64+
std::string version_dir = tc::JoinPath({root_path_, version});
65+
mkdir(version_dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
66+
if (!filename.empty()) {
67+
std::ofstream f(tc::JoinPath({version_dir, filename}));
68+
f << "# placeholder";
69+
}
70+
}
71+
72+
const std::string& Path() const { return root_path_; }
73+
74+
private:
75+
std::string root_path_;
76+
};
77+
78+
class AutoCompleteBackendFieldsTest : public ::testing::Test {};
79+
80+
// When backend is "python" and default_model_filename is empty and
81+
// cc_model_filenames is empty, default_model_filename should be set to
82+
// "model.py".
83+
TEST_F(AutoCompleteBackendFieldsTest, PythonBackendSetsDefaultFilename)
84+
{
85+
TempModelDir dir;
86+
dir.AddVersionWithFile("1", "model.py");
87+
88+
inference::ModelConfig config;
89+
config.set_backend("python");
90+
// default_model_filename and cc_model_filenames are both empty
91+
92+
auto status =
93+
tc::AutoCompleteBackendFields("test_model", dir.Path(), &config);
94+
ASSERT_TRUE(status.IsOk()) << status.AsString();
95+
EXPECT_EQ(config.default_model_filename(), "model.py");
96+
}
97+
98+
// When backend is "python" and default_model_filename is empty but
99+
// cc_model_filenames is populated, default_model_filename should NOT be
100+
// auto-filled to "model.py".
101+
TEST_F(
102+
AutoCompleteBackendFieldsTest,
103+
PythonBackendSkipsDefaultFilenameWhenCcModelFilenamesSet)
104+
{
105+
TempModelDir dir;
106+
dir.AddVersionWithFile("1", "custom_model.py");
107+
108+
inference::ModelConfig config;
109+
config.set_backend("python");
110+
(*config.mutable_cc_model_filenames())["gpu"] = "custom_model.py";
111+
// default_model_filename is empty, cc_model_filenames is set
112+
113+
auto status =
114+
tc::AutoCompleteBackendFields("test_model", dir.Path(), &config);
115+
ASSERT_TRUE(status.IsOk()) << status.AsString();
116+
EXPECT_EQ(config.default_model_filename(), "")
117+
<< "default_model_filename should remain empty when cc_model_filenames "
118+
"is set";
119+
}
120+
121+
// When backend is "python" and default_model_filename is already set,
122+
// it should be preserved regardless of cc_model_filenames.
123+
TEST_F(
124+
AutoCompleteBackendFieldsTest,
125+
PythonBackendPreservesExplicitDefaultFilename)
126+
{
127+
TempModelDir dir;
128+
dir.AddVersionWithFile("1", "my_model.py");
129+
130+
inference::ModelConfig config;
131+
config.set_backend("python");
132+
config.set_default_model_filename("my_model.py");
133+
134+
auto status =
135+
tc::AutoCompleteBackendFields("test_model", dir.Path(), &config);
136+
ASSERT_TRUE(status.IsOk()) << status.AsString();
137+
EXPECT_EQ(config.default_model_filename(), "my_model.py");
138+
}
139+
140+
// When backend is "python" and both default_model_filename and
141+
// cc_model_filenames are set, both should be preserved as-is.
142+
TEST_F(
143+
AutoCompleteBackendFieldsTest,
144+
PythonBackendPreservesBothDefaultAndCcModelFilenames)
145+
{
146+
TempModelDir dir;
147+
dir.AddVersionWithFile("1", "my_model.py");
148+
149+
inference::ModelConfig config;
150+
config.set_backend("python");
151+
config.set_default_model_filename("my_model.py");
152+
(*config.mutable_cc_model_filenames())["gpu"] = "gpu_model.py";
153+
154+
auto status =
155+
tc::AutoCompleteBackendFields("test_model", dir.Path(), &config);
156+
ASSERT_TRUE(status.IsOk()) << status.AsString();
157+
EXPECT_EQ(config.default_model_filename(), "my_model.py");
158+
EXPECT_EQ(config.cc_model_filenames().at("gpu"), "gpu_model.py");
159+
}
160+
161+
// When backend is empty but version dir contains model.py, backend should be
162+
// auto-detected as "python" and default_model_filename set to "model.py".
163+
TEST_F(AutoCompleteBackendFieldsTest, AutoDetectPythonBackendFromModelFile)
164+
{
165+
TempModelDir dir;
166+
dir.AddVersionWithFile("1", "model.py");
167+
168+
inference::ModelConfig config;
169+
// backend, platform, default_model_filename all empty
170+
171+
auto status =
172+
tc::AutoCompleteBackendFields("test_model", dir.Path(), &config);
173+
ASSERT_TRUE(status.IsOk()) << status.AsString();
174+
EXPECT_EQ(config.backend(), "python");
175+
EXPECT_EQ(config.default_model_filename(), "model.py");
176+
}
177+
178+
} // namespace

0 commit comments

Comments
 (0)