changeset 255:e75a76d11a71

updated SDK to 1.12.9 + manual implementation of SetStableStatus
author Alain Mazy <am@orthanc.team>
date Wed, 16 Jul 2025 15:53:28 +0200
parents b6a5d49c2afd
children 10d11de0fcd5
files CodeAnalysis/CustomFunctions.json CodeAnalysis/GenerateOrthancSDK.py NEWS OrthancSDKVersion.cmake Sources/Autogenerated/orthanc.pyi Sources/Autogenerated/sdk.cpp Sources/Autogenerated/sdk.h Sources/Autogenerated/sdk_GlobalFunctions.impl.h Sources/Autogenerated/sdk_OrthancPluginCompressionType.impl.h Sources/Plugin.cpp
diffstat 10 files changed, 552 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/CodeAnalysis/CustomFunctions.json	Wed Jul 16 10:39:24 2025 +0200
+++ b/CodeAnalysis/CustomFunctions.json	Wed Jul 16 15:53:28 2025 +0200
@@ -373,5 +373,32 @@
       }
     ],
     "return_sdk_type" : "void"
+  },
+
+  {
+    "comment" : "New in release 6.0",
+    "short_name" : "SetStableStatus",
+    "implementation" : "SetStableStatus",
+    "documentation" : {
+      "description" : [ "Change the Stable status of a resource" ],
+      "args" : {
+        "resourceId" : "The id of the resource.",
+        "stableStatus" : "The new stable status: 0 for Stable, 1 for Unstable."
+      },
+      "return" : "A tuple with (The error code, An integer indicating wheter the status has changed (1) or not (0) during the execution of this command)."
+    },
+    "args" : [
+      {
+        "sdk_name" : "resourceId",
+        "sdk_type" : "const char *"
+      },
+      {
+        "sdk_name" : "stableStatus",
+        "sdk_type" : "enumeration",
+        "sdk_enumeration" : "OrthancPluginStableStatus"
+      }
+    ],
+    "return_sdk_type" : "Tuple"
   }
+
 ]
--- a/CodeAnalysis/GenerateOrthancSDK.py	Wed Jul 16 10:39:24 2025 +0200
+++ b/CodeAnalysis/GenerateOrthancSDK.py	Wed Jul 16 15:53:28 2025 +0200
@@ -230,6 +230,9 @@
     elif f['return_sdk_type'] == 'Dictionary':
         # This is only used to generate the documentation file "orthanc.pyi"
         documentation['return_type'] = 'dict'
+    elif f['return_sdk_type'] == 'Tuple':
+        # This is only used to generate the documentation file "orthanc.pyi"
+        documentation['return_type'] = 'tuple'
     else:
         raise Exception('Return type not implemented: %s' % f['return_sdk_type'])
 
--- a/NEWS	Wed Jul 16 10:39:24 2025 +0200
+++ b/NEWS	Wed Jul 16 15:53:28 2025 +0200
@@ -5,6 +5,8 @@
 
 * Added Windows builder for Python 3.13
 * New methods imported from SDK 1.12.9 (TODO: sync again once released)
+  - AuditLog()
+  - SetStableStatus()
 
 
 Version 5.0 (2025-01-22)
--- a/OrthancSDKVersion.cmake	Wed Jul 16 10:39:24 2025 +0200
+++ b/OrthancSDKVersion.cmake	Wed Jul 16 15:53:28 2025 +0200
@@ -1,1 +1,1 @@
-set(ORTHANC_SDK_VERSION "1.12.6")
+set(ORTHANC_SDK_VERSION "1.12.9")
--- a/Sources/Autogenerated/orthanc.pyi	Wed Jul 16 10:39:24 2025 +0200
+++ b/Sources/Autogenerated/orthanc.pyi	Wed Jul 16 15:53:28 2025 +0200
@@ -31,7 +31,7 @@
 
 class ChangeType():
     """
-    The supported types of changes that can be signaled to the change callback. Note: this enum is not used to store changes in the DB !
+    The supported types of changes that can be signaled to the change callback. Note: This enumeration is not used to store changes in the database!
     """
 
     """
@@ -154,6 +154,11 @@
     """
     GZIP_WITH_SIZE: int = 3,
 
+    """
+    No compression (new in Orthanc 1.12.8)
+    """
+    NONE: int = 4,
+
 class ConstraintType():
     """
     The constraints on the tags (main DICOM tags and identifier tags) that must be supported by the database plugins.
@@ -884,6 +889,31 @@
     """
     UNSUPPORTED_MEDIA_TYPE: int = 3000,
 
+class HttpAuthenticationStatus():
+    """
+    The status related to the authentication of a HTTP request.
+    """
+
+    """
+    The authentication has been granted
+    """
+    GRANTED: int = 0,
+
+    """
+    The authentication has failed (401 HTTP status)
+    """
+    UNAUTHORIZED: int = 1,
+
+    """
+    The authorization has failed (403 HTTP status)
+    """
+    FORBIDDEN: int = 2,
+
+    """
+    Redirect to another path (e.g. for login, 307 HTTP status)
+    """
+    REDIRECT: int = 3,
+
 class HttpMethod():
     """
     The various HTTP methods for a REST call.
@@ -1194,6 +1224,21 @@
     """
     GRAYSCALE64: int = 11,
 
+class QueueOrigin():
+    """
+    The supported modes to remove an element from a queue.
+    """
+
+    """
+    Dequeue from the front of the queue
+    """
+    FRONT: int = 0,
+
+    """
+    Dequeue from the back of the queue
+    """
+    BACK: int = 1,
+
 class ReceivedInstanceAction():
     """
     The action to be taken after ReceivedInstanceCallback is triggered
@@ -1244,6 +1289,21 @@
     """
     NONE: int = 4,
 
+class StableStatus():
+    """
+    The "Stable" status of a resource.
+    """
+
+    """
+    The resource is stable
+    """
+    STABLE: int = 0,
+
+    """
+    The resource is unstable
+    """
+    UNSTABLE: int = 1,
+
 class StorageCommitmentFailureReason():
     """
     The available values for the Failure Reason (0008,1197) during storage commitment. http://dicom.nema.org/medical/dicom/2019e/output/chtml/part03/sect_C.14.html#sect_C.14.1.1
@@ -1284,6 +1344,36 @@
     """
     DUPLICATE_TRANSACTION_UID: int = 6,
 
+class StoreStatus():
+    """
+    The store status related to the adoption of a DICOM instance.
+    """
+
+    """
+    The file has been stored/adopted
+    """
+    SUCCESS: int = 0,
+
+    """
+    The file has already been stored/adopted (only if OverwriteInstances is set to false)
+    """
+    ALREADY_STORED: int = 1,
+
+    """
+    The file could not be stored/adopted
+    """
+    FAILURE: int = 2,
+
+    """
+    The file has been filtered out by a Lua script or a plugin
+    """
+    FILTERED_OUT: int = 3,
+
+    """
+    The storage is full (only if MaximumStorageSize/MaximumPatientCount is set and MaximumStorageMode is Reject)
+    """
+    STORAGE_FULL: int = 4,
+
 class ValueRepresentation():
     """
     The value representations present in the DICOM standard (version 2013).
@@ -1426,6 +1516,20 @@
 
 
 
+# Generate an audit log that might be handled by plugins that have registered an handler
+def AuditLog(user_id: str, resource_type: ResourceType, resource_id: str, action: str, log_data: bytes) -> None:
+    """
+    Generate an audit log that might be handled by plugins that have registered an handler.
+
+    Args:
+      user_id (str): A string uniquely identifying the user or entity that is executing the action on the resource.
+      resource_type (ResourceType): The type of the resource this log relates to.
+      resource_id (str): The resource this log relates to.
+      action (str): The action that is performed on the resource.
+      log_data (bytes): A pointer to custom log data.
+    """
+    ...
+
 # This function returns the MIME type of a file by inspecting its extension
 def AutodetectMimeType(path: str) -> str:
     """
@@ -1614,6 +1718,19 @@
     """
     ...
 
+# The iterator loops over the keys according to the lexicographical order
+def CreateKeysValuesIterator(store_id: str) -> KeysValuesIterator:
+    """
+    The iterator loops over the keys according to the lexicographical order.
+
+    Args:
+      store_id (str): A unique identifier identifying both the plugin and the key-value store.
+
+    Returns:
+      KeysValuesIterator: The newly allocated iterator, or NULL in the case of an error. The iterator must be freed by calling OrthancPluginFreeKeysValuesIterator().
+    """
+    ...
+
 # This function decodes one frame of a DICOM image that is stored in a memory buffer
 def DecodeDicomImage(buffer: bytes, frame_index: int) -> Image:
     """
@@ -1628,6 +1745,15 @@
     """
     ...
 
+def DeleteKeyValue(store_id: str, key: str) -> None:
+    """
+
+    Args:
+      store_id (str): A unique identifier identifying both the plugin and the key-value store.
+      key (str): The key of the value to store (note: storeId + key must be unique).
+    """
+    ...
+
 # This function takes as input a memory buffer containing a DICOM file, and outputs a JSON string representing the tags of this DICOM file
 def DicomBufferToJson(buffer: bytes, format: DicomToJsonFormat, flags: DicomToJsonFlags, max_string_length: int) -> str:
     """
@@ -1660,6 +1786,15 @@
     """
     ...
 
+def EnqueueValue(queue_id: str, value: bytes) -> None:
+    """
+
+    Args:
+      queue_id (str): A unique identifier identifying both the plugin and the queue.
+      value (bytes): The value to store.
+    """
+    ...
+
 # Add JavaScript code to customize the default behavior of Orthanc Explorer
 def ExtendOrthancExplorer(javascript: str) -> None:
     """
@@ -1703,6 +1838,19 @@
     """
     ...
 
+# If no custom data is associated with the attachment of interest, the target memory buffer is filled with the NULL value and a zero size
+def GetAttachmentCustomData(attachment_uuid: str) -> bytes:
+    """
+    If no custom data is associated with the attachment of interest, the target memory buffer is filled with the NULL value and a zero size.
+
+    Args:
+      attachment_uuid (str): The UUID of the attachment of interest.
+
+    Returns:
+      bytes: 0 if success, other value if error.
+    """
+    ...
+
 # Get the value of one of the command-line arguments that were used to launch Orthanc
 def GetCommandLineArgument(argument: int) -> str:
     """
@@ -2234,6 +2382,17 @@
     """
     ...
 
+# This function is notably used in the "orthanc-advanced-storage" when the plugin moves an attachment
+def SetAttachmentCustomData(attachment_uuid: str, custom_data: bytes) -> None:
+    """
+    This function is notably used in the "orthanc-advanced-storage" when the plugin moves an attachment.
+
+    Args:
+      attachment_uuid (str): The UUID of the attachment of interest.
+      custom_data (bytes): The value to store.
+    """
+    ...
+
 # This function gives a name to the thread that is calling this function
 def SetCurrentThreadName(thread_name: str) -> None:
     """
@@ -2309,6 +2468,16 @@
     """
     ...
 
+def StoreKeyValue(store_id: str, key: str, value: bytes) -> None:
+    """
+
+    Args:
+      store_id (str): A unique identifier identifying both the plugin and the key-value store.
+      key (str): The key of the value to store (note: storeId + key must be unique).
+      value (bytes): The value to store.
+    """
+    ...
+
 # This function parses a memory buffer that contains a DICOM file, then transcodes it to the given transfer syntax
 def TranscodeDicomInstance(buffer: bytes, transfer_syntax: str) -> DicomInstance:
     """
@@ -2577,6 +2746,20 @@
     """
     ...
 
+# Change the Stable status of a resource
+def SetStableStatus(resource_id: str, stable_status: StableStatus) -> tuple:
+    """
+    Change the Stable status of a resource
+
+    Args:
+      resource_id (str): The id of the resource.
+      stable_status (StableStatus): The new stable status: 0 for Stable, 1 for Unstable.
+
+    Returns:
+      tuple: A tuple with (The error code, An integer indicating wheter the status has changed (1) or not (0) during the execution of this command).
+    """
+    ...
+
 
 class DicomInstance:
     """
@@ -2978,6 +3161,33 @@
         """
         ...
 
+class KeysValuesIterator:
+    """
+    Key-Value store iterator
+    """
+    ...
+
+    
+    # Before using this function, the function OrthancPluginKeysValuesIteratorNext() must have been called at least once
+    def KeysValuesIteratorGetKey(self) -> str:
+        """
+        Before using this function, the function OrthancPluginKeysValuesIteratorNext() must have been called at least once.
+
+        Returns:
+          str: The current key, or NULL in the case of an error.
+        """
+        ...
+    
+    # Before using this function, the function OrthancPluginKeysValuesIteratorNext() must have been called at least once
+    def KeysValuesIteratorGetValue(self) -> bytes:
+        """
+        Before using this function, the function OrthancPluginKeysValuesIteratorNext() must have been called at least once.
+
+        Returns:
+          bytes: The current value, or NULL in the case of an error.
+        """
+        ...
+
 class Peers:
     """
     Orthanc peer
@@ -3230,6 +3440,7 @@
     def StorageAreaCreate(self, uuid: str, content: bytes, size: int, type: ContentType) -> None:
         """
         This function creates a new file inside the storage area that is currently used by Orthanc.
+        Warning: This function will result in a "not implemented" error on versions of the Orthanc core above 1.12.6.
 
         Args:
           uuid (str): The identifier of the file to be created.
@@ -3243,6 +3454,7 @@
     def StorageAreaRead(self, uuid: str, type: ContentType) -> bytes:
         """
         This function reads the content of a given file from the storage area that is currently used by Orthanc.
+        Warning: This function will result in a "not implemented" error on versions of the Orthanc core above 1.12.6.
 
         Args:
           uuid (str): The identifier of the file to be read.
@@ -3257,6 +3469,7 @@
     def StorageAreaRemove(self, uuid: str, type: ContentType) -> None:
         """
         This function removes a given file from the storage area that is currently used by Orthanc.
+        Warning: This function will result in a "not implemented" error on versions of the Orthanc core above 1.12.6.
 
         Args:
           uuid (str): The identifier of the file to be removed.
--- a/Sources/Autogenerated/sdk.cpp	Wed Jul 16 10:39:24 2025 +0200
+++ b/Sources/Autogenerated/sdk.cpp	Wed Jul 16 15:53:28 2025 +0200
@@ -43,6 +43,7 @@
 #include "./sdk_OrthancPluginDicomToJsonFormat.impl.h"
 #include "./sdk_OrthancPluginDicomWebBinaryMode.impl.h"
 #include "./sdk_OrthancPluginErrorCode.impl.h"
+#include "./sdk_OrthancPluginHttpAuthenticationStatus.impl.h"
 #include "./sdk_OrthancPluginHttpMethod.impl.h"
 #include "./sdk_OrthancPluginIdentifierConstraint.impl.h"
 #include "./sdk_OrthancPluginImageFormat.impl.h"
@@ -54,9 +55,12 @@
 #include "./sdk_OrthancPluginLogLevel.impl.h"
 #include "./sdk_OrthancPluginMetricsType.impl.h"
 #include "./sdk_OrthancPluginPixelFormat.impl.h"
+#include "./sdk_OrthancPluginQueueOrigin.impl.h"
 #include "./sdk_OrthancPluginReceivedInstanceAction.impl.h"
 #include "./sdk_OrthancPluginResourceType.impl.h"
+#include "./sdk_OrthancPluginStableStatus.impl.h"
 #include "./sdk_OrthancPluginStorageCommitmentFailureReason.impl.h"
+#include "./sdk_OrthancPluginStoreStatus.impl.h"
 #include "./sdk_OrthancPluginValueRepresentation.impl.h"
 
 #include "./sdk_OrthancPluginDicomInstance.impl.h"
@@ -66,6 +70,7 @@
 #include "./sdk_OrthancPluginFindQuery.impl.h"
 #include "./sdk_OrthancPluginImage.impl.h"
 #include "./sdk_OrthancPluginJob.impl.h"
+#include "./sdk_OrthancPluginKeysValuesIterator.impl.h"
 #include "./sdk_OrthancPluginPeers.impl.h"
 #include "./sdk_OrthancPluginRestOutput.impl.h"
 #include "./sdk_OrthancPluginServerChunkedRequestReader.impl.h"
@@ -83,6 +88,7 @@
 #include "./sdk_OrthancPluginFindQuery.methods.h"
 #include "./sdk_OrthancPluginImage.methods.h"
 #include "./sdk_OrthancPluginJob.methods.h"
+#include "./sdk_OrthancPluginKeysValuesIterator.methods.h"
 #include "./sdk_OrthancPluginPeers.methods.h"
 #include "./sdk_OrthancPluginRestOutput.methods.h"
 #include "./sdk_OrthancPluginServerChunkedRequestReader.methods.h"
@@ -102,6 +108,7 @@
   RegisterOrthancPluginDicomToJsonFormatEnumeration(module);
   RegisterOrthancPluginDicomWebBinaryModeEnumeration(module);
   RegisterOrthancPluginErrorCodeEnumeration(module);
+  RegisterOrthancPluginHttpAuthenticationStatusEnumeration(module);
   RegisterOrthancPluginHttpMethodEnumeration(module);
   RegisterOrthancPluginIdentifierConstraintEnumeration(module);
   RegisterOrthancPluginImageFormatEnumeration(module);
@@ -113,9 +120,12 @@
   RegisterOrthancPluginLogLevelEnumeration(module);
   RegisterOrthancPluginMetricsTypeEnumeration(module);
   RegisterOrthancPluginPixelFormatEnumeration(module);
+  RegisterOrthancPluginQueueOriginEnumeration(module);
   RegisterOrthancPluginReceivedInstanceActionEnumeration(module);
   RegisterOrthancPluginResourceTypeEnumeration(module);
+  RegisterOrthancPluginStableStatusEnumeration(module);
   RegisterOrthancPluginStorageCommitmentFailureReasonEnumeration(module);
+  RegisterOrthancPluginStoreStatusEnumeration(module);
   RegisterOrthancPluginValueRepresentationEnumeration(module);
 
   RegisterOrthancPluginDicomInstanceClass(module);
@@ -125,6 +135,7 @@
   RegisterOrthancPluginFindQueryClass(module);
   RegisterOrthancPluginImageClass(module);
   RegisterOrthancPluginJobClass(module);
+  RegisterOrthancPluginKeysValuesIteratorClass(module);
   RegisterOrthancPluginPeersClass(module);
   RegisterOrthancPluginRestOutputClass(module);
   RegisterOrthancPluginServerChunkedRequestReaderClass(module);
--- a/Sources/Autogenerated/sdk.h	Wed Jul 16 10:39:24 2025 +0200
+++ b/Sources/Autogenerated/sdk.h	Wed Jul 16 15:53:28 2025 +0200
@@ -41,6 +41,7 @@
 PyTypeObject* GetOrthancPluginFindQueryType();
 PyTypeObject* GetOrthancPluginImageType();
 PyTypeObject* GetOrthancPluginJobType();
+PyTypeObject* GetOrthancPluginKeysValuesIteratorType();
 PyTypeObject* GetOrthancPluginPeersType();
 PyTypeObject* GetOrthancPluginRestOutputType();
 PyTypeObject* GetOrthancPluginServerChunkedRequestReaderType();
@@ -119,6 +120,15 @@
   PyObject_HEAD
 
   /* Type-specific fields go here. */
+  OrthancPluginKeysValuesIterator* object_;
+  bool borrowed_;
+} sdk_OrthancPluginKeysValuesIterator_Object;
+
+typedef struct
+{
+  PyObject_HEAD
+
+  /* Type-specific fields go here. */
   OrthancPluginPeers* object_;
   bool borrowed_;
 } sdk_OrthancPluginPeers_Object;
--- a/Sources/Autogenerated/sdk_GlobalFunctions.impl.h	Wed Jul 16 10:39:24 2025 +0200
+++ b/Sources/Autogenerated/sdk_GlobalFunctions.impl.h	Wed Jul 16 15:53:28 2025 +0200
@@ -42,9 +42,36 @@
 extern PyObject *RegisterStorageArea(PyObject* module, PyObject *args);
 extern PyObject *RegisterStorageCommitmentScpCallback(PyObject* module, PyObject *args);
 extern PyObject *RegisterWorklistCallback(PyObject* module, PyObject *args);
+extern PyObject *SetStableStatus(PyObject* module, PyObject *args);
 // End of forward declarations
 
 
+static PyObject* sdk_OrthancPluginAuditLog(PyObject* module, PyObject* args)
+{
+  PythonLock::LogCall("Calling Python global function: OrthancPluginAuditLog()");
+
+  const char* arg0 = NULL;
+  long int arg1 = 0;
+  const char* arg2 = NULL;
+  const char* arg3 = NULL;
+  Py_buffer arg4;
+
+  if (!PyArg_ParseTuple(args, "slsss*", &arg0, &arg1, &arg2, &arg3, &arg4))
+  {
+    PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (5 arguments expected)");
+    return NULL;
+  }
+
+  {
+    PythonThreadsAllower allower;
+    OrthancPluginAuditLog(OrthancPlugins::GetGlobalContext(), arg0, static_cast<OrthancPluginResourceType>(arg1), arg2, arg3, arg4.buf, arg4.len);
+  }
+  PyBuffer_Release(&arg4);
+
+  Py_INCREF(Py_None);
+  return Py_None;
+}
+
 static PyObject* sdk_OrthancPluginAutodetectMimeType(PyObject* module, PyObject* args)
 {
   PythonLock::LogCall("Calling Python global function: OrthancPluginAutodetectMimeType()");
@@ -449,6 +476,39 @@
   }
 }
 
+static PyObject* sdk_OrthancPluginCreateKeysValuesIterator(PyObject* module, PyObject* args)
+{
+  PythonLock::LogCall("Calling Python global function: OrthancPluginCreateKeysValuesIterator()");
+
+  const char* arg0 = NULL;
+
+  if (!PyArg_ParseTuple(args, "s", &arg0))
+  {
+    PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
+    return NULL;
+  }
+
+  // This is the case of a constructor
+  OrthancPluginKeysValuesIterator* obj;
+  {
+    PythonThreadsAllower allower;
+    obj = OrthancPluginCreateKeysValuesIterator(OrthancPlugins::GetGlobalContext(), arg0);
+  }
+  
+  if (obj == NULL)
+  {
+    PythonLock::RaiseException(OrthancPluginErrorCode_InternalError);
+    return NULL;  
+  }
+  else
+  {
+    PyObject *argList = Py_BuildValue("Lb", obj, false /* not borrowed */);
+    PyObject *python = PyObject_CallObject((PyObject *) &sdk_OrthancPluginKeysValuesIterator_Type, argList);
+    Py_DECREF(argList);
+    return python;
+  }
+}
+
 static PyObject* sdk_OrthancPluginDecodeDicomImage(PyObject* module, PyObject* args)
 {
   PythonLock::LogCall("Calling Python global function: OrthancPluginDecodeDicomImage()");
@@ -483,6 +543,38 @@
   }
 }
 
+static PyObject* sdk_OrthancPluginDeleteKeyValue(PyObject* module, PyObject* args)
+{
+  PythonLock::LogCall("Calling Python global function: OrthancPluginDeleteKeyValue()");
+
+  const char* arg0 = NULL;
+  const char* arg1 = NULL;
+
+  if (!PyArg_ParseTuple(args, "ss", &arg0, &arg1))
+  {
+    PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
+    return NULL;
+  }
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginDeleteKeyValue(OrthancPlugins::GetGlobalContext(), arg0, arg1);
+  }
+  
+
+  if (code == OrthancPluginErrorCode_Success)
+  {
+    Py_INCREF(Py_None);
+    return Py_None;
+  }
+  else
+  {
+    PythonLock::RaiseException(code);
+    return NULL;
+  }
+}
+
 static PyObject* sdk_OrthancPluginDicomBufferToJson(PyObject* module, PyObject* args)
 {
   PythonLock::LogCall("Calling Python global function: OrthancPluginDicomBufferToJson()");
@@ -547,6 +639,38 @@
   }
 }
 
+static PyObject* sdk_OrthancPluginEnqueueValue(PyObject* module, PyObject* args)
+{
+  PythonLock::LogCall("Calling Python global function: OrthancPluginEnqueueValue()");
+
+  const char* arg0 = NULL;
+  Py_buffer arg1;
+
+  if (!PyArg_ParseTuple(args, "ss*", &arg0, &arg1))
+  {
+    PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
+    return NULL;
+  }
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginEnqueueValue(OrthancPlugins::GetGlobalContext(), arg0, arg1.buf, arg1.len);
+  }
+  PyBuffer_Release(&arg1);
+
+  if (code == OrthancPluginErrorCode_Success)
+  {
+    Py_INCREF(Py_None);
+    return Py_None;
+  }
+  else
+  {
+    PythonLock::RaiseException(code);
+    return NULL;
+  }
+}
+
 static PyObject* sdk_OrthancPluginExtendOrthancExplorer(PyObject* module, PyObject* args)
 {
   PythonLock::LogCall("Calling Python global function: OrthancPluginExtendOrthancExplorer()");
@@ -638,6 +762,36 @@
   }
 }
 
+static PyObject* sdk_OrthancPluginGetAttachmentCustomData(PyObject* module, PyObject* args)
+{
+  PythonLock::LogCall("Calling Python global function: OrthancPluginGetAttachmentCustomData()");
+
+  const char* arg0 = NULL;
+
+  if (!PyArg_ParseTuple(args, "s", &arg0))
+  {
+    PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (1 arguments expected)");
+    return NULL;
+  }
+
+  OrthancPlugins::MemoryBuffer buffer;
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginGetAttachmentCustomData(OrthancPlugins::GetGlobalContext(), *buffer, arg0);
+  }
+  
+  if (code == OrthancPluginErrorCode_Success)
+  {
+    return PyBytes_FromStringAndSize(buffer.GetData(), buffer.GetSize());
+  }
+  else
+  {
+    PythonLock::RaiseException(code);
+    return NULL;  
+  }
+}
+
 static PyObject* sdk_OrthancPluginGetCommandLineArgument(PyObject* module, PyObject* args)
 {
   PythonLock::LogCall("Calling Python global function: OrthancPluginGetCommandLineArgument()");
@@ -1809,6 +1963,38 @@
   }
 }
 
+static PyObject* sdk_OrthancPluginSetAttachmentCustomData(PyObject* module, PyObject* args)
+{
+  PythonLock::LogCall("Calling Python global function: OrthancPluginSetAttachmentCustomData()");
+
+  const char* arg0 = NULL;
+  Py_buffer arg1;
+
+  if (!PyArg_ParseTuple(args, "ss*", &arg0, &arg1))
+  {
+    PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (2 arguments expected)");
+    return NULL;
+  }
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginSetAttachmentCustomData(OrthancPlugins::GetGlobalContext(), arg0, arg1.buf, arg1.len);
+  }
+  PyBuffer_Release(&arg1);
+
+  if (code == OrthancPluginErrorCode_Success)
+  {
+    Py_INCREF(Py_None);
+    return Py_None;
+  }
+  else
+  {
+    PythonLock::RaiseException(code);
+    return NULL;
+  }
+}
+
 static PyObject* sdk_OrthancPluginSetCurrentThreadName(PyObject* module, PyObject* args)
 {
   PythonLock::LogCall("Calling Python global function: OrthancPluginSetCurrentThreadName()");
@@ -1986,6 +2172,39 @@
   return Py_None;
 }
 
+static PyObject* sdk_OrthancPluginStoreKeyValue(PyObject* module, PyObject* args)
+{
+  PythonLock::LogCall("Calling Python global function: OrthancPluginStoreKeyValue()");
+
+  const char* arg0 = NULL;
+  const char* arg1 = NULL;
+  Py_buffer arg2;
+
+  if (!PyArg_ParseTuple(args, "sss*", &arg0, &arg1, &arg2))
+  {
+    PyErr_SetString(PyExc_TypeError, "Bad types for the arguments (3 arguments expected)");
+    return NULL;
+  }
+
+  OrthancPluginErrorCode code;
+  {
+    PythonThreadsAllower allower;
+    code = OrthancPluginStoreKeyValue(OrthancPlugins::GetGlobalContext(), arg0, arg1, arg2.buf, arg2.len);
+  }
+  PyBuffer_Release(&arg2);
+
+  if (code == OrthancPluginErrorCode_Success)
+  {
+    Py_INCREF(Py_None);
+    return Py_None;
+  }
+  else
+  {
+    PythonLock::RaiseException(code);
+    return NULL;
+  }
+}
+
 static PyObject* sdk_OrthancPluginTranscodeDicomInstance(PyObject* module, PyObject* args)
 {
   PythonLock::LogCall("Calling Python global function: OrthancPluginTranscodeDicomInstance()");
@@ -2089,6 +2308,8 @@
 
 static PyMethodDef ORTHANC_SDK_FUNCTIONS[] = 
 {
+  { "AuditLog", sdk_OrthancPluginAuditLog, METH_VARARGS,
+    "Generated from C function OrthancPluginAuditLog()" },
   { "AutodetectMimeType", sdk_OrthancPluginAutodetectMimeType, METH_VARARGS,
     "Generated from C function OrthancPluginAutodetectMimeType()" },
   { "BufferCompression", sdk_OrthancPluginBufferCompression, METH_VARARGS,
@@ -2115,12 +2336,18 @@
     "Generated from C function OrthancPluginCreateFindMatcher()" },
   { "CreateImage", sdk_OrthancPluginCreateImage, METH_VARARGS,
     "Generated from C function OrthancPluginCreateImage()" },
+  { "CreateKeysValuesIterator", sdk_OrthancPluginCreateKeysValuesIterator, METH_VARARGS,
+    "Generated from C function OrthancPluginCreateKeysValuesIterator()" },
   { "DecodeDicomImage", sdk_OrthancPluginDecodeDicomImage, METH_VARARGS,
     "Generated from C function OrthancPluginDecodeDicomImage()" },
+  { "DeleteKeyValue", sdk_OrthancPluginDeleteKeyValue, METH_VARARGS,
+    "Generated from C function OrthancPluginDeleteKeyValue()" },
   { "DicomBufferToJson", sdk_OrthancPluginDicomBufferToJson, METH_VARARGS,
     "Generated from C function OrthancPluginDicomBufferToJson()" },
   { "DicomInstanceToJson", sdk_OrthancPluginDicomInstanceToJson, METH_VARARGS,
     "Generated from C function OrthancPluginDicomInstanceToJson()" },
+  { "EnqueueValue", sdk_OrthancPluginEnqueueValue, METH_VARARGS,
+    "Generated from C function OrthancPluginEnqueueValue()" },
   { "ExtendOrthancExplorer", sdk_OrthancPluginExtendOrthancExplorer, METH_VARARGS,
     "Generated from C function OrthancPluginExtendOrthancExplorer()" },
   { "ExtendOrthancExplorer2", sdk_OrthancPluginExtendOrthancExplorer2, METH_VARARGS,
@@ -2129,6 +2356,8 @@
     "Generated from C function OrthancPluginGenerateRestApiAuthorizationToken()" },
   { "GenerateUuid", sdk_OrthancPluginGenerateUuid, METH_VARARGS,
     "Generated from C function OrthancPluginGenerateUuid()" },
+  { "GetAttachmentCustomData", sdk_OrthancPluginGetAttachmentCustomData, METH_VARARGS,
+    "Generated from C function OrthancPluginGetAttachmentCustomData()" },
   { "GetCommandLineArgument", sdk_OrthancPluginGetCommandLineArgument, METH_VARARGS,
     "Generated from C function OrthancPluginGetCommandLineArgument()" },
   { "GetCommandLineArgumentsCount", sdk_OrthancPluginGetCommandLineArgumentsCount, METH_VARARGS,
@@ -2213,6 +2442,8 @@
     "Generated from C function OrthancPluginRestApiPut()" },
   { "RestApiPutAfterPlugins", sdk_OrthancPluginRestApiPutAfterPlugins, METH_VARARGS,
     "Generated from C function OrthancPluginRestApiPutAfterPlugins()" },
+  { "SetAttachmentCustomData", sdk_OrthancPluginSetAttachmentCustomData, METH_VARARGS,
+    "Generated from C function OrthancPluginSetAttachmentCustomData()" },
   { "SetCurrentThreadName", sdk_OrthancPluginSetCurrentThreadName, METH_VARARGS,
     "Generated from C function OrthancPluginSetCurrentThreadName()" },
   { "SetDescription", sdk_OrthancPluginSetDescription, METH_VARARGS,
@@ -2227,6 +2458,8 @@
     "Generated from C function OrthancPluginSetRootUri()" },
   { "SetRootUri2", sdk_OrthancPluginSetRootUri2, METH_VARARGS,
     "Generated from C function OrthancPluginSetRootUri2()" },
+  { "StoreKeyValue", sdk_OrthancPluginStoreKeyValue, METH_VARARGS,
+    "Generated from C function OrthancPluginStoreKeyValue()" },
   { "TranscodeDicomInstance", sdk_OrthancPluginTranscodeDicomInstance, METH_VARARGS,
     "Generated from C function OrthancPluginTranscodeDicomInstance()" },
   { "UncompressImage", sdk_OrthancPluginUncompressImage, METH_VARARGS,
@@ -2261,6 +2494,8 @@
     "Implemented in C++ function RegisterStorageCommitmentScpCallback()" },
   { "RegisterWorklistCallback", RegisterWorklistCallback, METH_VARARGS,
     "Implemented in C++ function RegisterWorklistCallback()" },
+  { "SetStableStatus", SetStableStatus, METH_VARARGS,
+    "Implemented in C++ function SetStableStatus()" },
   { NULL, NULL }
 };
 
--- a/Sources/Autogenerated/sdk_OrthancPluginCompressionType.impl.h	Wed Jul 16 10:39:24 2025 +0200
+++ b/Sources/Autogenerated/sdk_OrthancPluginCompressionType.impl.h	Wed Jul 16 15:53:28 2025 +0200
@@ -97,6 +97,12 @@
     Py_DECREF(tmp);
   }
 
+  {
+    PyObject* tmp = PyLong_FromLong(4);
+    PyDict_SetItemString(sdk_OrthancPluginCompressionType_Type.tp_dict, "NONE", tmp);
+    Py_DECREF(tmp);
+  }
+
 
   Py_INCREF(&sdk_OrthancPluginCompressionType_Type);
   if (PyModule_AddObject(module, "CompressionType", (PyObject *)&sdk_OrthancPluginCompressionType_Type) < 0)
--- a/Sources/Plugin.cpp	Wed Jul 16 10:39:24 2025 +0200
+++ b/Sources/Plugin.cpp	Wed Jul 16 15:53:28 2025 +0200
@@ -286,6 +286,49 @@
   }
 }
 
+PyObject* SetStableStatus(PyObject* module, PyObject* args)
+{
+  const char* resourceId = NULL;
+  long int stableStatus = 0;
+
+  if (!PyArg_ParseTuple(args, "sl", &resourceId, &stableStatus))
+  {
+    PyErr_SetString(PyExc_TypeError, "Please provide a string containing the resourceId and a integer with 0 for stable and 1 for unstable");
+    return NULL;
+  }
+  else
+  {
+    OrthancPluginErrorCode code;
+    int32_t statusHasChanged;
+
+    {
+      PythonThreadsAllower allower;
+      code = OrthancPluginSetStableStatus(OrthancPlugins::GetGlobalContext(), &statusHasChanged, resourceId, static_cast<OrthancPluginStableStatus>(stableStatus));
+    }
+    
+    if (code == OrthancPluginErrorCode_Success)
+    {
+      /**
+       * "PyGILState_Ensure()" can be invoked several times from the
+       * same thread, so no problem in creating a PythonLock even if
+       * the GIL is already locked.
+       **/
+      PythonLock lock;
+
+      PythonObject tuple(lock, PyTuple_New(2));
+      PyTuple_SetItem(tuple.GetPyObject(), 0, PyLong_FromUnsignedLong(static_cast<unsigned long>(code)));
+      PyTuple_SetItem(tuple.GetPyObject(), 1, PyLong_FromLong(static_cast<long>(statusHasChanged)));
+      
+      return tuple.Release();
+    }
+    else
+    {
+      std::string message = "Failed to change stable status of resource: " + std::string(resourceId);
+      PyErr_SetString(PyExc_TypeError, message.c_str());
+      return NULL;
+    }
+  }
+}
 
 
 static bool pythonEnabled_ = false;