.. _omnigraph_versioning:

OmniGraph Versioning
####################

There are many facets to OmniGraph that can and will change over time as OmniGraph is still very much a
work in progress. In order to minimize disruption to our users all of these types of changes have been
enumerated and incremental deprecation plans have been created.

.. _omnigraph_deprecation_communication:

Deprecation Communication
*************************

The first thing we will do when some functionality is to be deprecated is to communicate our intent in the
#omni-graph Slack channel, and in the Slack channel of any groups we believe will be affected by the change. The intent
of this initial communication is to coordinate with stakeholders to come to an agreement on a timeline for the
deprecation.

Once a date has been determined we will proceed with up to three phases of deprecation. The combination of phases will
depend on the exact nature of the change and the timeline that has been decided.

.. _omnigraph_soft_deprecation:

Soft Deprecation
================

The soft deprecation phase is where a setting will be introduced to toggle between the old and new behaviors.
The difference between the two could be as trivial as the availability of a deprecated function or as complex
as a complete replacement of a commonly used data structure or algorithm. The setting will be a Carbonite setting
under the tree `/persistent/omnigraph/deprecation/...`.

At this phase the default value of the setting will be to take the original code paths, which will remain untouched.

Communication of the change will take place in two ways:

- An **@channel** announcement will be posted in the Slack channel(s) indicating the new behavior is available
- A deprecation message is added to the original code paths as a one-time warning

.. _omnigraph_default_deprecation:

Default Deprecation
===================

Once you have had a chance to migrate to the new behavior the default behavior will switch:

- An **@channel** announcement will be posted in the Slack channel(s) indicating the new behavior is to be the default
- The setting default will change to take the new code path
- The settings manager will emit a deprecation warning whenever the setting is changed to specify the old code path

.. _omnigraph_hard_deprecation:

Hard Deprecation
================

In the rare case when old behavior must be completely removed, after the agreed on time has passed the old code path
will be removed:

- An **@channel** announcement will be posted in the Slack channel(s) indicating the old behavior is being removed
- The setting and all of the old code paths will be physically deleted
- The settings manager will emit an error whenever the now-deleted setting is attempted to be accessed

.. _omnigraph_semantic_versioning:

Semantic Versioning
*******************

CHANGELOG.md:and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`_, mostly applied to
changes made via the extension versions.

Given a version number MAJOR.MINOR.PATCH, increment the:

    **MAJOR** version when you make incompatible API changes,

    **MINOR** version when you add functionality in a backwards compatible manner

    **PATCH** version when you make backwards compatible bug fixes.


What this means to the C++ programmer is:

    **MAJOR** change: You must recompile and potentially refactor your code for compatibility

    **MINOR** change: You can use your code as-is in binary form, and optionally recompile for compatibility

    **PATCH** change: Your code works as-is in binary form, no need for recompiling


What this means to the Python programmer is:

    **MAJOR** change: Your code may not work. You should refactor to restore correct execution.

    **MINOR** change: Your code will continue to work, however you may receive deprecation warnings and should refactor your code to use the latest interfaces.

    **PATCH** change: Your code will be mostly unaware of the change, other than corrections to previously incorrect behaviours. (You may need to refactor if your code relied on incorrect behaviour.)

.. _omnigraph_public_python_api:

The Public Python API
=====================

We are using the `PEP8 Standard <https://peps.python.org/pep-0008/#public-and-internal-interfaces>`_ for defining the
actual public API we are supporting. 

.. warning::

    Although the nature of Python allows you to inspect and access pretty much anything if it doesn't appear as part
    of our "published" API then it is subject to change at any time without warning. If there is something that is
    not part of the interface you might find particular useful then request that it be surfaced.

The model of import we use is similar to what is used by popular packages like `numpy`, `pandas`, and `scikit-learn`.
You import the top level module as a simple prefix and use the API directly from there.

.. code-block:: python

    # The core OmniGraph functionality
    import omni.graph.core as og
    og.get_all_graphs()

There are two more modules we provide for interacting with OmniGraph:

.. code-block:: python

    # A subset of the OmniGraph functionality that facilitates integration testing
    import omni.graph.core.tests as ogt
    # NOT YET AVAILABLE: A subset of the OmniGraph functionality that implements the AutoNode functionality
    import omni.graph.core.autonode as oga
    # NOT YET AVAILABLE: The code generator framework - for utilities, key/value constants, and typing
    import omni.graph.tools as ogn

.. hint::

    The Python bindings to our ABI are considered part of the published API and are available in the same way as
    all of the other Python functions. They are available in the `omni.graph.core` module.

Getting Old Versions
--------------------

By default you will always get the latest version of the module, however some level of backward compatibility will be
provided through importing a version-specific module. This module will be frozen at the state of the API contents as
of the specified version so that you can continue to access old functionality without warnings until such time as it is
:ref:`hard deprecated<omnigraph_hard_deprecation>`.

.. code-block:: python

    import omni.graph.core._1 as og
    og.the_deprecated_function()


Other Types Of Versions
=======================

OmniGraph Extension Versions
----------------------------

As with other parts of Kit the OmniGraph extensions have their own version number, and the interface definitions each
have their own version number. These version numbers follow the general guidelines used by Kit.

.. only:: internal

    Internal: link to Kit / exts-main-doc broken until kit_repo_docs migration completed (bidirectional dependency bad)

.. _omnigraph_carbonite_versions:

OmniGraph Carbonite Interface Versions
--------------------------------------
A good portion of the OmniGraph interfaces are Carbonite style for historic reasons, so they will follow the
Carbonite upgrade procedures. The primary rules are:

- Existing functions in an interface always work as described
- Functions are never removed from an interface
- Add all new functions to the end of the interface
- Increment the minor version of the interface whenever a new function is added

.. hint::

    Most Carbonite version changes will result in a corresponding minor version bump of the extension in which they live
    as it involves new functionality being added.

.. _omnigraph_oni_versions:

OmniGraph ONI Versions
----------------------

Some of the OmniGraph interfaces, and those developed in the future, will be ONI style, so they will follow the
ONI upgrade procedures. The primary rules are:

- Once an interface is published it can never be changed
- New functionality in an interface is created by adding a new version that is a derived class (e.g. *IBundle2* and *IBundle3*)

.. hint::

    Most ONI version changes will result in a corresponding minor version bump of the extension in which they live as
    it involves new functionality being added.


OmniGraph File Format Versions
------------------------------

The OmniGraph nodes also have a USD backing which itself contains a file format version number. For the most part this
version number is strictly used to automatically migrate a USD scene to the latest version as it would be problematic
to maintain multiple versions within the same code base. It appears as an attribute on the *OmniGraph* prim type.

.. code-block:: USD
    :caption: OmniGraph prim using version 1.4

    def OmniGraph "TestGraph"
    {
        token evaluator:type = "push"
        int2 fileFormatVersion = (1, 4)
        token flatCacheBacking = "Shared"
        token pipelineStage = "pipelineStageSimulation"
        token evaluationMode = "Automatic"
    }

OGN Code Generator Versions
---------------------------
There is also a version number for the .ogn node generator. It is equal to the version number of the extension
containing it (*omni.graph.tools*) and is embedded into the generated code for version management. You should not
need to worry about this version number unless you want to file a bug report, where it would be valuable information.

Node Type Versions
------------------
Every node type definition has a version number with it. The number should be incremented every time there is a change
in behavior of the node, such as adding or removing attributes or changing the computation algorithm. This applies to
nodes you write as well as nodes you consume.

A mismatch in version number between a node being created and the current node implementation will trigger a callback
to the `updateNodeVersion` function, which your node can override if there is some cleanup you can do that will help
maintain expected operation of the node.


Protecting Yourself With Tests
******************************
OmniGraph uses something called the Extension Testing Matrix to validate any dangerous changes. The more tests you have
written that typify your pattern of OmniGraph use the safer it will be for you when changes are made. We can't run
tests we don't have so please help us help you; write more tests!
