From 210fe16422d2d466e75a2972d66b0fce51fda536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Zientkiewicz?= Date: Wed, 22 Apr 2026 20:55:40 +0200 Subject: [PATCH 1/2] Add schema aliases. Use aliases in rename-only deprecations. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaƂ Zientkiewicz --- dali/operators/audio/resample.cc | 14 ++-- dali/operators/decoder/inflate/inflate.cc | 5 +- .../generic/resize/tensor_resize_cpu.cc | 14 ++-- dali/operators/reader/file_reader_op.cc | 10 +-- dali/operators/reader/mxnet_reader_op.cc | 12 ++-- dali/operators/reader/numpy_reader_op.cc | 12 ++-- dali/operators/reader/sequence_reader_op.cc | 13 ++-- dali/operators/reader/tfrecord_reader_op.cc | 8 +-- .../video/decoder/video_decoder_cpu.cc | 10 +-- dali/pipeline/operator/op_schema.cc | 66 +++++++++++++++++-- dali/pipeline/operator/op_schema.h | 14 +++- dali/pipeline/operator/operator_factory.h | 29 +++++--- 12 files changed, 122 insertions(+), 85 deletions(-) diff --git a/dali/operators/audio/resample.cc b/dali/operators/audio/resample.cc index 86ed2b7d50b..70db9da10bc 100644 --- a/dali/operators/audio/resample.cc +++ b/dali/operators/audio/resample.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2022-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// Copyright (c) 2022-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -97,18 +97,14 @@ type. Example:: nullptr, false); // Deprecated alias -DALI_SCHEMA(experimental__AudioResample) - .AddParent("AudioResample") - .DocStr("Legacy alias for :meth:`audio_resample`.") - .NumInput(1) - .NumOutput(1) - .MakeDocHidden() +DALI_SCHEMA_ALIAS(experimental__AudioResample, AudioResample) .Deprecate( "1.18", "AudioResample", "This operator was moved out from the experimental phase, " - "and is now a regular DALI operator. This is just an deprecated " - "alias kept for backward compatibility."); + "and is now a regular DALI operator. This is just a deprecated " + "alias kept for backward compatibility.") + .MakeDocHidden(); namespace audio { diff --git a/dali/operators/decoder/inflate/inflate.cc b/dali/operators/decoder/inflate/inflate.cc index 355f9239e10..c334ffe593c 100644 --- a/dali/operators/decoder/inflate/inflate.cc +++ b/dali/operators/decoder/inflate/inflate.cc @@ -89,10 +89,7 @@ The value is ignored if the `layout` is not specified or the input is not a sequ .OutputLayout(0, std::nullopt) .OutputNDim(0, std::nullopt); -DALI_SCHEMA(experimental__Inflate) - .AddParent("decoders__Inflate") - .NumInput(1) - .NumOutput(1) +DALI_SCHEMA_ALIAS(experimental__Inflate, decoders__Inflate) .Deprecate("2.0", "decoders__Inflate") .MakeDocHidden(); diff --git a/dali/operators/generic/resize/tensor_resize_cpu.cc b/dali/operators/generic/resize/tensor_resize_cpu.cc index 59624b2a4bf..a71569e7a03 100644 --- a/dali/operators/generic/resize/tensor_resize_cpu.cc +++ b/dali/operators/generic/resize/tensor_resize_cpu.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2022-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// Copyright (c) 2022-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -46,20 +46,14 @@ DALI_SCHEMA(TensorResize) .AddParent("TensorResizeAttr"); // Deprecated alias -DALI_SCHEMA(experimental__TensorResize) - .AddParent("TensorResize") - .DocStr("Legacy alias for :meth:`tensor_resize`.") - .NumInput(1) - .NumOutput(1) - .MakeDocHidden() - .SupportVolumetric() - .AllowSequences() +DALI_SCHEMA_ALIAS(experimental__TensorResize, TensorResize) .Deprecate( "2.0", "TensorResize", "This operator was moved out from the experimental phase, " "and is now a regular DALI operator. This is just a deprecated " - "alias kept for backward compatibility."); + "alias kept for backward compatibility.") + .MakeDocHidden(); // Kept for backwards compatibility DALI_REGISTER_OPERATOR(experimental__TensorResize, tensor_resize::TensorResizeCPU, CPU); diff --git a/dali/operators/reader/file_reader_op.cc b/dali/operators/reader/file_reader_op.cc index 64a3560f3c0..0d6b77223f2 100644 --- a/dali/operators/reader/file_reader_op.cc +++ b/dali/operators/reader/file_reader_op.cc @@ -146,17 +146,13 @@ case-sensitively, otherwise case-insensitively.)", false) // Deprecated alias DALI_REGISTER_OPERATOR(FileReader, FileReader, CPU); -DALI_SCHEMA(FileReader) - .DocStr("Legacy alias for :meth:`readers.file`.") - .NumInput(0) - .NumOutput(2) // (Images, Labels) - .AddParent("readers__File") - .MakeDocHidden() +DALI_SCHEMA_ALIAS(FileReader, readers__File) .Deprecate( "1.0", "readers__File", R"code(In DALI 1.0 all readers were moved into a dedicated :mod:`~nvidia.dali.fn.readers` submodule and renamed to follow a common pattern. This is a placeholder operator with identical -functionality to allow for backward compatibility.)code"); +functionality to allow for backward compatibility.)code") + .MakeDocHidden(); } // namespace dali diff --git a/dali/operators/reader/mxnet_reader_op.cc b/dali/operators/reader/mxnet_reader_op.cc index fb6e34523d4..d0bcba04405 100644 --- a/dali/operators/reader/mxnet_reader_op.cc +++ b/dali/operators/reader/mxnet_reader_op.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// Copyright (c) 2017-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -64,17 +64,13 @@ properties. // Deprecated alias DALI_REGISTER_OPERATOR(MXNetReader, MXNetReader, CPU); -DALI_SCHEMA(MXNetReader) - .DocStr("Legacy alias for :meth:`readers.mxnet`.") - .NumInput(0) - .NumOutput(2) - .AddParent("readers__MXNet") - .MakeDocHidden() +DALI_SCHEMA_ALIAS(MXNetReader, readers__MXNet) .Deprecate( "1.0", "readers__MXNet", R"code(In DALI 1.0 all readers were moved into a dedicated :mod:`~nvidia.dali.fn.readers` submodule and renamed to follow a common pattern. This is a placeholder operator with identical -functionality to allow for backward compatibility.)code"); +functionality to allow for backward compatibility.)code") + .MakeDocHidden(); } // namespace dali diff --git a/dali/operators/reader/numpy_reader_op.cc b/dali/operators/reader/numpy_reader_op.cc index db22b98de9d..2e23572afcc 100644 --- a/dali/operators/reader/numpy_reader_op.cc +++ b/dali/operators/reader/numpy_reader_op.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// Copyright (c) 2020-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -238,18 +238,14 @@ Mutually exclusive with ``dont_use_mmap=False``.)code", // Deprecated alias DALI_REGISTER_OPERATOR(NumpyReader, NumpyReaderCPU, CPU); -DALI_SCHEMA(NumpyReader) - .DocStr("Legacy alias for :meth:`readers.numpy`.") - .NumInput(0) - .NumOutput(1) // (Arrays) - .AddParent("readers__Numpy") - .MakeDocHidden() +DALI_SCHEMA_ALIAS(NumpyReader, readers__Numpy) .Deprecate( "1.0", "readers__Numpy", R"code(In DALI 1.0 all readers were moved into a dedicated :mod:`~nvidia.dali.fn.readers` submodule and renamed to follow a common pattern. This is a placeholder operator with identical -functionality to allow for backward compatibility.)code"); +functionality to allow for backward compatibility.)code") + .MakeDocHidden(); NumpyReaderCPU::~NumpyReaderCPU() { // Stop the prefetch thread as it uses the thread pool from this class. So before we can diff --git a/dali/operators/reader/sequence_reader_op.cc b/dali/operators/reader/sequence_reader_op.cc index cfcb05d2953..1910812ce8a 100644 --- a/dali/operators/reader/sequence_reader_op.cc +++ b/dali/operators/reader/sequence_reader_op.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// Copyright (c) 2018-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -90,18 +90,13 @@ For reading video sequences, one of :meth:`nvidia.dali.fn.readers.video`, // Deprecated alias DALI_REGISTER_OPERATOR(SequenceReader, SequenceReader, CPU); -DALI_SCHEMA(SequenceReader) - .DocStr("Legacy alias for :meth:`readers.sequence`.") - .NumInput(0) - .NumOutput(1) // ([Frames]) - .AllowSequences() - .AddParent("readers__Sequence") - .MakeDocHidden() +DALI_SCHEMA_ALIAS(SequenceReader, readers__Sequence) .Deprecate( "1.0", "readers__Sequence", R"code(In DALI 1.0 all readers were moved into a dedicated :mod:`~nvidia.dali.fn.readers` submodule and renamed to follow a common pattern. This is a placeholder operator with identical -functionality to allow for backward compatibility.)code"); +functionality to allow for backward compatibility.)code") + .MakeDocHidden(); } // namespace dali diff --git a/dali/operators/reader/tfrecord_reader_op.cc b/dali/operators/reader/tfrecord_reader_op.cc index fcb3e8c8d93..9ba99ffa8a7 100644 --- a/dali/operators/reader/tfrecord_reader_op.cc +++ b/dali/operators/reader/tfrecord_reader_op.cc @@ -134,16 +134,14 @@ functionality to allow for backward compatibility.)code"); // Deprecated alias -DALI_SCHEMA(TFRecordReader) - .DocStr("Legacy alias for :meth:`readers.tfrecord`.") - .AddParent("readers__TFRecord") - .MakeDocHidden() +DALI_SCHEMA_ALIAS(TFRecordReader, readers__TFRecord) .Deprecate( "1.0", "readers__TFRecord", R"code(In DALI 1.0 all readers were moved into a dedicated :mod:`~nvidia.dali.fn.readers` submodule and renamed to follow a common pattern. This is a placeholder operator with identical -functionality to allow for backward compatibility.)code"); +functionality to allow for backward compatibility.)code") + .MakeDocHidden(); void TFRecordReader::Prefetch() { // We actually prepare the next batch diff --git a/dali/operators/video/decoder/video_decoder_cpu.cc b/dali/operators/video/decoder/video_decoder_cpu.cc index d74111bf2b1..9c2942f1010 100644 --- a/dali/operators/video/decoder/video_decoder_cpu.cc +++ b/dali/operators/video/decoder/video_decoder_cpu.cc @@ -198,18 +198,14 @@ apart or starting playback from a frame deep into the video.)code", .OutputDType(0, DALI_UINT8) .OutputLayout(0, "FHWC"); -DALI_SCHEMA(experimental__decoders__Video) - .AddParent("decoders__Video") - .DocStr("Legacy alias for :meth:`decoders.video`.") - .NumInput(1) - .NumOutput(1) - .MakeDocHidden() +DALI_SCHEMA_ALIAS(experimental__decoders__Video, decoders__Video) .Deprecate( "2.0", "decoders__Video", "This operator was moved out from the experimental phase, " "and is now a regular DALI operator. This is just a deprecated " - "alias kept for backward compatibility."); + "alias kept for backward compatibility.") + .MakeDocHidden(); class VideoDecoderCpu : public VideoDecoderBase { public: diff --git a/dali/pipeline/operator/op_schema.cc b/dali/pipeline/operator/op_schema.cc index 714de1d35d7..0480019b27e 100644 --- a/dali/pipeline/operator/op_schema.cc +++ b/dali/pipeline/operator/op_schema.cc @@ -27,11 +27,20 @@ namespace dali { -std::map> &SchemaRegistry::registry() { +namespace { + +std::map> ®istry() { static std::map> schema_map; return schema_map; } +std::map> &aliases() { + static std::map> alias_map; + return alias_map; +} + +} // namespace + OpSchema &SchemaRegistry::RegisterSchema(std::string_view name) { auto &schema_map = registry(); @@ -41,20 +50,52 @@ OpSchema &SchemaRegistry::RegisterSchema(std::string_view name) { } const OpSchema &SchemaRegistry::GetSchema(std::string_view name) { - auto &schema_map = registry(); - auto it = schema_map.find(name); - if (it == schema_map.end()) + if (auto *schema = TryGetSchema(name)) + return *schema; + else throw invalid_key("Schema for operator '" + std::string(name) + "' not registered"); - - return it->second; } const OpSchema *SchemaRegistry::TryGetSchema(std::string_view name) { auto &schema_map = registry(); auto it = schema_map.find(name); - return it != schema_map.end() ? &it->second : nullptr; + if (it == schema_map.end() || !it->second.AliasFor().empty()) { + auto &alias_map = aliases(); + auto alias_it = alias_map.find(name); + if (alias_it != alias_map.end()) { + name = alias_it->second; + it = schema_map.find(name); + } + } + + if (it == schema_map.end()) + return nullptr; + + return &it->second; +} + +void SchemaRegistry::AddAlias(std::string_view alias_name, std::string_view actual_name) { + if (alias_name == actual_name) + throw std::invalid_argument("Schema name self-aliasing is forbidden"); + + auto &alias_map = aliases(); + auto previous_target_it = alias_map.find(alias_name); + if (previous_target_it != alias_map.end()) + throw std::invalid_argument(make_string("\"", alias_name, + "\" is already used as a schema alias name for \"", previous_target_it->second, "\"")); + + for (;;) { + auto redir = alias_map.find(actual_name); + if (redir == alias_map.end()) + break; + if (redir->second == alias_name) + throw std::invalid_argument("Cycle detected while adding schema alias."); + actual_name = redir->second; + } + alias_map[std::string(alias_name)] = actual_name; } + const OpSchema &OpSchema::Default() { static OpSchema default_schema(DefaultSchemaTag{}); return default_schema; @@ -391,6 +432,14 @@ OpSchema &OpSchema::Deprecate(std::string version, std::string in_favor_of, return *this; } +OpSchema &OpSchema::AliasFor(std::string_view actual_name) { + DALI_ENFORCE(alias_for_.empty(), make_string( + "The schema \"", name_, "\" is already an alias for \"", alias_for_, "\"")); + + alias_for_ = actual_name; + SchemaRegistry::AddAlias(name_, actual_name); + return *this; +} OpSchema &OpSchema::Unserializable() { serializable_ = false; @@ -847,6 +896,9 @@ const std::string &OpSchema::DeprecatedInFavorOf() const { return deprecated_in_favor_of_; } +const std::string &OpSchema::AliasFor() const { + return alias_for_; +} const std::string &OpSchema::DeprecationMessage() const { return deprecation_message_; diff --git a/dali/pipeline/operator/op_schema.h b/dali/pipeline/operator/op_schema.h index 1f71950dffe..50e75800e7c 100644 --- a/dali/pipeline/operator/op_schema.h +++ b/dali/pipeline/operator/op_schema.h @@ -439,6 +439,9 @@ class DLL_PUBLIC OpSchema { std::string in_favor_of = "", std::string explanation = ""); + /** Marks that this schema is actually just an alias */ + OpSchema &AliasFor(std::string_view actual_name); + /** Notes that this operator cannot be serialized */ OpSchema &Unserializable(); @@ -774,6 +777,9 @@ used with DALIDataType, to avoid confusion with `AddOptionalArg(name, doc, /** What operator replaced the current one. */ const std::string &DeprecatedInFavorOf() const; + /** Whether this schema is just an alias for another one */ + const std::string &AliasFor() const; + /** Additional deprecation message */ const std::string &DeprecationMessage() const; @@ -1056,6 +1062,7 @@ used with DALIDataType, to avoid confusion with `AddOptionalArg(name, doc, std::string deprecated_in_favor_of_; std::string deprecation_message_; std::string deprecation_version_; + std::string alias_for_; }; @@ -1065,10 +1072,9 @@ class SchemaRegistry { DLL_PUBLIC static const OpSchema &GetSchema(std::string_view name); DLL_PUBLIC static const OpSchema *TryGetSchema(std::string_view name); - private: - inline SchemaRegistry() {} + DLL_PUBLIC static void AddAlias(std::string_view alias_name, std::string_view actual_name); - DLL_PUBLIC static std::map> ®istry(); + SchemaRegistry() = delete; }; template @@ -1109,6 +1115,8 @@ inline T OpSchema::GetDefaultValueForArgument(std::string_view name) const { #define DALI_SCHEMA(OpName) DALI_DEFINE_SCHEMA(OpName) #endif +#define DALI_SCHEMA_ALIAS(AliasName, OpName) DALI_SCHEMA(AliasName).AliasFor(#OpName) + } // namespace dali #endif // DALI_PIPELINE_OPERATOR_OP_SCHEMA_H_ diff --git a/dali/pipeline/operator/operator_factory.h b/dali/pipeline/operator/operator_factory.h index d84a7a18e10..376321120df 100644 --- a/dali/pipeline/operator/operator_factory.h +++ b/dali/pipeline/operator/operator_factory.h @@ -67,14 +67,27 @@ class OperatorRegistry { std::unique_ptr Create( std::string_view name, const OpSpec &spec, - std::optional device_name = {}) { + std::optional devName = {}) { std::lock_guard lock(mutex_); - auto creator_it = registry_.find(name); - DALI_ENFORCE(creator_it != registry_.end(), make_string( + auto it = registry_.find(name); + std::string_view lookup_name = name; + while (it == registry_.end()) { + // Maybe we got an alias? Check the schema's actual name. + if (auto *schema = SchemaRegistry::TryGetSchema(lookup_name)) { + std::string_view new_name = schema->name(); + if (new_name == lookup_name) + break; // no alias found + lookup_name = new_name; + it = registry_.find(lookup_name); + } else { + break; + } + } + DALI_ENFORCE(it != registry_.end(), make_string( "Operator \"", name, "\" not registered", - (device_name? make_string(" for \"", *device_name, "\"") : ""))); - - return creator_it->second(spec); + (devName ? make_string(" for ", *devName) : ""), + ".")); + return it->second(spec); } vector RegisteredNames(bool internal_ops) { @@ -119,12 +132,12 @@ class Registerer { #define DALI_DECLARE_OPTYPE_REGISTRY(RegistryName, OpType) \ class DLL_PUBLIC RegistryName##Registry { \ public: \ - DLL_PUBLIC static ::dali::OperatorRegistry& Registry(); \ + DLL_PUBLIC static ::dali::OperatorRegistry& Registry(); \ }; #define DALI_DEFINE_OPTYPE_REGISTRY(RegistryName, OpType) \ dali::OperatorRegistry& RegistryName##Registry::Registry() { \ - static ::dali::OperatorRegistry registry; \ + static ::dali::OperatorRegistry registry; \ return registry; \ } From d799c6913c510111789c3dfb1cd2372b74147538 Mon Sep 17 00:00:00 2001 From: Michal Zientkiewicz Date: Tue, 30 Jun 2026 16:26:11 +0200 Subject: [PATCH 2/2] Use optional string_view in registerer constructor. Signed-off-by: Michal Zientkiewicz --- dali/pipeline/operator/operator_factory.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dali/pipeline/operator/operator_factory.h b/dali/pipeline/operator/operator_factory.h index 376321120df..d4ba15a0b69 100644 --- a/dali/pipeline/operator/operator_factory.h +++ b/dali/pipeline/operator/operator_factory.h @@ -67,7 +67,7 @@ class OperatorRegistry { std::unique_ptr Create( std::string_view name, const OpSpec &spec, - std::optional devName = {}) { + std::optional device_name = {}) { std::lock_guard lock(mutex_); auto it = registry_.find(name); std::string_view lookup_name = name; @@ -85,7 +85,7 @@ class OperatorRegistry { } DALI_ENFORCE(it != registry_.end(), make_string( "Operator \"", name, "\" not registered", - (devName ? make_string(" for ", *devName) : ""), + (device_name ? make_string(" for ", *device_name) : ""), ".")); return it->second(spec); } @@ -116,8 +116,8 @@ class Registerer { Registerer(std::string name, OperatorRegistry *registry, typename OperatorRegistry::Creator creator, - std::string_view devName = "") { - registry->Register(std::move(name), std::move(creator), devName); + std::optional device_name = {}) { + registry->Register(std::move(name), std::move(creator), device_name); } // Standard creator function used by all operators