Background: Changes Introduced in Python 3.12 and Later
-
Up to Python 3.11, TestComplete automatically made global objects such as
Log,Project, andSysavailable 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 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 still access these globals directly in a single script unit. However, if you import that unit into another module, the globals 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. However, the current Python integration in TestComplete is based on an older architecture that does not fully align with Python’s modern interpreter model. |
Understanding Global Object Visibility Across Modules
Python does not provide constructs (such as using, static const, typedef, or namespaces in C++) to expose symbols across files automatically. However, each module in Python has its own namespace.
The only reliable and future-proof approaches are:
-
Importing required objects.
-
Passing required objects as function arguments.
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
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 explicitly would require extensive script modifications.
To address this, a workaround was introduced in the form of a compatibility layer called the shim. During Python startup, the shim loads a lightweight tc module that preserves 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 |
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:
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. It covers more than 90 percent of typical scenarios.
However, the tc shim has some limitations:
-
Deep import chains or complex recursive scripts might fail occasionally. Since the resolution is dynamic, rerunning the script often fixes the error.
-
TestComplete Globals are not standard Python objects. Some of them are initialized later during runtime, which means their resolution might occasionally fail.
-
Most failures now raise
AttributeError(for example, “Log not found”). However, in some cases,RuntimeErrormight still occur.
