Working with TestComplete Global Objects in Python 3.13

Applies to TestComplete 15.79, last modified on December 10, 2025

Background: Changes Introduced in Python 3.12 and Later

  • Up to Python 3.11, TestComplete automatically made global objects such as Log, Project, and Sys available across all script units.

  • Starting with Python 3.12, the interpreter uses isolated states. Even though the TestComplete globals are still available, Python now treats each global as a regular scoped object. A global object defined in one script unit is visible only in that unit unless you explicitly import or pass it as an argument to another unit.

  • You can access these global objects directly in a single script unit. However, when importing units to other modules, the global objects do not carry over automatically.

Note:

Python is a runtime-driven language. It checks for missing or unresolved objects only during execution. This behavior differs from compiled languages such as C++ or Java, which detect such issues at build time.

This limitation comes from Python’s isolation changes introduced in version 3.12 and later. It is not specific to TestComplete. The Python integration in TestComplete is based on an older architecture that does not align with Python’s modern interpreter model.

Understanding Global Object Visibility Across Modules

Python does not provide constructs (such as using, static const, typedef, namespace (or namespaces) in C++) to expose symbols across files automatically. Each module has its own namespace, so to reliably access objects across modules, you must explicitly import the required objects or pass them as function arguments. These approaches help prevent runtime errors caused by missing or unresolved global objects and ensure stable, predictable behavior across modules.

Recommended Fix in Python 3.12 and Later: Pass Objects as Arguments

The recommended solution in Python 3.12 and later is to pass required objects, such as Log, Project, or Sys, explicitly to the functions that use them.

This approach is reliable across recursive calls, nested imports, and repeated runs. It also aligns with Python’s current design and interpreter isolation model.

For existing projects, this approach might require updating multiple function definitions which can be time-consuming. However, this approach is a recommendation for new scripts.

Example: Accessing method from Unit1.py in Unit2.py

Python

# Unit1.py
def test1(Log, Project):
    Log.Message(Project.FileName)

# Unit2.py
import Unit1
def test2(Log, Project, Sys, ProjectSuite):
    Log.Message("From Unit2")
    Unit1.test1(Log, Project)

Compatibility Path for Existing Scripts: tc Shim

Many existing projects rely on the Python 3.11 behavior, where TestComplete globals are automatically accessible across script units. Updating every function to pass these objects requires extensive script modifications.

TestComplete introduces compatibility layer called the shim to resolve this issue. During Python startup, the shim loads a lightweight tc module preserving the normal script execution flow while emulating the global access behavior from Python 3.11. This allows most existing scripts to continue running with minimal or no changes.

Importing and Using the tc Module in Scripts

Import tc at the top of your script before user code runs. You can import all objects or select specific ones.

Note:

The tc module is an internal TestComplete namespace. It is not available on PyPI and does not require installation.

You can import the tc module using any of the following ways:

Python

from tc import *        # brings all TC objects into scope
from tc import Log      # imports only Log
import tc               # access as tc.Log, tc.Project

Example:

Python

# Unit1.py
from tc import Log, Project

def test1():
    Log.Message("Unit1: log_and_project works")
    Log.Message("Unit1: Project path is " + Project.Path)

# Unit2.py
from tc import *
import Unit1

def test2():
    Log.Message("Unit2: Log works, project = " + Project.Path)
    Unit1.test1()
              # access as tc.Log, tc.Project

Centralizing Global Imports in a Shared Configuration File

If your project uses a central configuration file, you can keep all tc imports in one place and reference them from other scripts.

Example:

Python

# globals_tc.py
from tc import Log, Project, Sys, ProjectSuite

# Unit1.py
import globals_tc as G
def test1():
    G.Log.Message("Unit1: " + G.Project.Path)

# Unit2.py
import globals_tc as G
import Unit1
def test2():
    G.Log.Message("Unit2: " + G.Project.Path)
    Unit1.test1()

Coverage and Limitations

The tc shim works reliably for common use cases, such as accessing Log, Project, and Sys across one- or two-level imports.

TestComplete tc shim limitations:

  • Deep import chains or complex recursive scripts might fail occasionally. Since the resolution is dynamic, rerunning the script often fixes the error.

  • TestComplete global objects are not standard Python objects, and some initialize only at runtime, so their resolution might occasionally fail.

  • Most failures now raise AttributeError (for example, “Log not found”), but in some cases, the system raises RuntimeError if it cannot find a global object, making error handling more reliable.

Highlight search results