diff --git a/include/aidge/operator/AvgPooling.hpp b/include/aidge/operator/AvgPooling.hpp
index 06ee4327e2f2d4df32c2decd73841bdf5f79a739..920829473d856b2a4c14fc0859abcd4c3b70277a 100644
--- a/include/aidge/operator/AvgPooling.hpp
+++ b/include/aidge/operator/AvgPooling.hpp
@@ -119,8 +119,8 @@ extern template class Aidge::AvgPooling_Op<4>;
 namespace {
 template <>
 const char *const EnumStrings<Aidge::AvgPoolingAttr>::data[] = {
-    "StrideDims",
-    "KernelDims"
+    "stride_dims",
+    "kernel_dims"
 };
 }
 
diff --git a/include/aidge/operator/BatchNorm.hpp b/include/aidge/operator/BatchNorm.hpp
index b5b64eb428d709e804dd9f6711530b348e0be747..08d1f6a88d394e34dd6e351f500429113a52c9fa 100644
--- a/include/aidge/operator/BatchNorm.hpp
+++ b/include/aidge/operator/BatchNorm.hpp
@@ -111,7 +111,7 @@ extern template std::shared_ptr<Aidge::Node> Aidge::BatchNorm<4>(const DimSize_t
 
 namespace {
 template <>
-const char *const EnumStrings<Aidge::BatchNormAttr>::data[] = { "Epsilon", "Momentum" };
+const char *const EnumStrings<Aidge::BatchNormAttr>::data[] = { "epsilon", "momentum" };
 }
 
 #endif //AIDGE_CORE_OPERATOR_BATCHNORM_H_
diff --git a/include/aidge/operator/Cast.hpp b/include/aidge/operator/Cast.hpp
index 6911053932afff6675be4eb2c713d8d3cd34b462..291669b7c57c14a77ffa6b40fa2aefab8d281fc7 100644
--- a/include/aidge/operator/Cast.hpp
+++ b/include/aidge/operator/Cast.hpp
@@ -93,7 +93,7 @@ inline std::shared_ptr<Node> Cast(const DataType targetType, const std::string&
 
 namespace {
 template <>
-const char* const EnumStrings<Aidge::CastAttr>::data[] = { "TargetType" };
+const char* const EnumStrings<Aidge::CastAttr>::data[] = { "target_type" };
 }
 
 #endif /* AIDGE_CORE_OPERATOR_CAST_H_ */
diff --git a/include/aidge/operator/Concat.hpp b/include/aidge/operator/Concat.hpp
index 8341a93fe66d260ae3687170629b8759d0305a9c..ab14bf527dd9949f3bb2b6157619e58c7c7580ee 100644
--- a/include/aidge/operator/Concat.hpp
+++ b/include/aidge/operator/Concat.hpp
@@ -108,7 +108,7 @@ inline std::shared_ptr<Node> Concat(const IOIndex_t nbIn, const std::int32_t axi
 namespace {
     template <>
     const char* const EnumStrings<Aidge::ConcatAttr>::data[] = {
-        "Axis"
+        "axis"
     };
 }
 
diff --git a/include/aidge/operator/Conv.hpp b/include/aidge/operator/Conv.hpp
index 87ff5854b310ca472994bd6b68fd6ae58d31e806..e89c94f968ab89f43e6ef2d95a40a6f557cc41c7 100644
--- a/include/aidge/operator/Conv.hpp
+++ b/include/aidge/operator/Conv.hpp
@@ -178,9 +178,9 @@ extern template class Aidge::Conv_Op<2>;
 namespace {
 template <>
 const char *const EnumStrings<Aidge::ConvAttr>::data[] = {
-    "StrideDims",
-    "DilationDims",
-    "KernelDims"
+    "stride_dims",
+    "dilation_dims",
+    "kernel_dims"
 };
 }
 
diff --git a/include/aidge/operator/ConvDepthWise.hpp b/include/aidge/operator/ConvDepthWise.hpp
index c8a83ff7de62a61e8125eac29d61c3938115cd09..1acf240bfcdd256953cd96b92e3622a265aafa0b 100644
--- a/include/aidge/operator/ConvDepthWise.hpp
+++ b/include/aidge/operator/ConvDepthWise.hpp
@@ -140,8 +140,8 @@ extern template class Aidge::ConvDepthWise_Op<2>;
 
 namespace {
 template <>
-const char *const EnumStrings<Aidge::ConvDepthWiseAttr>::data[] = {"StrideDims", "DilationDims",
-                                                          "KernelDims"};
+const char *const EnumStrings<Aidge::ConvDepthWiseAttr>::data[] = {"stride_dims", "dilation_dims",
+                                                          "kernel_dims"};
 }
 
 #endif /* AIDGE_CORE_OPERATOR_CONVDEPTHWISE_H_ */
diff --git a/include/aidge/operator/Fold.hpp b/include/aidge/operator/Fold.hpp
index 28127f9efe437531a64d228f7ed9c168edc39eb6..caf904e870425c000687ccd95397c92744020eec 100644
--- a/include/aidge/operator/Fold.hpp
+++ b/include/aidge/operator/Fold.hpp
@@ -133,10 +133,10 @@ extern template class Aidge::Fold_Op<2>;
 namespace {
 template <>
 const char *const EnumStrings<Aidge::FoldAttr>::data[] = {
-    "OutputDims",
-    "StrideDims",
-    "DilationDims",
-    "KernelDims"
+    "output_dims",
+    "stride_dims",
+    "dilation_dims",
+    "kernel_dims"
 };
 }
 
diff --git a/include/aidge/operator/Gather.hpp b/include/aidge/operator/Gather.hpp
index 3e9b780732fa9144f2e58bef854d1b42d063d0bf..5f3917e486e2e2188bfd23bd58a13b51d5fc7a59 100644
--- a/include/aidge/operator/Gather.hpp
+++ b/include/aidge/operator/Gather.hpp
@@ -114,7 +114,7 @@ inline std::shared_ptr<Node> Gather(std::int8_t axis = 0, const std::vector<int6
 
 namespace {
 template <>
-const char *const EnumStrings<Aidge::GatherAttr>::data[] = {"Axis", "Indices", "GatheredShape"};
+const char *const EnumStrings<Aidge::GatherAttr>::data[] = {"axis", "indices", "gathered_shape"};
 }
 
 #endif /* AIDGE_CORE_OPERATOR_GATHER_H_ */
diff --git a/include/aidge/operator/LeakyReLU.hpp b/include/aidge/operator/LeakyReLU.hpp
index 294e7ebb009ff184c9150d2aa18067a15deeba22..3057b99f70fa3693f7e434be29dcd40fb98d4bea 100644
--- a/include/aidge/operator/LeakyReLU.hpp
+++ b/include/aidge/operator/LeakyReLU.hpp
@@ -99,7 +99,7 @@ inline std::shared_ptr<Node> LeakyReLU(float negativeSlope = 0.0f, const std::st
 namespace {
 template <>
 const char* const EnumStrings<Aidge::LeakyReLUAttr>::data[]
-    = {"NegativeSlope"};
+    = {"negative_slope"};
 }
 
 #endif /* AIDGE_CORE_OPERATOR_RELU_H_ */
diff --git a/include/aidge/operator/MaxPooling.hpp b/include/aidge/operator/MaxPooling.hpp
index 082aa26bbdf1d55dcae29d1ffb2b9810db8b17d0..7e2c68681e645133812103a94e4c39ab9d1dc970 100644
--- a/include/aidge/operator/MaxPooling.hpp
+++ b/include/aidge/operator/MaxPooling.hpp
@@ -156,7 +156,7 @@ inline std::shared_ptr<Node> MaxPooling(
 
 namespace {
 template <>
-const char *const EnumStrings<Aidge::MaxPoolingAttr>::data[] = {"StrideDims", "KernelDims", "CeilMode"};
+const char *const EnumStrings<Aidge::MaxPoolingAttr>::data[] = {"stride_dims", "kernel_dims", "ceil_mode"};
 }
 
 #endif /* AIDGE_CORE_OPERATOR_MAXPOOLING_H_ */
diff --git a/include/aidge/operator/Memorize.hpp b/include/aidge/operator/Memorize.hpp
index d6af56f2faad18b9e39c793ea68e39eac4dd2f01..bb652e833ad06df37f55d3582afd0e66cc3e97c8 100644
--- a/include/aidge/operator/Memorize.hpp
+++ b/include/aidge/operator/Memorize.hpp
@@ -113,9 +113,9 @@ inline std::shared_ptr<Node> Memorize(const std::uint32_t endStep, const std::st
 namespace {
 template <>
 const char *const EnumStrings<Aidge::MemorizeAttr>::data[] = {
-    "ScheduleStep",
-    "ForwardStep",
-    "EndStep"
+    "schedule_step",
+    "forward_step",
+    "end_step"
 };
 }
 
diff --git a/include/aidge/operator/Pad.hpp b/include/aidge/operator/Pad.hpp
index 5fd0f93986206e6cd958a85055159783eeb8bc8f..215fafb7fee10587dec38e77685d705f7c1bb980 100644
--- a/include/aidge/operator/Pad.hpp
+++ b/include/aidge/operator/Pad.hpp
@@ -139,7 +139,7 @@ extern template class Aidge::Pad_Op<2>;
 
 namespace {
 template <>
-const char *const EnumStrings<Aidge::PadAttr>::data[] = {"BeginEndBorders", "BorderType", "BorderValue"};
+const char *const EnumStrings<Aidge::PadAttr>::data[] = {"begin_end_borders", "border_type", "border_value"};
 
 template <>
 const char *const EnumStrings<Aidge::PadBorderType>::data[] = {"Constant", "Edge", "Reflect", "Wrap"};
diff --git a/include/aidge/operator/Pop.hpp b/include/aidge/operator/Pop.hpp
index 575d56b455940ea98571110dbaa9a83de09fef37..fb3b32eeacf2e199df88b6bd0256cf6cbdaa1065 100644
--- a/include/aidge/operator/Pop.hpp
+++ b/include/aidge/operator/Pop.hpp
@@ -100,7 +100,7 @@ inline std::shared_ptr<Node> Pop(const std::string& name = "") {
 namespace {
 template <>
 const char *const EnumStrings<Aidge::PopAttr>::data[] = {
-    "ForwardStep"
+    "forward_step"
 };
 }
 
diff --git a/include/aidge/operator/Producer.hpp b/include/aidge/operator/Producer.hpp
index 9e3bdd1ba2f601da27dea3a6a01131a0c8191eb4..d391cc629f5cd0dbb9a6961a2cb42a9ae0b186b9 100644
--- a/include/aidge/operator/Producer.hpp
+++ b/include/aidge/operator/Producer.hpp
@@ -160,7 +160,7 @@ std::shared_ptr<Node> addProducer(std::shared_ptr<Node>& otherNode, const IOInde
 namespace {
 template <>
 const char *const EnumStrings<Aidge::ProdAttr>::data[] = {
-    "Constant"
+    "constant"
 };
 }
 #endif /* AIDGE_CORE_OPERATOR_PRODUCER_H_ */
diff --git a/include/aidge/operator/ReduceMean.hpp b/include/aidge/operator/ReduceMean.hpp
index 3fcf19ffd13645fb28b6efcfefaf8e347b148c89..000607c60e4e3c85671e70a941bd11f3427333dd 100644
--- a/include/aidge/operator/ReduceMean.hpp
+++ b/include/aidge/operator/ReduceMean.hpp
@@ -127,7 +127,7 @@ inline std::shared_ptr<Node> ReduceMean(const std::vector<std::int32_t> &axes,
 
 namespace {
 template <>
-const char *const EnumStrings<Aidge::ReduceMeanAttr>::data[] = {"Axes", "KeepDims"};
+const char *const EnumStrings<Aidge::ReduceMeanAttr>::data[] = {"axes", "keep_dims"};
 }
 
 #endif /* AIDGE_CORE_OPERATOR_REDUCEMEAN_H_ */
diff --git a/include/aidge/operator/Reshape.hpp b/include/aidge/operator/Reshape.hpp
index 4ea0cca30089555ff7979f141f94e5c84f04ffa1..29a08c76c248018fff87a5f765a0b62cbd23b6b7 100644
--- a/include/aidge/operator/Reshape.hpp
+++ b/include/aidge/operator/Reshape.hpp
@@ -107,7 +107,7 @@ inline std::shared_ptr<Node> Reshape(const std::vector<std::int64_t>& shape = {}
 
 namespace {
 template <>
-const char *const EnumStrings<Aidge::ReshapeAttr>::data[] = { "Shape", "AllowZero" };
+const char *const EnumStrings<Aidge::ReshapeAttr>::data[] = { "shape", "allow_zero" };
 }
 
 #endif /* AIDGE_CORE_OPERATOR_RESHAPE_H_ */
diff --git a/include/aidge/operator/Scaling.hpp b/include/aidge/operator/Scaling.hpp
index 7d8e11b31546cd87a8d6b2d36e2929c9ef6df7a2..0683a26f6e9d8ef462c2af4693f372b43c33a144 100644
--- a/include/aidge/operator/Scaling.hpp
+++ b/include/aidge/operator/Scaling.hpp
@@ -105,7 +105,7 @@ inline std::shared_ptr<Node> Scaling(float scalingFactor = 1.0f,
 namespace {
 template <>
 const char* const EnumStrings<Aidge::ScalingAttr>::data[]
-    = {"ScalingFactor", "QuantizedNbBits", "IsOutputUnsigned"};
+    = {"scaling_factor", "quantized_nb_bits", "is_output_unsigned"};
 }
 
 #endif /* AIDGE_CORE_OPERATOR_SCALING_H_ */
diff --git a/include/aidge/operator/Shape.hpp b/include/aidge/operator/Shape.hpp
index 6d2d1b5e7c212fafa5ad6457d9e0a260e96b1c90..94f237726e79d8fe7824ff2c9b2f7640bbfc716f 100644
--- a/include/aidge/operator/Shape.hpp
+++ b/include/aidge/operator/Shape.hpp
@@ -105,7 +105,7 @@ inline std::shared_ptr<Node> Shape(const std::int64_t start = 0, const std::int6
 
 namespace {
 template <>
-const char *const EnumStrings<Aidge::ShapeAttr>::data[] = {"Start", "End"};
+const char *const EnumStrings<Aidge::ShapeAttr>::data[] = {"start", "end"};
 }
 
 #endif /* AIDGE_CORE_OPERATOR_SHAPE_H_ */
diff --git a/include/aidge/operator/Slice.hpp b/include/aidge/operator/Slice.hpp
index 7d425a0f3589e74b54ee0834fdc4291ea7f49bad..04a67fe98f7682737bff6df18f28d568ee33e093 100644
--- a/include/aidge/operator/Slice.hpp
+++ b/include/aidge/operator/Slice.hpp
@@ -115,7 +115,7 @@ inline std::shared_ptr<Node> Slice(const std::vector<std::int64_t>& starts = {},
 
 namespace {
 template <>
-const char *const EnumStrings<Aidge::SliceAttr>::data[] = { "Starts", "Ends", "Axes", "Steps" };
+const char *const EnumStrings<Aidge::SliceAttr>::data[] = { "starts", "ends", "axes", "steps" };
 }
 
 #endif /* AIDGE_CORE_OPERATOR_RELU_H_ */
diff --git a/include/aidge/operator/Softmax.hpp b/include/aidge/operator/Softmax.hpp
index 70f3a561ae5c9ba4720de8419bcd5aaf32a51e47..0b7a8e57193439872c6fcc2699b9f5e55c643961 100644
--- a/include/aidge/operator/Softmax.hpp
+++ b/include/aidge/operator/Softmax.hpp
@@ -92,7 +92,7 @@ inline std::shared_ptr<Node> Softmax(std::int32_t axis, const std::string& name
 
 namespace {
 template <>
-const char *const EnumStrings<Aidge::SoftmaxAttr>::data[] = {"Axis"};
+const char *const EnumStrings<Aidge::SoftmaxAttr>::data[] = {"axis"};
 }
 
 #endif /* AIDGE_CORE_OPERATOR_SOFTMAX_H_ */
diff --git a/include/aidge/operator/Split.hpp b/include/aidge/operator/Split.hpp
index 42baf66e6722c6f9a0d3f40f12d4f4685fcc6980..7bdec1579c8a8f46640de5caf42c01568d208059 100644
--- a/include/aidge/operator/Split.hpp
+++ b/include/aidge/operator/Split.hpp
@@ -34,20 +34,24 @@ enum class SplitAttr { Axis, Split };
 
 class Split_Op
     : public OperatorTensor,
-      public Registrable<Split_Op, std::string, std::shared_ptr<OperatorImpl>(const Split_Op &)>,
-      public StaticAttributes<SplitAttr, std::int8_t, std::vector<DimSize_t>> {
+      public Registrable<Split_Op, std::string, std::shared_ptr<OperatorImpl>(const Split_Op &)> {
 
 public:
     static const std::string Type;
 
+private:
+    using Attributes_ = StaticAttributes<SplitAttr, std::int8_t, std::vector<DimSize_t>>;
+    template <SplitAttr e> using attr = typename Attributes_::template attr<e>;
+    const std::shared_ptr<Attributes_> mAttributes;
+
+public:
     Split_Op() = delete;
 
-    using Attributes_ = StaticAttributes<SplitAttr,  std::int8_t, std::vector<DimSize_t>>;
-    template <SplitAttr e> using attr = typename Attributes_::template attr<e>;
     Split_Op( std::int8_t axis, DimSize_t nbOutputs, const std::vector<DimSize_t>& split)
         : OperatorTensor(Type, {InputCategory::Data, InputCategory::OptionalData}, nbOutputs),
-          Attributes_(attr<SplitAttr::Axis>(axis),
-                      attr<SplitAttr::Split>(split))
+          mAttributes(std::make_shared<Attributes_>(
+            attr<SplitAttr::Axis>(axis),
+            attr<SplitAttr::Split>(split)))
     {
         mImpl = std::make_shared<Split_OpImpl>(*this);
     }
@@ -60,7 +64,7 @@ public:
      */
     Split_Op(const Split_Op &op)
         : OperatorTensor(op),
-          Attributes_(op)
+          mAttributes(op.mAttributes)
     {
         if (!op.backend().empty()) {
             SET_IMPL_MACRO(Split_Op, *this, op.backend());
@@ -81,6 +85,10 @@ public:
 
     void setBackend(const std::string &name, DeviceIdx_t device = 0) override;
 
+    inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
+    inline std::int8_t& axis() const { return mAttributes->template getAttr<SplitAttr::Axis>(); }
+    inline std::vector<DimSize_t>& split() const { return mAttributes->template getAttr<SplitAttr::Split>(); }
+
     static const std::vector<std::string> getInputsName(){
         return {"data_input", "split"};
     }
@@ -105,7 +113,7 @@ inline std::shared_ptr<Node> Split(DimSize_t nbOutput,
 
 namespace {
 template <>
-const char *const EnumStrings<Aidge::SplitAttr>::data[] = { "Axis", "Split" };
+const char *const EnumStrings<Aidge::SplitAttr>::data[] = { "axis", "split" };
 }
 
 #endif /* AIDGE_CORE_OPERATOR_SPLIT_H_ */
diff --git a/include/aidge/operator/Transpose.hpp b/include/aidge/operator/Transpose.hpp
index 72096448ebf0e00d73e33bdab094ca7f0b7d0633..efd9e1792d530f45754809913a7c648d82c7985e 100644
--- a/include/aidge/operator/Transpose.hpp
+++ b/include/aidge/operator/Transpose.hpp
@@ -105,7 +105,7 @@ inline std::shared_ptr<Node> Transpose(const std::vector<DimSize_t> &outputDimsO
 
 namespace {
 template <>
-const char *const EnumStrings<Aidge::TransposeAttr>::data[] = {"OutputDimsOrder"};
+const char *const EnumStrings<Aidge::TransposeAttr>::data[] = {"output_dims_order"};
 }
 
 #endif /* AIDGE_CORE_OPERATOR_TRANSPOSE_H_ */
diff --git a/include/aidge/operator/Unfold.hpp b/include/aidge/operator/Unfold.hpp
index 169fbb05ebeff0e5d38eb9606133d6279cc31cd8..58cbcd2d756ad44ef2ec6a38d46909a114b187c2 100644
--- a/include/aidge/operator/Unfold.hpp
+++ b/include/aidge/operator/Unfold.hpp
@@ -137,9 +137,9 @@ extern template class Aidge::Unfold_Op<2>;
 namespace {
 template <>
 const char *const EnumStrings<Aidge::UnfoldAttr>::data[] = {
-    "StrideDims",
-    "DilationDims",
-    "KernelDims"
+    "stride_dims",
+    "dilation_dims",
+    "kernel_dims"
 };
 }
 
diff --git a/include/aidge/utils/Attributes.hpp b/include/aidge/utils/Attributes.hpp
index c1f6a8a7f704b4bd813983cb178d9e5acba5a5e1..7dce3d327d42de15dc2589788b4643742ed1a463 100644
--- a/include/aidge/utils/Attributes.hpp
+++ b/include/aidge/utils/Attributes.hpp
@@ -42,32 +42,6 @@ constexpr std::size_t size(T (&)[N]) { return N; }
 *  Attributes in the binding code.
 */
 class Attributes {
-protected:
-    /**
-     * @brief Convert snake_case to PascalCase.
-     * @param snakeCase string to convert.
-    */
-    static std::string snakeToPascal(const std::string& snakeCase);
-
-
-    /**
-     * @brief Convert PascalCase to snake_case.
-     * @param pascalCase string to convert.
-    */
-    static std::string pascalToSnake(const std::string& pascalCase);
-
-    /**
-     * @brief Check whether a given string is in PascalCase.
-     * @param str String to check.
-     */
-    static bool isPascalCase(const std::string& str);
-
-    /**
-     * @brief Check whether a given string is in snake_case.
-     * @param str String to check.
-     */
-    static bool isSnakeCase(const std::string& str);
-
 public:
     /**
      * @brief Check if the attribute exists.
diff --git a/include/aidge/utils/DynamicAttributes.hpp b/include/aidge/utils/DynamicAttributes.hpp
index 26a2d07667da78c9b4c37ad8700fd5b17c603a4a..cf7f048dbe5999f433277c46e4e3cb9798c43674 100644
--- a/include/aidge/utils/DynamicAttributes.hpp
+++ b/include/aidge/utils/DynamicAttributes.hpp
@@ -50,12 +50,11 @@ public:
     {
         const auto dot = name.find('.');
         if (dot == name.npos) {
-            AIDGE_ASSERT(isPascalCase(name), "Aidge standard requires PascalCase for C++ Attributes for \"{}\".", name);
 #ifdef PYBIND
             // If attribute does not exist in C++, it might have been created or modified in Python
             auto it = mAttrs.find(name);
             if (it == mAttrs.end()) {
-                auto itPy = mAttrsPy.find(pascalToSnake(name));
+                auto itPy = mAttrsPy.find(name);
                 if (itPy != mAttrsPy.end()) {
                     // Insert the attribute back in C++
                     mAttrs.emplace(std::make_pair(name, future_std::any(itPy->second.cast<T>())));
@@ -67,7 +66,6 @@ public:
         }
         else {
             const auto ns = name.substr(0, dot);
-            AIDGE_ASSERT(isPascalCase(ns), "Aidge standard requires PascalCase for C++ Attributes namespace for \"{}\".", ns);
             const auto nsName = name.substr(dot + 1);
             return future_std::any_cast<const DynamicAttributes&>(mAttrs.at(ns)).getAttr<T>(nsName);
         }
@@ -87,22 +85,20 @@ public:
     {
         const auto dot = name.find('.');
         if (dot == name.npos) {
-            AIDGE_ASSERT(isPascalCase(name), "Aidge standard requires PascalCase for C++ Attributes for \"{}\".", name);
             const auto& res = mAttrs.emplace(std::make_pair(name, future_std::any(value)));
-            AIDGE_ASSERT(res.second, "attribute \"{}\" already exists", name);
+            AIDGE_ASSERT(res.second, "addAttr(): attribute \"{}\" already exists. Use setAttr() if this is expected.", name);
 
 #ifdef PYBIND
             // We cannot handle Python object if the Python interpreter is not running
             if (Py_IsInitialized()) {
                 // Keep a copy of the attribute in py::object that is updated everytime
-                const auto& resPy = mAttrsPy.emplace(std::make_pair(pascalToSnake(name), py::cast(value)));
-                AIDGE_ASSERT(resPy.second, "attribute \"{}\" already exists (added in Python)", name);
+                const auto& resPy = mAttrsPy.emplace(std::make_pair(name, py::cast(value)));
+                AIDGE_ASSERT(resPy.second, "addAttr(): attribute \"{}\" already exists (added in Python). Use setAttr() if this is expected.", name);
             }
 #endif
         }
         else {
             const auto ns = name.substr(0, dot);
-            AIDGE_ASSERT(isPascalCase(ns), "Aidge standard requires PascalCase for C++ Attributes namespace for \"{}\".", ns);
             const auto nsName = name.substr(dot + 1);
             const auto& res = mAttrs.emplace(std::make_pair(ns, future_std::any(DynamicAttributes())));
             future_std::any_cast<DynamicAttributes&>(res.first->second).addAttr(nsName, value);
@@ -117,7 +113,6 @@ public:
     {
         const auto dot = name.find('.');
         if (dot == name.npos) {
-            AIDGE_ASSERT(isPascalCase(name), "Aidge standard requires PascalCase for C++ Attributes for \"{}\".", name);
             auto res = mAttrs.emplace(std::make_pair(name, future_std::any(value)));
             if (!res.second)
                 res.first->second = future_std::any(value);
@@ -134,7 +129,6 @@ public:
         }
         else {
             const auto ns = name.substr(0, dot);
-            AIDGE_ASSERT(isPascalCase(ns), "Aidge standard requires PascalCase for C++ Attributes namespace for \"{}\".", ns);
             const auto nsName = name.substr(dot + 1);
             auto res = mAttrs.emplace(std::make_pair(ns, future_std::any(DynamicAttributes())));
             future_std::any_cast<DynamicAttributes&>(res.first->second).setAttr<T>(nsName, value);
@@ -144,15 +138,15 @@ public:
     void delAttr(const std::string& name) {
         const auto dot = name.find('.');
         if (dot == name.npos) {
-            mAttrs.erase((isSnakeCase(name)) ? snakeToPascal(name) : name);
+            mAttrs.erase(name);
 #ifdef PYBIND
-            mAttrsPy.erase((isPascalCase(name)) ? pascalToSnake(name) : name);
+            mAttrsPy.erase(name);
 #endif
         }
         else {
             const auto ns = name.substr(0, dot);
             const auto nsName = name.substr(dot + 1);
-            future_std::any_cast<DynamicAttributes&>(mAttrs.at((isSnakeCase(ns)) ? snakeToPascal(ns) : ns)).delAttr(nsName);
+            future_std::any_cast<DynamicAttributes&>(mAttrs.at(ns)).delAttr(nsName);
         }
     }
 
@@ -161,18 +155,16 @@ public:
     {
         const auto dot = name.find('.');
         if (dot == name.npos) {
-            AIDGE_ASSERT(isSnakeCase(name), "Aidge standard requires snake_case for Attributes with Python for \"{}\".", name);
-            auto it = mAttrs.find(snakeToPascal(name));
-            AIDGE_ASSERT(it == mAttrs.end(), "attribute \"{}\" already exists (added in C++)", name);
+            auto it = mAttrs.find(name);
+            AIDGE_ASSERT(it == mAttrs.end(), "add_attr(): attribute \"{}\" already exists (added in C++). Use set_attr() if this is expected.", name);
 
             const auto& res = mAttrsPy.emplace(std::make_pair(name, value));
-            AIDGE_ASSERT(res.second, "attribute \"{}\" already exists", name);
+            AIDGE_ASSERT(res.second, "add_attr(): attribute \"{}\" already exists. Use set_attr() if this is expected.", name);
         }
         else {
             const auto ns = name.substr(0, dot);
-            AIDGE_ASSERT(isSnakeCase(ns), "Aidge standard requires snake_case for Attributes namespace with Python for \"{}\".", ns);
             const auto nsName = name.substr(dot + 1);
-            const auto& res = mAttrs.emplace(std::make_pair(snakeToPascal(ns), DynamicAttributes()));
+            const auto& res = mAttrs.emplace(std::make_pair(ns, DynamicAttributes()));
 
             future_std::any_cast<DynamicAttributes&>(res.first->second).addAttrPy(nsName, std::move(value));
         }
@@ -182,20 +174,17 @@ public:
     {
         const auto dot = name.find('.');
         if (dot == name.npos) {
-            AIDGE_ASSERT(isSnakeCase(name), "Aidge standard requires snake_case for Attributes with Python for \"{}\".", name);
             auto resPy = mAttrsPy.emplace(std::make_pair(name, value));
             if (!resPy.second)
                 resPy.first->second = std::move(value);
 
             // Force getAttr() to take attribute value from mAttrsPy and update mAttrs
-            const std::string pascalName = snakeToPascal(name);
-            mAttrs.erase(pascalName);
+            mAttrs.erase(name);
         }
         else {
             const auto ns = name.substr(0, dot);
-            AIDGE_ASSERT(isSnakeCase(ns), "Aidge standard requires snake_case for Attributes namespace with Python for \"{}\".", ns);
             const auto nsName = name.substr(dot + 1);
-            const auto& res = mAttrs.emplace(std::make_pair(snakeToPascal(ns), DynamicAttributes()));
+            const auto& res = mAttrs.emplace(std::make_pair(ns, DynamicAttributes()));
 
             future_std::any_cast<DynamicAttributes&>(res.first->second).setAttrPy(nsName, std::move(value));
         }
@@ -204,14 +193,12 @@ public:
     py::dict dict() const override {
         py::dict attributes;
         for (const auto& elt : mAttrs) {
-            const std::string snakeName = pascalToSnake(elt.first);
             if (elt.second.type() == typeid(DynamicAttributes)) {
-                attributes[snakeName.c_str()] = future_std::any_cast<const DynamicAttributes&>(elt.second).dict();
+                attributes[elt.first.c_str()] = future_std::any_cast<const DynamicAttributes&>(elt.second).dict();
             }
         }
         for (const auto& elt : mAttrsPy) {
-            const std::string snakeName = pascalToSnake(elt.first);
-            attributes[snakeName.c_str()] = elt.second;
+            attributes[elt.first.c_str()] = elt.second;
         }
         return attributes;
     }
@@ -234,9 +221,8 @@ public:
     bool hasAttr(const std::string& name) const override final {
         const auto dot = name.find('.');
         if (dot == name.npos) {
-            AIDGE_ASSERT(isPascalCase(name), "Aidge standard requires PascalCase for C++ Attributes for \"{}\".", name);
 #ifdef PYBIND
-            return (mAttrs.find(name) != mAttrs.cend() || mAttrsPy.find(pascalToSnake(name)) != mAttrsPy.cend());
+            return (mAttrs.find(name) != mAttrs.cend() || mAttrsPy.find(name) != mAttrsPy.cend());
 
 #else
             return (mAttrs.find(name) != mAttrs.cend());
@@ -244,7 +230,6 @@ public:
         }
         else {
             const auto ns = name.substr(0, dot);
-            AIDGE_ASSERT(isPascalCase(ns), "Aidge standard requires PascalCase for C++ Attributes namespace \"{}\".", ns);
             const auto it = mAttrs.find(ns);
             if (it != mAttrs.cend()) {
                 const auto nsName = name.substr(dot + 1);
@@ -260,14 +245,12 @@ public:
     bool hasAttrPy(const std::string& name) const override final {
         const auto dot = name.find('.');
         if (dot == name.npos) {
-            AIDGE_ASSERT(isSnakeCase(name), "Aidge standard requires snake_case for Attributes with Python for \"{}\".", name);
             // Attributes might have been created in Python, the second condition is necessary.
-            return (mAttrs.find(snakeToPascal(name)) != mAttrs.cend() || mAttrsPy.find(name) != mAttrsPy.cend());
+            return (mAttrs.find(name) != mAttrs.cend() || mAttrsPy.find(name) != mAttrsPy.cend());
         }
         else {
             const auto ns = name.substr(0, dot);
-            AIDGE_ASSERT(isSnakeCase(ns), "Aidge standard requires snake_case for Attributes namespace with Python for \"{}\".", ns);
-            const auto it = mAttrs.find(snakeToPascal(ns));
+            const auto it = mAttrs.find(ns);
             if (it != mAttrs.cend()) {
                 const auto nsName = name.substr(dot + 1);
                 return future_std::any_cast<const DynamicAttributes&>(it->second).hasAttrPy(nsName);
@@ -326,12 +309,11 @@ public:
     inline py::object getAttrPy(const std::string& name) const override final {
         const auto dot = name.find('.');
         if (dot == name.npos) {
-            AIDGE_ASSERT(isSnakeCase(name), "Aidge standard requires snake_case for Attributes with Python for \"{}\".", name);
             auto itPy = mAttrsPy.find(name);
             if (itPy == mAttrsPy.end()) {
                 // Attribute may be a namespace
-                auto it = mAttrs.find(snakeToPascal(name));
-                AIDGE_ASSERT(it != mAttrs.end() && it->second.type() == typeid(DynamicAttributes), "attribute \"{}\" not found", name);
+                auto it = mAttrs.find(name);
+                AIDGE_ASSERT(it != mAttrs.end() && it->second.type() == typeid(DynamicAttributes), "get_attr(): attribute \"{}\" not found", name);
                 return py::cast(future_std::any_cast<const DynamicAttributes&>(it->second));
             }
             else {
@@ -339,11 +321,9 @@ public:
             }
         }
         else {
-            // Namespace is stored in mAttrs, so convention should be pascal.
             const auto ns = name.substr(0, dot);
-            AIDGE_ASSERT(isSnakeCase(ns), "Aidge standard requires snake_case for Attributes namespace with Python for \"{}\".", ns);
             const auto nsName = name.substr(dot + 1);
-            return future_std::any_cast<const DynamicAttributes&>(mAttrs.at(snakeToPascal(ns))).getAttrPy(nsName);
+            return future_std::any_cast<const DynamicAttributes&>(mAttrs.at(ns)).getAttrPy(nsName);
         }
     };
 #endif
diff --git a/include/aidge/utils/StaticAttributes.hpp b/include/aidge/utils/StaticAttributes.hpp
index 8fc88ff79c50751ba7b79662fc9fc430d4ed601d..3bb41b5bb0d9c2727d95a2656a1a2d5b96ff950b 100644
--- a/include/aidge/utils/StaticAttributes.hpp
+++ b/include/aidge/utils/StaticAttributes.hpp
@@ -180,7 +180,6 @@ public:
     //////////////////////////////////////
     // Runtime existance check with name
     bool hasAttr(const std::string& name) const override final {
-        AIDGE_ASSERT(isPascalCase(name), "Aidge standard requires PascalCase for C++ Attributes.");
         for (std::size_t i = 0; i < size(EnumStrings<ATTRS_ENUM>::data); ++i) {
             if (name == EnumStrings<ATTRS_ENUM>::data[i]) {
                 return true;
@@ -192,10 +191,8 @@ public:
 
 #ifdef PYBIND
         bool hasAttrPy(const std::string& name) const override final {
-        AIDGE_ASSERT(isSnakeCase(name), "Aidge standard requires snake_case for Attributes with Python, got '{}'.", name);
-        const std::string pascalName = snakeToPascal(name);
         for (std::size_t i = 0; i < size(EnumStrings<ATTRS_ENUM>::data); ++i) {
-            if (pascalName == EnumStrings<ATTRS_ENUM>::data[i]) {
+            if (name == EnumStrings<ATTRS_ENUM>::data[i]) {
                 return true;
             }
         }
@@ -234,7 +231,7 @@ public:
     static std::set<std::string> staticGetAttrsName() {
         std::set<std::string> attrsName;
         for (std::size_t i = 0; i < size(EnumStrings<ATTRS_ENUM>::data); ++i) {
-            attrsName.insert(pascalToSnake(std::string(EnumStrings<ATTRS_ENUM>::data[i])));
+            attrsName.insert(std::string(EnumStrings<ATTRS_ENUM>::data[i]));
         }
         return attrsName;
     }
@@ -244,10 +241,9 @@ public:
         if (name == "__dict__") {
             return py::none();
         }
-        AIDGE_ASSERT(isSnakeCase(name), "Aidge standard requires snake_case for Attributes with Python, got '{}'.", name);
-        const std::string pascalName = snakeToPascal(name);
+
         for (std::size_t i = 0; i < size(EnumStrings<ATTRS_ENUM>::data); ++i) {
-            if (pascalName == EnumStrings<ATTRS_ENUM>::data[i]) {
+            if (name == EnumStrings<ATTRS_ENUM>::data[i]) {
                 // https://github.com/pybind/pybind11/blob/f3e0602802c7840992c97f4960515777cad6a5c7/include/pybind11/pytypes.h#L1119-L1138
                 // Normal accessor would not work as we convert the tuple to a py::object which can be anything
                 return py::detail::accessor_policies::tuple_item::get(py::cast(mAttrs), static_cast<py::size_t>(i));
@@ -264,10 +260,8 @@ public:
 
 
     void setAttrPy(const std::string& name, py::object&& value) override final{
-        AIDGE_ASSERT(isSnakeCase(name), "Aidge standard requires snake_case for Attributes with Python, got '{}'.", name);
-        const std::string pascalName = snakeToPascal(name);
         for (std::size_t i = 0; i < size(EnumStrings<ATTRS_ENUM>::data); ++i) {
-            if (pascalName == EnumStrings<ATTRS_ENUM>::data[i]) {
+            if (name == EnumStrings<ATTRS_ENUM>::data[i]) {
                 // Cannot update attribute using reference has it would require templating
                 // Use a dirty
                 auto tmpAttr = py::cast(mAttrs);
@@ -282,10 +276,9 @@ public:
     py::dict dict() const override {
         py::dict attributes;
         for (std::size_t i = 0; i < size(EnumStrings<ATTRS_ENUM>::data); ++i) {
-            const std::string snakeName = pascalToSnake(EnumStrings<ATTRS_ENUM>::data[i]);
-                // https://github.com/pybind/pybind11/blob/f3e0602802c7840992c97f4960515777cad6a5c7/include/pybind11/pytypes.h#L1119-L1138
-                // Normal accessor would not work as we convert the tuple to a py::object which can be anything
-            attributes[snakeName.c_str()] = py::detail::accessor_policies::tuple_item::get(py::cast(mAttrs), static_cast<py::size_t>(i));
+            // https://github.com/pybind/pybind11/blob/f3e0602802c7840992c97f4960515777cad6a5c7/include/pybind11/pytypes.h#L1119-L1138
+            // Normal accessor would not work as we convert the tuple to a py::object which can be anything
+            attributes[EnumStrings<ATTRS_ENUM>::data[i]] = py::detail::accessor_policies::tuple_item::get(py::cast(mAttrs), static_cast<py::size_t>(i));
         }
         return attributes;
     }
@@ -306,8 +299,7 @@ public:
     // AttrDict get_a() const {
     //     py::dict attributes_;
     //     for (std::size_t i = 0; i < size(EnumStrings<ATTRS_ENUM>::data); ++i) {
-    //         const std::string snakeName = pascalToSnake(std::string(EnumStrings<ATTRS_ENUM>::data[i]));
-    //         attributes_[snakeName.c_str()] = py::detail::accessor_policies::tuple_item::get(py::cast(mAttrs), static_cast<py::size_t>(i));
+    //         attributes_[EnumStrings<ATTRS_ENUM>::data[i]] = py::detail::accessor_policies::tuple_item::get(py::cast(mAttrs), static_cast<py::size_t>(i));
     //     }
     //     return AttrDict(attributes_);
     // }
diff --git a/python_binding/operator/pybind_Split.cpp b/python_binding/operator/pybind_Split.cpp
index 6efc123864f21bf8ea02008b29fe59f31685f17c..f63a01f9815aa59cfbad0aea36f148899f44c9ea 100644
--- a/python_binding/operator/pybind_Split.cpp
+++ b/python_binding/operator/pybind_Split.cpp
@@ -21,14 +21,13 @@ namespace py = pybind11;
 namespace Aidge {
 
 void init_Split(py::module& m) {
-    py::class_<Split_Op, std::shared_ptr<Split_Op>, Attributes, OperatorTensor>(m, "SplitOp", py::multiple_inheritance())
+    py::class_<Split_Op, std::shared_ptr<Split_Op>, OperatorTensor>(m, "SplitOp", py::multiple_inheritance())
         .def(py::init<DimSize_t, std::int8_t, std::vector<DimSize_t>&>(),
                 py::arg("nb_outputs"),
                 py::arg("axis"),
                 py::arg("split"))
         .def_static("get_inputs_name", &Split_Op::getInputsName)
-        .def_static("get_outputs_name", &Split_Op::getOutputsName)
-        .def_static("attributes_name", &Split_Op::staticGetAttrsName);
+        .def_static("get_outputs_name", &Split_Op::getOutputsName);
 
     declare_registrable<Split_Op>(m, "SplitOp");
 
diff --git a/python_binding/utils/pybind_Attributes.cpp b/python_binding/utils/pybind_Attributes.cpp
index d449feaad9a7234e6f67215737795672fc54e9ac..6989e1274e253afa828e4a941c514fc649525af6 100644
--- a/python_binding/utils/pybind_Attributes.cpp
+++ b/python_binding/utils/pybind_Attributes.cpp
@@ -21,12 +21,12 @@ namespace Aidge {
 
 DynamicAttributes test_DynamicAttributes_binding() {
     DynamicAttributes attrs;
-    attrs.addAttr<int>("A", 42);
-    attrs.addAttr<std::string>("B", "test");
-    attrs.addAttr<std::vector<bool>>("C", {true, false, true});
-    attrs.addAttr("Mem.A", 1);
-    attrs.addAttr("Mem.Data.B", 1.0f);
-    attrs.addAttr("Impl.C", std::string("test"));
+    attrs.addAttr<int>("a", 42);
+    attrs.addAttr<std::string>("b", "test");
+    attrs.addAttr<std::vector<bool>>("c", {true, false, true});
+    attrs.addAttr("mem.a", 1);
+    attrs.addAttr("mem.data.b", 1.0f);
+    attrs.addAttr("impl.c", std::string("test"));
     return attrs;
 }
 
diff --git a/src/operator/Shape.cpp b/src/operator/Shape.cpp
index 8166712e1e5fd967bb9328e95ecf8c5388636ba7..39f5e2fe09b7ac750b8ea9d48d17fc2e97013c1a 100644
--- a/src/operator/Shape.cpp
+++ b/src/operator/Shape.cpp
@@ -34,17 +34,17 @@ const std::string Aidge::Shape_Op::Type = "Shape";
 
 bool Aidge::Shape_Op::forwardDims(bool /*allowDataDependency*/) {
     if (inputsAssociated()) {
-        if (mAttributes->template getAttr<std::int64_t>("Start") < 0)
-            mAttributes->template getAttr<std::int64_t>("Start") += static_cast<std::int64_t>(getInput(0)->nbDims());
-        if (mAttributes->template getAttr<std::int64_t>("End") < 0)
-            mAttributes->template getAttr<std::int64_t>("End") += static_cast<std::int64_t>(getInput(0)->nbDims());
+        if (this->start() < 0)
+            this->start() += static_cast<std::int64_t>(getInput(0)->nbDims());
+        if (this->end() < 0)
+            this->end() += static_cast<std::int64_t>(getInput(0)->nbDims());
 
-        const auto start = mAttributes->template getAttr<std::int64_t>("Start");
-        const auto end = mAttributes->template getAttr<std::int64_t>("End");
+        const auto start = this->start();
+        const auto end = this->end();
         const auto nbDims = static_cast<std::int64_t>(getInput(0)->nbDims());
         const DimSize_t roi = end - start + 1;
 
-        AIDGE_ASSERT(start < nbDims && end < nbDims, "'Start' and 'End' must be < {}", nbDims);
+        AIDGE_ASSERT(start < nbDims && end < nbDims, "'start' and 'end' must be < {}", nbDims);
         AIDGE_ASSERT(roi> 1, "Unvalid ROI for Shape");
 
         mOutputs[0]->resize({roi});
diff --git a/src/operator/Split.cpp b/src/operator/Split.cpp
index a0cb049b19e9411daf65bbe2a10319c62b32c1b8..5e9319906a09e774d28af0578919106fb2738d04 100644
--- a/src/operator/Split.cpp
+++ b/src/operator/Split.cpp
@@ -28,8 +28,8 @@
 
 void Aidge::Split_OpImpl::forward() {
     const Split_Op& op = dynamic_cast<const Split_Op&>(mOp);
-    const auto axis = op.template getAttr<std::int8_t>("Axis");
-    const auto splits = op.template getAttr<std::vector<DimSize_t>>("Split");
+    const auto axis = op.axis();
+    const auto splits = op.split();
     const auto dims = op.getInput(0)->dims();
 
     //Compute pre/post axis strides
@@ -68,7 +68,7 @@ bool Aidge::Split_Op::forwardDims(bool allowDataDependency) {
     if (inputsAssociated()) {
         // Copy optional input #1, if present, to attribute Split
         if (getInput(1)) {
-            if (!this->template getAttr<SplitAttr::Split>().empty()) {
+            if (!this->split().empty()) {
                 Log::notice("Split_Op: ignoring non-empty Split attribute because input#1 takes precedence");
             }
 
@@ -78,21 +78,21 @@ bool Aidge::Split_Op::forwardDims(bool allowDataDependency) {
             }
 
             std::shared_ptr<Tensor> fallback;
-            this->template getAttr<SplitAttr::Split>().reserve(getInput(1)->size());
+            this->split().reserve(getInput(1)->size());
             const auto& splits = getInput(1)->refCastFrom(fallback, NativeType<DimSize_t>::type, "cpu");
             std::copy_n(static_cast<DimSize_t*>(splits.getImpl()->hostPtr()),
                         splits.size(),
-                        std::back_inserter(this->template getAttr<SplitAttr::Split>()));
+                        std::back_inserter(this->split()));
         }
 
         // Compute output dims
-        if (this->template getAttr<std::int8_t>("Axis") < 0)
-            this->template getAttr<std::int8_t>("Axis") += static_cast<std::int8_t>(getInput(0)->nbDims());
+        if (this->axis() < 0)
+            this->axis() += static_cast<std::int8_t>(getInput(0)->nbDims());
 
-        DimSize_t dimToSplit = getInput(0)->dims()[this->template getAttr<std::int8_t>("Axis")];
+        DimSize_t dimToSplit = getInput(0)->dims()[this->axis()];
         DimSize_t nbOutput = this->nbOutputs();
         // Fill Split attr if empty
-        if(this->template getAttr<SplitAttr::Split>().empty()) {
+        if(this->split().empty()) {
             // In case the input Split is not provided, divide the dimension of Axis into equal slices
             AIDGE_ASSERT(dimToSplit > nbOutput, "Split_Op: Output number {} musn't be bigger than dimension {}.", nbOutput, dimToSplit);
             DimSize_t baseSliceSize = dimToSplit / nbOutput;
@@ -100,12 +100,12 @@ bool Aidge::Split_Op::forwardDims(bool allowDataDependency) {
             DimSize_t remainder = dimToSplit % nbOutput;
 
             for (DimSize_t i = 0; i < static_cast<DimSize_t>(nbOutput -1); ++i) {
-                    this->template getAttr<SplitAttr::Split>().push_back(baseSliceSize);
+                    this->split().push_back(baseSliceSize);
             }
-            this->template getAttr<SplitAttr::Split>().push_back(baseSliceSize + remainder);
+            this->split().push_back(baseSliceSize + remainder);
         }
 
-        const auto splits = this->template getAttr<SplitAttr::Split>();
+        const auto splits = this->split();
         AIDGE_ASSERT(splits.size() == nbOutput, "Split_Op: number of slices {} must be equal to number of outputs {}", splits, nbOutput);
         DimSize_t totalSplitSize = std::accumulate(splits.cbegin(), splits.cend(), 0);
         AIDGE_ASSERT(totalSplitSize == dimToSplit, "Split_Op: Total chunks size {} is different from dimension size {}.", totalSplitSize, dimToSplit);
@@ -113,7 +113,7 @@ bool Aidge::Split_Op::forwardDims(bool allowDataDependency) {
         std::vector<DimSize_t> outDims = getInput(0)->dims();
         for (std::size_t i = 0; i < nbOutput; ++i)
         {
-            outDims[this->template getAttr<std::int8_t>("Axis")] = this->template getAttr<SplitAttr::Split>()[i];
+            outDims[this->axis()] = this->split()[i];
             mOutputs[i]->resize(outDims);
         }
 
diff --git a/src/utils/Attributes.cpp b/src/utils/Attributes.cpp
deleted file mode 100644
index e79db53a60a955e3502e070cda5818d3d7b6c922..0000000000000000000000000000000000000000
--- a/src/utils/Attributes.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/********************************************************************************
- * Copyright (c) 2023 CEA-List
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0.
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- ********************************************************************************/
-
-#include "aidge/utils/Attributes.hpp"
-
-#include <cctype>  // std::isdigit, std::islower, std::isupper, std::tolower,
-                   // std::toupper
-#include <string>
-
-std::string Aidge::Attributes::snakeToPascal(const std::string& snakeCase) {
-    std::string result;
-    bool to_upper = true; // Start with uppercase for PascalCase
-
-    for (char ch : snakeCase) {
-        if (ch == '_') {
-            to_upper = true; // Next character should be uppercase
-        } else {
-            if (to_upper) {
-                result += std::toupper(ch);
-                to_upper = false; // Reset flag after making a character uppercase
-            } else {
-                result += ch;
-            }
-        }
-    }
-    return result;
-}
-
-std::string Aidge::Attributes::pascalToSnake(const std::string& pascalCase) {
-    std::string result;
-
-    for (char ch : pascalCase) {
-        if (std::isupper(ch)) {
-            if (!result.empty()) {
-                result += '_';
-            }
-            result += std::tolower(ch);
-        } else {
-            result += ch;
-        }
-    }
-    return result;
-}
-
-bool Aidge::Attributes::isPascalCase(const std::string& str) {
-    if (str.empty() || !std::isupper(str[0])) {
-        return false;
-    }
-
-    bool expectUpper = false;
-    for (size_t i = 1; i < str.size(); ++i) {
-        if (str[i] == '_') {
-            return false;
-        }
-        if (std::isupper(str[i])) {
-            if (!expectUpper) {
-                return false;
-            }
-            expectUpper = false;
-        } else if (std::islower(str[i]) || std::isdigit(str[i])) {
-            expectUpper = true;
-        } else {
-            return false;
-        }
-    }
-    return true;
-}
-
-bool Aidge::Attributes::isSnakeCase(const std::string& str) {
-    if (str.empty()) {
-        return false;
-    }
-
-    bool lastCharWasUnderscore = false;
-    for (char ch : str) {
-        if (ch == '_') {
-            if (lastCharWasUnderscore) {
-                return false;
-            }
-            lastCharWasUnderscore = true;
-        } else if (!std::islower(ch) && !std::isdigit(ch)) {
-            return false;
-        } else {
-            lastCharWasUnderscore = false;
-        }
-    }
-    return true;
-}
diff --git a/unit_tests/utils/Test_DynamicAttributes.cpp b/unit_tests/utils/Test_DynamicAttributes.cpp
index c687af95d5e865328bc5f9043e65cdec510e7b22..b8a1264b3ad954e776a5ae4c47f03cd0c3fb82c9 100644
--- a/unit_tests/utils/Test_DynamicAttributes.cpp
+++ b/unit_tests/utils/Test_DynamicAttributes.cpp
@@ -21,42 +21,42 @@ using namespace Aidge;
 TEST_CASE("[core/attributes] DynamicAttributes") {
     SECTION("TestAttr") {
         DynamicAttributes attrs;
-        attrs.addAttr("A", 1);
-        attrs.addAttr("B", 1.0f);
-        attrs.addAttr("C", std::string("test"));
-        attrs.addAttr<std::vector<bool>>("D", {false, true, false});
-
-        REQUIRE(attrs.getAttr<int>("A") == 1);
-        REQUIRE(attrs.getAttr<float>("B") == 1.0f);
-        REQUIRE(attrs.getAttr<std::string>("C") == "test");
-        REQUIRE(attrs.getAttr<std::vector<bool>>("D") == std::vector<bool>{{false, true, false}});
-
-        attrs.addAttr("E", DynamicAttributes());
-        attrs.getAttr<DynamicAttributes>("E").addAttr("E1", 1.0f);
-        attrs.getAttr<DynamicAttributes>("E").addAttr("E2", std::string("test"));
-
-        REQUIRE(attrs.getAttr<DynamicAttributes>("E").getAttr<float>("E1") == 1.0f);
-        REQUIRE(attrs.getAttr<DynamicAttributes>("E").getAttr<std::string>("E2") == "test");
+        attrs.addAttr("a", 1);
+        attrs.addAttr("b", 1.0f);
+        attrs.addAttr("c", std::string("test"));
+        attrs.addAttr<std::vector<bool>>("d", {false, true, false});
+
+        REQUIRE(attrs.getAttr<int>("a") == 1);
+        REQUIRE(attrs.getAttr<float>("b") == 1.0f);
+        REQUIRE(attrs.getAttr<std::string>("c") == "test");
+        REQUIRE(attrs.getAttr<std::vector<bool>>("d") == std::vector<bool>{{false, true, false}});
+
+        attrs.addAttr("e", DynamicAttributes());
+        attrs.getAttr<DynamicAttributes>("e").addAttr("e1", 1.0f);
+        attrs.getAttr<DynamicAttributes>("e").addAttr("e2", std::string("test"));
+
+        REQUIRE(attrs.getAttr<DynamicAttributes>("e").getAttr<float>("e1") == 1.0f);
+        REQUIRE(attrs.getAttr<DynamicAttributes>("e").getAttr<std::string>("e2") == "test");
     }
 
     SECTION("TestAttrNS") {
         DynamicAttributes attrs;
-        attrs.addAttr("Mem.A", 1);
-        attrs.addAttr("Mem.Data.B", 1.0f);
-        attrs.addAttr("Impl.C", std::string("test"));
-        attrs.addAttr<std::vector<bool>>("D", {false, true, false});
-
-        REQUIRE(attrs.getAttr<int>("Mem.A") == 1);
-        REQUIRE(attrs.getAttr<float>("Mem.Data.B") == 1.0f);
-        REQUIRE(attrs.getAttr<std::string>("Impl.C") == "test");
-        REQUIRE(attrs.getAttr<std::vector<bool>>("D") == std::vector<bool>{{false, true, false}});
-
-        attrs.getAttr<DynamicAttributes>("Mem.Data").addAttr("E", 2.0f);
-        attrs.getAttr<DynamicAttributes>("Impl").addAttr("F", std::string("test2"));
-        REQUIRE(attrs.getAttr<float>("Mem.Data.E") == 2.0f);
-        REQUIRE(attrs.getAttr<std::string>("Impl.F") == "test2");
-
-        REQUIRE(attrs.getAttr<DynamicAttributes>("Mem.Data").getAttr<float>("B") == 1.0f);
-        REQUIRE(attrs.getAttr<DynamicAttributes>("Impl").getAttr<std::string>("C") == "test");
+        attrs.addAttr("mem.a", 1);
+        attrs.addAttr("mem.data.b", 1.0f);
+        attrs.addAttr("impl.c", std::string("test"));
+        attrs.addAttr<std::vector<bool>>("d", {false, true, false});
+
+        REQUIRE(attrs.getAttr<int>("mem.a") == 1);
+        REQUIRE(attrs.getAttr<float>("mem.data.b") == 1.0f);
+        REQUIRE(attrs.getAttr<std::string>("impl.c") == "test");
+        REQUIRE(attrs.getAttr<std::vector<bool>>("d") == std::vector<bool>{{false, true, false}});
+
+        attrs.getAttr<DynamicAttributes>("mem.data").addAttr("e", 2.0f);
+        attrs.getAttr<DynamicAttributes>("impl").addAttr("f", std::string("test2"));
+        REQUIRE(attrs.getAttr<float>("mem.data.e") == 2.0f);
+        REQUIRE(attrs.getAttr<std::string>("impl.f") == "test2");
+
+        REQUIRE(attrs.getAttr<DynamicAttributes>("mem.data").getAttr<float>("b") == 1.0f);
+        REQUIRE(attrs.getAttr<DynamicAttributes>("impl").getAttr<std::string>("c") == "test");
     }
 }