Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ As of build 305, installation .exe files have been deprecated; see
Coming in build 312, as yet unreleased
--------------------------------------

* Resolved a handful of deprecation warnings (mhammond#2593, [@Avasam][Avasam])
* Deprecate `pythoncom.frozen` (mhammond#2593, [@Avasam][Avasam])
`pythoncom.frozen` used to expose `Py_FrozenFlag` from the C API.
`Py_FrozenFlag` is deprecated since Python 3.12.

Build 311, released 2025/07/14
------------------------------

Expand Down
25 changes: 25 additions & 0 deletions com/pythoncom.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,29 @@
# Magic utility that "redirects" to pythoncomXX.dll
from typing import Any

import pywintypes

pywintypes.__import_pywin32_system_module__("pythoncom", globals())


# This module dynamically re-exports from a C-Extension.
# `__getattr__() -> Any` prevents checkers attribute access errors
# without the use of external type stubs.
# So keep it even if pythoncom.frozen support is removed.
def __getattr__(name: str) -> Any:
Comment on lines +9 to +13
Copy link
Collaborator Author

@Avasam Avasam Apr 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This incidentally has the exact same benefits as https://github.com/mhammond/pywin32/pull/2418/files#diff-417d6662c94f9f97ab29ec3611822c62e6da513054d38f6dfdc0155fc2f4463b
(which does:

from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
    def __getattr__(name: str) -> Any: ...

)

if name == "frozen":
import sys
import warnings

warnings.warn(
f"`pythoncom.frozen` used to expose `Py_FrozenFlag` from the C API. "
+ "`Py_FrozenFlag` is deprecated since Python 3.12. "
+ "Ever since pywin32 b200, loading the `win32com` module has silently "
+ "been replacing `pythoncom.frozen` with `sys.frozen`. "
+ 'Use `getattr(sys, "frozen", False)` directly instead.',
DeprecationWarning,
stacklevel=2,
)
return getattr(sys, "frozen", False)
else:
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
10 changes: 3 additions & 7 deletions com/win32com/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@
import pythoncom
import win32api

# flag if we are in a "frozen" build.
_frozen = getattr(sys, "frozen", False)
# pythoncom dumbly defaults this to zero - we believe sys.frozen over it.
if _frozen and not getattr(pythoncom, "frozen", 0):
pythoncom.frozen = sys.frozen
__frozen: str | bool = getattr(sys, "frozen", False)

# Add support for an external "COM Extensions" path.
# Concept is that you can register a seperate path to be used for
Expand Down Expand Up @@ -86,11 +82,11 @@ def SetupEnvironment():
# (which the win32com developers do!)
def __PackageSupportBuildPath__(package_path):
# See if we have a special directory for the binaries (for developers)
if not _frozen and __build_path__:
if not __frozen and __build_path__:
package_path.append(__build_path__)


if not _frozen:
if not __frozen:
SetupEnvironment()

# If we don't have a special __gen_path__, see if we have a gen_py as a
Expand Down
2 changes: 1 addition & 1 deletion com/win32com/server/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

# Note that we derive from com_error, which derives from builtin Exception
# Also note that we don't support "self.args", as we don't support tuple-unpacking
class COMException(pythoncom.com_error): # type: ignore[name-defined] # Dynamic module
class COMException(pythoncom.com_error): # Dynamic module
"""An Exception object that is understood by the framework.

If the framework is presented with an exception of type class,
Expand Down
29 changes: 14 additions & 15 deletions com/win32com/server/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

"""

from __future__ import annotations

import os
import sys

Expand All @@ -17,6 +19,8 @@

CATID_PythonCOMServer = "{B3EF80D0-68E2-11D0-A689-00C04FD658FF}"

__frozen: str | bool = getattr(sys, "frozen", False)


def _set_subkeys(keyName, valueDict, base=win32con.HKEY_CLASSES_ROOT):
hkey = win32api.RegCreateKey(base, keyName)
Expand Down Expand Up @@ -207,13 +211,9 @@ def RegisterServer(
# Set default clsctx.
if not clsctx:
clsctx = pythoncom.CLSCTX_INPROC_SERVER | pythoncom.CLSCTX_LOCAL_SERVER
# And if we are frozen, ignore the ones that don't make sense in this
# context.
if pythoncom.frozen:
assert sys.frozen, (
"pythoncom is frozen, but sys.frozen is not set - don't know the context!"
)
if sys.frozen == "dll":
# And if we are frozen, ignore the ones that don't make sense in this context.
if __frozen:
if __frozen == "dll":
clsctx &= pythoncom.CLSCTX_INPROC_SERVER
else:
clsctx &= pythoncom.CLSCTX_LOCAL_SERVER
Expand All @@ -223,7 +223,7 @@ def RegisterServer(
# nod to Gordon's installer - if sys.frozen and sys.frozendllhandle
# exist, then we are being registered via a DLL - use this DLL as the
# file name.
if pythoncom.frozen:
if __frozen:
if hasattr(sys, "frozendllhandle"):
dllName = win32api.GetModuleFileName(sys.frozendllhandle)
else:
Expand Down Expand Up @@ -261,9 +261,8 @@ def RegisterServer(
_remove_key(keyNameRoot + "\\InprocServer32")

if clsctx & pythoncom.CLSCTX_LOCAL_SERVER:
if pythoncom.frozen:
# If we are frozen, we write "{exe} /Automate", just
# like "normal" .EXEs do
if __frozen:
# If we are frozen, we write "{exe} /Automate", just like "normal" .EXEs do
exeName = win32api.GetShortPathName(sys.executable)
command = f"{exeName} /Automate"
else:
Expand Down Expand Up @@ -302,7 +301,7 @@ def RegisterServer(
_remove_key(keyNameRoot + "\\PythonCOMPath")

if addPyComCat is None:
addPyComCat = pythoncom.frozen == 0
addPyComCat = __frozen == False
Copy link
Collaborator Author

@Avasam Avasam Apr 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would've done

Suggested change
addPyComCat = __frozen == False
addPyComCat = not __frozen

But since pythoncom.frozen = sys.frozen, and we see above that sys.frozen could be "dll". "dll" != 0.

I don't know if this was an oversight or intended behaviour, so I kept the current behaviour.

if addPyComCat:
catids = catids + [CATID_PythonCOMServer]

Expand Down Expand Up @@ -422,7 +421,7 @@ def RegisterClasses(*classes, **flags):
clsctx = _get(cls, "_reg_clsctx_")
tlb_filename = _get(cls, "_reg_typelib_filename_")
# default to being a COM category only when not frozen.
addPyComCat = not _get(cls, "_reg_disable_pycomcat_", pythoncom.frozen != 0)
addPyComCat = not _get(cls, "_reg_disable_pycomcat_", __frozen)
addnPath = None
if debugging:
# If the class has a debugging dispatcher specified, use it, otherwise
Expand Down Expand Up @@ -455,7 +454,7 @@ def RegisterClasses(*classes, **flags):

spec = moduleName + "." + cls.__name__
# Frozen apps don't need their directory on sys.path
if not pythoncom.frozen:
if not __frozen:
scriptDir = os.path.split(sys.argv[0])[0]
if not scriptDir:
scriptDir = "."
Expand Down Expand Up @@ -664,7 +663,7 @@ def RegisterPyComCategory():
regCat.RegisterCategories([(CATID_PythonCOMServer, 0x0409, "Python COM Server")])


if not pythoncom.frozen:
if not __frozen:
try:
win32api.RegQueryValue(
win32con.HKEY_CLASSES_ROOT,
Expand Down
8 changes: 4 additions & 4 deletions com/win32com/src/PythonCOM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2637,9 +2637,6 @@ PYWIN_MODULE_INIT_FUNC(pythoncom)

ADD_CONSTANT(DESCKIND_FUNCDESC);
ADD_CONSTANT(DESCKIND_VARDESC);
// Expose the frozen flag, as Python itself doesn't!!
// @prop int|frozen|1 if the host is a frozen program, else 0
AddConstant(dict, "frozen", Py_FrozenFlag);

// And finally some gross hacks relating to DCOM
// I'm really not sure what a better option is!
Expand Down Expand Up @@ -2678,7 +2675,10 @@ PYWIN_MODULE_INIT_FUNC(pythoncom)
// @prop int|dcom|1 if the system is DCOM aware, else 0. Only Win95 without DCOM extensions should return 0

// ### ALL THE @PROPERTY TAGS MUST COME AFTER THE LAST @PROP TAG!!
// @property int|pythoncom|frozen|1 if the host is a frozen program, else 0
// @property int|pythoncom|frozen|`pythoncom.frozen` used to expose `Py_FrozenFlag` from the C API.
// `Py_FrozenFlag` is deprecated since Python 3.12.
// Ever since pywin32 b200, loading the `win32com` module has silently been replacing `pythoncom.frozen` with
// `sys.frozen`. Use `getattr(sys, "frozen", False)` directly instead.
// @property int|pythoncom|dcom|1 if the system is DCOM aware, else 0. Only Win95 without DCOM extensions should
// return 0

Expand Down
4 changes: 1 addition & 3 deletions com/win32comext/mapi/src/exchangeguids.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
#define USES_IID_IExchangeFolderACLs

#ifndef BUILD_FREEZE
/* In a frozen environemnt, these are likely to be picked
up by the MAPI module */

// In a frozen environemnt, these are likely to be picked up by the MAPI module
#define USES_IID_IMsgStore
#define USES_IID_IMAPISession
#define USES_IID_IAttachment
Expand Down
2 changes: 1 addition & 1 deletion pycln.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ skip_imports = [
"IDLEenvironment", # Injects fast_readline into the IDLE auto-indent extension
"pythoncom", # pythoncomXX.dll loader
"pywintypes", # pywintypesXX.dll loader
"win32com", # Sets pythoncom.frozen and adds modules to path based on the registry
"win32com", # Adds modules to path based on the registry
"win32traceutil", # Redirects output to win32trace remote collector
"win32ui", # Must always be imported before dde
]
Expand Down