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 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
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 |
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.
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 raisesRuntimeErrorif it cannot find a global object, making error handling more reliable.
