RegisterStorageCommitmentScpCallback for Python plugin

Dear Orthanc team,

I observed that the OrthancPluginRegisterStorageCommitmentScpCallback in C++ plugins isn’t available in Python plugins.

Since this callback isn’t on the Orthanc roadmap, I wonder if there’s any reason stopping you from porting this callback?

If there are no specific reasons, I would like to try porting this callback to Python.

I wonder if there’s any resource I can take advantage of? Below are some references I found along the way:

Hi Sun,

Only reason why it is not mapped in the python SDK is a lack of time and lack of interest/funding so far.

You can surely implement it by yourself. You can get inspiration from other callbacks in the python plugin: https://hg.orthanc-server.com/orthanc-python/file/tip/Sources. This is likely not the easiest one to implement because of the “factory” objects.

Best regards,

Alain.

Dear Orthanc team,

I implemented the StorageCommitmentScpCallback for Python and would like to have some feedback.

View the patch diff on GitHub

The patch is uploaded to GitHub for ease of review: https://github.com/j3soon/orthanc-python-storage-commitment/pull/1/files

Since the patch is not trivial (as you mentioned), I would like to ask for your suggestions here before submitting it.

If no further modifications are required, I will submit a patch into the Orthanc internal code following the contribution guidelines (i.e., sign and email a CLA to Osimis & submit a Mercurial patch, as mentioned in https://book.orthanc-server.com/developers/repositories.html#submitting-code )

Description

The original C++ callback is defined as: (ref: https://sdk.orthanc-server.com/group__DicomCallbacks.html#ga86bf2a20f48e22c74bc18d589e51bb02)

OrthancPluginErrorCode
OrthancPluginRegisterStorageCommitmentScpCallback(
  OrthancPluginContext*                    context,
  OrthancPluginStorageCommitmentFactory    factory,
  OrthancPluginStorageCommitmentDestructor destructor,
  OrthancPluginStorageCommitmentLookup     lookup
)

  • The factory callback receives the DICOM Storage Commitment information, and returns a new object handler for later use.
  • The lookup callback is called once for each instance in the DICOM Storage Commitment, and returns an error code for the current instance. It can access the handler constructed in factory.
  • The destructor callback deconstructs the handler created in factory.

Python utilizes reference counting, so we don’t need to explicitly provide a destructor callback. If we want to use a custom destructor, simply use a custom type and define __del__. (In fact, Orthanc does not call the destructor immediately after responding to the DICOM Storage Commitment request. The destructor is called immediately before Orthanc stops/exits. I’m not sure if this is a bug in Orthanc, but this issue does not affect the implementation of the Python callback.)

Therefore, the Python RegisterStorageCommitmentScpCallback should only contain 2 callbacks: factory and lookup.

Below is a Python plugin equivalent to the C++ sample plugin: (https://hg.orthanc-server.com/orthanc/file/tip/OrthancServer/Plugins/Samples/StorageCommitmentScp/Plugin.cpp )

import orthanc

class CallbackData(object):
    def __init__(self):
        print("Constructor called.")
        self.count = 0
    def __del__(self):
        print("Destructor called.")
    def count_post_increment(self):
        self.count += 1
        return self.count - 1

def StorageCommitmentScpCallback(jobId, transactionUid, sopClassUids, sopInstanceUids, remoteAet, calledAet):
    print(jobId, transactionUid, remoteAet, calledAet)
    assert len(sopClassUids) == len(sopInstanceUids)
    for i in range(len(sopClassUids)):
        print("++", sopClassUids[i], sopInstanceUids[i])
    data = CallbackData() # any Python native type or self-defined class
    return data

def StorageCommitmentLookup(sopClassUid, sopInstanceUid, data):
    print("??", sopClassUid, sopInstanceUid)
    if data.count_post_increment() % 2 == 0:
        return orthanc.StorageCommitmentFailureReason.SUCCESS
    else:
        return orthanc.StorageCommitmentFailureReason.NO_SUCH_OBJECT_INSTANCE

orthanc.RegisterStorageCommitmentScpCallback(StorageCommitmentScpCallback, StorageCommitmentLookup)

Details of File Changes

The following are the modification details of this patch:

  • .gitignore & .hgignore:
    For visualization purpose on GitHub, they won’t be included in the final patch.
  • CMakeLists.txt:
    Requires compiling StorageCommitmentScpCallback.cpp.
  • NEWS:
    The Change Log
  • Sources/Plugin.cpp:
    Includes StorageCommitmentScpCallback.h and defines RegisterStorageCommitmentScpCallback for Python. The (TODO) in the comment: New in release (TODO) will be changed to the next release number.
  • Sources/ICallbackRegistration.h & Sources/ICallbackRegistration.cpp:
    Add Apply2 for adding Python callback that receives 2 arguments.
  • Sources/StorageCommitmentScpCallback.h & Sources/StorageCommitmentScpCallback.cpp:
    Code for porting OrthancPluginRegisterStorageCommitmentScpCallback in C++ to RegisterStorageCommitmentScpCallback in Python.
  • Samples/*:
    3 python plugin samples for testing the callback, which are equivalent to the C++ sample plugin: (https://hg.orthanc-server.com/orthanc/file/tip/OrthancServer/Plugins/Samples/StorageCommitmentScp/Plugin.cpp ) . They won’t be included in the final patch for orthanc-python, but I think they may be included in an additional patch for orthanc-tests in https://hg.orthanc-server.com/orthanc-tests/file/default .

Hi,

Thanks a lot for this contribution, that looks very good and your documentation and samples are much appreciated. I’ve made minor comments in the Github PR. Once you’ve replied to these comments and signed the CLA, I will integrate the patch in the main repo.

Best regards,

Alain.

Dear Orthanc team,

I signed and sent the CLA a while ago. Just checking in to make sure the legal team has received it.

Thank you,
Johnson

Hi Johnson,

Yes, everything is in order on that end. I just need some time to reintegrate your changes - I have a ticket for that so I won’t forget.

Sorry for the delay

Alain.

Hi,

Your changes have finally been included in the Python plugin v 4.1 that has just been released.

Thanks for waiting so long :slight_smile:

Alain.

1 Like