跳转到内容

模組:PythonScript/Librarys/StdLogics

维基百科,自由的百科全书
-- Module:PythonScript/Librarys/StdLogics
-- 1.typing
-- 2.contextlib
-- 3.difflib
-- 塞不下了。

local StdLogics = {}

-- ==========================================
-- 1. typing 模組 (型別提示與泛型支援)
-- ==========================================
function StdLogics.typing()
	local typing_helper = {
	    initialized = false,
	    cache = {}
	}
	
	function typing_helper.ensure_init()
	    if typing_helper.initialized then return end
	    typing_helper.initialized = true
	
	    local PyClass = require("Module:PythonScript/Class")
	    local Runtime = require("Module:PythonScript/Runtime")
	    local B = Runtime.builtins
	    local EvalUtils = require("Module:PythonScript/Evaluator/Utils")
	    local Evaluator = require("Module:PythonScript/Evaluator")
	
	    local C = typing_helper.cache
	
	    -- ==========================================
	    -- 1. 核心泛型別名 (GenericAlias)
	    -- ==========================================
	    local GenericAlias_dict = {
	        __init__ = { __type = "builtin_method", __call = function(a)
	            a[1].__dict.__origin__ = a[2]
	            a[1].__dict.__args__ = a[3]
	            a[1].__dict._is_typing = true
	            return B.None
	        end },
	        __repr__ = { __type = "builtin_method", __call = function(a)
	            local origin = a[1].__dict.__origin__
	            local args = a[1].__dict.__args__
	            local oname = (type(origin) == "table" and origin.__dict and origin.__dict._name) or
	                          (type(origin) == "table" and origin.__name) or tostring(origin)
	            
	            oname = string.gsub(oname, "^typing%.", "")
	            local p = {}
	            if type(args) == "table" and args.__type == "tuple" then
	                for _, v in ipairs(args.elements) do
	                    local v_name = (type(v) == "table" and v.__dict and v.__dict._name) or B.repr({v})
	                    table.insert(p, v_name)
	                end
	            else
	                local v_name = (type(args) == "table" and args.__dict and args.__dict._name) or B.repr({args})
	                table.insert(p, v_name)
	            end
	            return "typing." .. oname .. "[" .. table.concat(p, ", ") .. "]"
	        end },
	        __eq__ = { __type = "builtin_method", __call = function(a)
	            local self, other = a[1], a[2]
	            if type(other) == "table" and other.__class == C._GenericAlias then
	                return EvalUtils.py_eq(self.__dict.__origin__, other.__dict.__origin__) and
	                       EvalUtils.py_eq(self.__dict.__args__, other.__dict.__args__)
	            end
	            return false
	        end },
	        __hash__ = { __type = "builtin_method", __call = function(a)
	            return B.hash({ a[1].__dict.__origin__ })
	        end },
	        __call__ = { __type = "builtin_method", __call = function(a, kw)
	            local origin = a[1].__dict.__origin__
	            local call_args = {}
	            for i = 2, #a do call_args[#call_args + 1] = a[i] end
	            if type(origin) == "table" then
	                if origin.__type == "class" then
	                    return Evaluator.invoke(origin, call_args, kw)
	                elseif origin.__dict and origin.__dict._name then
	                    local map = { List = B.list, Dict = B.dict, Tuple = B.tuple, Set = B.set, FrozenSet = B.frozenset }
	                    local target = map[origin.__dict._name]
	                    if target then return Evaluator.invoke(target, call_args, kw) end
	                end
	            end
	            return B.NotImplemented
	        end }
	    }
	    C._GenericAlias = PyClass.make_class("_GenericAlias", {}, GenericAlias_dict)
	    C._GenericAlias.__dict["__module__"] = "typing"
	
	    -- ==========================================
	    -- 2. 特殊標記物件 (_SpecialForm)
	    -- ==========================================
	    local SpecialForm_dict = {
	        __init__ = { __type = "builtin_method", __call = function(a)
	            a[1].__dict._name = a[2]
	            a[1].__dict._is_typing = true
	            return B.None
	        end },
	        __repr__ = { __type = "builtin_method", __call = function(a)
	            return "typing." .. a[1].__dict._name
	        end },
	        -- 【修復核心】:__getitem__ 必須放在類別上,並委派給實例自定義的函式
	        __getitem__ = { __type = "builtin_method", __call = function(a)
	            local self, slice = a[1], a[2]
	            local getitem_fn = self.__dict._getitem_fn
	            if getitem_fn then return getitem_fn(self, slice) end
	            Runtime.raise("TypeError", self.__dict._name .. " is not subscriptable")
	        end }
	    }
	    C._SpecialForm = PyClass.make_class("_SpecialForm", {}, SpecialForm_dict)
	    C._SpecialForm.__dict["__module__"] = "typing"
	
	    local function default_alias_getitem(self, slice)
	        local inst = PyClass.make_instance(C._GenericAlias)
	        inst.__dict.__origin__ = self
	        inst.__dict.__args__ = slice
	        inst.__dict._is_typing = true
	        return inst
	    end
	
	    local function make_special_form(name, getitem_fn)
	        local inst = PyClass.make_instance(C._SpecialForm)
	        inst.__dict._name = name
	        inst.__dict._is_typing = true
	        if getitem_fn then
	            inst.__dict._getitem_fn = getitem_fn
	        end
	        return inst
	    end
	
	    C.Any = make_special_form("Any")
	    C.Any.__dict._is_any = true
	    C.NoReturn = make_special_form("NoReturn")
	    C.Never = make_special_form("Never")
	    C.Self = make_special_form("Self")
	
	    C.Literal = make_special_form("Literal", default_alias_getitem)
	    C.ClassVar = make_special_form("ClassVar", default_alias_getitem)
	    C.Final = make_special_form("Final", default_alias_getitem)
	    C.Annotated = make_special_form("Annotated", default_alias_getitem)
	    C.Callable = make_special_form("Callable", default_alias_getitem)
	    C.TypeGuard = make_special_form("TypeGuard", default_alias_getitem)
	    C.TypeIs = make_special_form("TypeIs", default_alias_getitem)

		local common_aliases = {
	        "List", "Dict", "Tuple", "Set", "FrozenSet", "Type",
	        "Iterable", "Iterator", "Generator", "Sequence", "Mapping",
	        "AbstractSet", "MutableSet", "MutableMapping", "MutableSequence",
	        "Coroutine", "AsyncGenerator", "AsyncIterable", "AsyncIterator", "Awaitable",
	        "Hashable", "Sized", "Container", "Collection", "Reversible",
	        "ContextManager", "AsyncContextManager",
	        "Text", "ByteString", "Match", "Pattern", "ForwardRef",
	        "OrderedDict", "ChainMap", "Counter", "Deque"
	    }
	    for _, name in ipairs(common_aliases) do
	        C[name] = make_special_form(name, default_alias_getitem)
	    end
		
	    C.Union = make_special_form("Union", function(self, slice)
	        local items = {}
	        if type(slice) == "table" and slice.__type == "tuple" then items = slice.elements
	        else items = {slice} end
	        return EvalUtils.make_union_type(items)
	    end)
	
	    C.Optional = make_special_form("Optional", function(self, slice)
	        return EvalUtils.make_union_type({slice, B.NoneType})
	    end)
	
	    -- ==========================================
	    -- 3. TypeVar 家族
	    -- ==========================================
	    local function make_type_var(cls_name)
	        local dict = {
	            __init__ = { __type = "builtin_method", __call = function(a, kw)
	                a[1].__dict.__name__ = a[2]
	                a[1].__dict._is_typing = true
	                a[1].__dict.__covariant__ = kw and kw.covariant or false
	                a[1].__dict.__contravariant__ = kw and kw.contravariant or false
	                return B.None
	            end },
	            __repr__ = { __type = "builtin_method", __call = function(a)
	                local d = a[1].__dict
	                local p = ""
	                if d.__covariant__ then p = "+" elseif d.__contravariant__ then p = "-" end
	                return "~" .. p .. d.__name__
	            end }
	        }
	        local cls = PyClass.make_class(cls_name, {}, dict)
	        cls.__dict["__module__"] = "typing"
	        return cls
	    end
	
	    C.TypeVar = make_type_var("TypeVar")
	    C.ParamSpec = make_type_var("ParamSpec")
	    C.TypeVarTuple = make_type_var("TypeVarTuple")
	
	    -- ==========================================
	    -- 4. Generic 與 Protocol 基底類別
	    -- ==========================================
	    local Generic_dict = {
	        __class_getitem__ = { __type = "classmethod", __func = { __type = "builtin_method", __call = function(a)
	            local inst = PyClass.make_instance(C._GenericAlias)
	            inst.__dict.__origin__ = a[1]
	            inst.__dict.__args__ = a[2]
	            inst.__dict._is_typing = true
	            return inst
	        end } }
	    }
	    C.Generic = PyClass.make_class("Generic", {}, Generic_dict)
	    C.Generic.__dict["__module__"] = "typing"
	
	    C.Protocol = PyClass.make_class("Protocol", { C.Generic }, {})
	    C.Protocol.__dict["__module__"] = "typing"
	
	    -- ==========================================
	    -- 5. Type Hint 工廠函式 (NewType, cast)
	    -- ==========================================
	    C.cast = { __type = "builtin_method", __name = "cast", __call = function(a)
	        -- 【修復】:非 bound method 參數從 a[1] 開始
	        return a[2] 
	    end }
	
	    C.NewType = { __type = "builtin_method", __name = "NewType", __call = function(a)
	        local name = a[1] or "NewType"
	        local tp = a[2]
	        local nt = { __type = "builtin_method", __name = name, __call = function(args) return args[1] end }
	        nt.__dict = { __name__ = name, __supertype__ = tp, _is_typing = true }
	        return nt
	    end }
	
	    -- ==========================================
	    -- 6. 動態資料類別工廠 (NamedTuple, TypedDict)
	    -- ==========================================
		local NamedTuple_dict = {
	        __new__ = { __type = "builtin_method", __call = function(a, kw)
	            local cls = a[1]
	            -- 模式一:函式呼叫工廠 NamedTuple("Point", [("x", int)])
	            if cls == C.NamedTuple and #a >= 2 and type(a[2]) == "string" then
	                local typename = a[2]
	                local fields = a[3]
	                local col_mod = require("Module:PythonScript/Librarys").get_module("collections")
	                local nt_fn = PyClass.get_attr(col_mod, "namedtuple")
	                
	                local field_names = {}
	                local ann_pairs = {}
	                if type(fields) == "table" and (fields.__type == "list" or fields.__type == "tuple") then
	                    for _, f in ipairs(fields.elements) do
	                        if type(f) == "table" and f.__type == "tuple" and #f.elements >= 2 then
	                            table.insert(field_names, f.elements[1])
	                            table.insert(ann_pairs, {key = f.elements[1], value = f.elements[2]})
	                        else
	                            table.insert(field_names, f)
	                        end
	                    end
	                end
	                local new_cls = Evaluator.invoke(nt_fn, {typename, {__type="list", elements=field_names}}, {})
	                new_cls.__dict["__annotations__"] = {__type="dict", pairs=ann_pairs}
	                return new_cls
	            end

	            -- 模式二:類別繼承 class Point(NamedTuple): ...
	            if cls ~= C.NamedTuple then
	                if not cls.__dict._nt_class then
	                    local ann = cls.__dict["__annotations__"]
	                    local keys = {}
	                    if ann and type(ann) == "table" and ann.__type == "dict" then
	                        for _, p in ipairs(ann.pairs) do table.insert(keys, p.key) end
	                    end
	                    local col_mod = require("Module:PythonScript/Librarys").get_module("collections")
	                    local nt_fn = PyClass.get_attr(col_mod, "namedtuple")
	                    local list_keys = {__type="list", elements=keys}
	                    cls.__dict._nt_class = Evaluator.invoke(nt_fn, {cls.__name, list_keys}, {})
	                    table.insert(cls.__dict._nt_class.__mro, cls)
	                end
	                
	                local nt_args = {}
	                for i = 2, #a do table.insert(nt_args, a[i]) end
	                local inst = Evaluator.invoke(cls.__dict._nt_class, nt_args, kw)
	
	                if type(inst) == "table" and inst.__type == "instance" then
	                    local elts = {}
	                    local ann = cls.__dict["__annotations__"]
	                    if ann and type(ann) == "table" and ann.__type == "dict" then
	                        for _, p in ipairs(ann.pairs) do
	                            table.insert(elts, require("Module:PythonScript/Class").get_attr(inst, p.key))
	                        end
	                    end
	                    inst.__builtin_value = { __type = "tuple", elements = elts }
	                end
	                return inst
	            end
	            
	            return B.NotImplemented
	        end }
	    }
		
	    C.NamedTuple = PyClass.make_class("NamedTuple", { B.object }, NamedTuple_dict)
    	C.NamedTuple.__dict["__module__"] = "typing"

		local TypedDict_dict = {
	        __new__ = { __type = "builtin_method", __call = function(a, kw)
	            local cls = a[1]
	            -- 模式一:函式呼叫工廠 TypedDict("User", {"name": str})
	            if cls == C.TypedDict and #a >= 2 and type(a[2]) == "string" then
	                local typename = a[2]
	                local fields = a[3]
	                local new_cls = PyClass.make_class(typename, { C.TypedDict }, {})
	                new_cls.__dict["__module__"] = "typing"
	                local ann_pairs = {}
	                if type(fields) == "table" and fields.__type == "dict" then
	                    for _, p in ipairs(fields.pairs) do
	                        table.insert(ann_pairs, {key = p.key, value = p.value})
	                    end
	                end
	                new_cls.__dict["__annotations__"] = {__type="dict", pairs=ann_pairs}
	                return new_cls
	            end
	            
	            -- 模式二:類別繼承 class HTTPResponse(TypedDict): ...
	            -- 執行個體化時,依照 CPython 規範,直接回傳純種 dict 實體!
	            local dict_args = {}
	            for i = 2, #a do table.insert(dict_args, a[i]) end
	            return B.dict.__call(dict_args, kw)
	        end }
	    }
		
		C.TypedDict = PyClass.make_class("TypedDict", { B.dict }, TypedDict_dict)
		C.TypedDict.__dict["__module__"] = "typing"
	end
	
	function typing_helper.get_module()
	    typing_helper.ensure_init()
	    local PyClass = require("Module:PythonScript/Class")
	    local Runtime = require("Module:PythonScript/Runtime")
	    
	    local mod_dict = {
	        __getattr__ = {
	            __type = "builtin_method",
	            __call = function(args)
	                local self, attr = args[1], args[2]
	                local val = typing_helper.cache[attr]
	                if val ~= nil then
	                    self.__dict[attr] = val
	                    return val
	                end
	                Runtime.raise("AttributeError", "module 'typing' has no attribute '" .. tostring(attr) .. "'")
	            end
	        }
	    }
	    local mod = PyClass.make_instance(PyClass.make_class("module", {}, mod_dict))
	    mod.__dict["__name__"] = "typing"
	    mod.__dict["__all__"] = {
	        __type = "list",
	        elements = {
"Any", "Literal", "Self", "NoReturn", "Never", "ClassVar", "Final", 
            "Annotated", "Union", "Optional", "TypeVar", "Generic", "ParamSpec", 
            "TypeVarTuple", "Protocol", "TypedDict", "NamedTuple", "Callable", 
            "TypeGuard", "TypeIs", "NewType", "cast",
            "List", "Dict", "Tuple", "Set", "FrozenSet", "Type",
            "Iterable", "Iterator", "Generator", "Sequence", "Mapping",
            "AbstractSet", "MutableSet", "MutableMapping", "MutableSequence",
            "Coroutine", "AsyncGenerator", "AsyncIterable", "AsyncIterator", "Awaitable",
            "Hashable", "Sized", "Container", "Collection", "Reversible",
            "ContextManager", "AsyncContextManager",
            "Text", "ByteString", "Match", "Pattern", "ForwardRef",
            "OrderedDict", "ChainMap", "Counter", "Deque"
	        }
	    }
	    return mod
	end
	return typing_helper
end

-- ==========================================
-- 2. contextlib 模組
-- ==========================================
function StdLogics.contextlib()
	local contextlib_helper = {
	    initialized = false,
	    cache = {}
	}
	
	function contextlib_helper.is_none(v)
	    return v == nil or (type(v) == "table" and v.__class and v.__class.__name == "NoneType")
	end
	
	function contextlib_helper.ensure_init()
	    if contextlib_helper.initialized then return end
	    contextlib_helper.initialized = true
	
	    local PyClass = require("Module:PythonScript/Class")
	    local Runtime = require("Module:PythonScript/Runtime")
	    local B = Runtime.builtins
	    local Evaluator = require("Module:PythonScript/Evaluator")
	    local C = contextlib_helper.cache
	
	    -- 輔助:在 with 語句外手動執行 context manager 完整生命週期
	    local function run_with_cm(cm, body_fn)
	        local enter_m = PyClass.get_attr(cm, "__enter__")
	        local exit_m = PyClass.get_attr(cm, "__exit__")
	        Evaluator.invoke(enter_m, {}, {})
	
	        local prev_stack_len = #Runtime.Traceback.stack
	        local prev_depth = Runtime.Traceback.eval_depth
	        local prev_file_idx = Runtime.Traceback.current_file_idx
	        local prev_func_name = Runtime.Traceback.current_func_name
	
	        local ok, res = pcall(body_fn)
	        Runtime.Traceback.eval_depth = prev_depth
	
	        if ok then
	            Evaluator.invoke(exit_m, { B.None, B.None, B.None }, {})
	            return res
	        else
	            while #Runtime.Traceback.stack > prev_stack_len do table.remove(Runtime.Traceback.stack) end
	            Runtime.Traceback.current_file_idx = prev_file_idx
	            Runtime.Traceback.current_func_name = prev_func_name
	
	            local exc_type = (type(res) == "table" and res.__class) or B.Exception
	            local tb = (type(res) == "table" and res.__dict and res.__dict.__traceback_info__) or B.None
	            local suppress = Evaluator.invoke(exit_m, { exc_type, res, tb }, {})
	            if B.bool.__call({suppress}) then
	                return B.None
	            end
	            error(res, 0)
	        end
	    end
	
	    -- ==========================================
	    -- 1. AbstractContextManager & ContextDecorator
	    -- ==========================================
	    C.AbstractContextManager = PyClass.make_class("AbstractContextManager", {}, {
	        __enter__ = { __type = "builtin_method", __name = "__enter__", __call = function(a) return a[1] end },
	        __exit__ = { __type = "builtin_method", __name = "__exit__", __call = function() return B.None end }
	    })
	    C.AbstractContextManager.__dict["__module__"] = "contextlib"
	
	    C.AbstractAsyncContextManager = PyClass.make_class("AbstractAsyncContextManager", {}, {
	        __aenter__ = { __type = "builtin_method", __name = "__aenter__", __call = function(a) return a[1] end },
	        __aexit__ = { __type = "builtin_method", __name = "__aexit__", __call = function() return B.None end }
	    })
	    C.AbstractAsyncContextManager.__dict["__module__"] = "contextlib"
	
	    C.ContextDecorator = PyClass.make_class("ContextDecorator", {}, {
	        _recreate_cm = { __type = "builtin_method", __name = "_recreate_cm", __call = function(a) return a[1] end },
	        __call__ = { __type = "builtin_method", __name = "__call__", __call = function(a)
	            local self, func = a[1], a[2]
	            local wrapper = {
	                __type = "builtin_method",
	                __name = (type(func) == "table" and (func.__name or func.__qualname__)) or "<wrapped>",
	                __dict = { __wrapped__ = func },
	                __call = function(f_args, f_kwargs)
	                    local rec_m = PyClass.get_attr(self, "_recreate_cm")
	                    local cm = Evaluator.invoke(rec_m, {}, {})
	                    return run_with_cm(cm, function()
	                        return Evaluator.invoke(func, f_args, f_kwargs)
	                    end)
	                end
	            }
	            return wrapper
	        end }
	    })
	    C.ContextDecorator.__dict["__module__"] = "contextlib"
	
	    -- ==========================================
	    -- 2. @contextmanager & @asynccontextmanager
	    -- ==========================================
	    local gcm_dict = {
	        __init__ = { __type = "builtin_method", __call = function(a)
	            local self = a[1]
	            self.__dict._func = a[2]
	            self.__dict._args = a[3] or {}
	            self.__dict._kwds = a[4] or {}
	            self.__dict.gen = nil
	            return nil
	        end },
	        _recreate_cm = { __type = "builtin_method", __call = function(a)
	            local d = a[1].__dict
	            local copy = PyClass.make_instance(a[1].__class)
	            copy.__dict._func = d._func
	            copy.__dict._args = d._args
	            copy.__dict._kwds = d._kwds
	            return copy
	        end },
	        __enter__ = { __type = "builtin_method", __call = function(a)
	            local self = a[1]
	            local d = self.__dict
	            d.gen = Evaluator.invoke(d._func, d._args, d._kwds)
	            local ok, res = pcall(B.next, { d.gen })
	            if not ok then
	                if type(res) == "table" and res.__class and res.__class.__name == "StopIteration" then
	                    Runtime.raise("RuntimeError", "generator didn't yield")
	                end
	                error(res, 0)
	            end
	            return res
	        end },
	        __exit__ = { __type = "builtin_method", __call = function(a)
	            local self, typ, val, tb = a[1], a[2], a[3], a[4]
	            local gen = self.__dict.gen
	            if not gen then return false end
	
	            if contextlib_helper.is_none(typ) then
	                local ok, res = pcall(B.next, { gen })
	                if not ok then
	                    if type(res) == "table" and res.__class and res.__class.__name == "StopIteration" then
	                        return false
	                    end
	                    error(res, 0)
	                end
	                Runtime.raise("RuntimeError", "generator didn't stop")
	            else
	                if contextlib_helper.is_none(val) then
	                    val = (type(typ) == "table" and typ.__type == "class") and Evaluator.invoke(typ, {}, {}) or typ
	                end
	                local has_throw, throw_m = pcall(PyClass.get_attr, gen, "throw")
	                if has_throw and throw_m then
	                    local ok, res = pcall(Evaluator.invoke, throw_m, { typ, val, tb }, {})
	                    if not ok then
	                        if type(res) == "table" and res.__class and res.__class.__name == "StopIteration" then
	                            return true
	                        end
	                        if res == val then return false end
	                        error(res, 0)
	                    end
	                    Runtime.raise("RuntimeError", "generator didn't stop after throw()")
	                end
	                if gen.__dict then gen.__dict.is_finished = true end
	                return false
	            end
	        end }
	    }
	    gcm_dict.__aenter__ = gcm_dict.__enter__
	    gcm_dict.__aexit__ = gcm_dict.__exit__
	
	    local GeneratorContextManager = PyClass.make_class("_GeneratorContextManager", { C.ContextDecorator, C.AbstractContextManager }, gcm_dict)
	    GeneratorContextManager.__dict["__module__"] = "contextlib"
	
	    C.contextmanager = {
	        __type = "builtin_method", __name = "contextmanager",
	        __call = function(a)
	            local func = a and a[1]
	            if not func then Runtime.raise("TypeError", "contextmanager() missing required argument 'func'") end
	            return {
	                __type = "builtin_method",
	                __name = (type(func) == "table" and (func.__name or func.__qualname__)) or "<contextmanager>",
	                __dict = { __wrapped__ = func },
	                __call = function(f_args, f_kwargs)
	                    local inst = PyClass.make_instance(GeneratorContextManager)
	                    inst.__dict._func = func
	                    inst.__dict._args = f_args or {}
	                    inst.__dict._kwds = f_kwargs or {}
	                    return inst
	                end
	            }
	        end
	    }
	    C.asynccontextmanager = C.contextmanager
	
	    -- ==========================================
	    -- 3. suppress, nullcontext, closing, aclosing
	    -- ==========================================
	    local suppress_dict = {
	        __init__ = { __type = "builtin_method", __call = function(a)
	            local self = a[1]
	            local excs = {}
	            for i = 2, #a do excs[#excs + 1] = a[i] end
	            self.__dict._exceptions = excs
	            return nil
	        end },
	        __enter__ = { __type = "builtin_method", __call = function() return B.None end },
	        __exit__ = { __type = "builtin_method", __call = function(a)
	            local self, exctype, excinst = a[1], a[2], a[3]
	            if contextlib_helper.is_none(exctype) then return false end
	            for _, target in ipairs(self.__dict._exceptions) do
	                if PyClass.is_subclass(exctype, target) or (not contextlib_helper.is_none(excinst) and PyClass.is_instance(excinst, target)) then
	                    return true
	                end
	            end
	            return false
	        end }
	    }
	    C.suppress = PyClass.make_class("suppress", { C.AbstractContextManager }, suppress_dict)
	    C.suppress.__dict["__module__"] = "contextlib"
	
	    local nullcontext_dict = {
	        __init__ = { __type = "builtin_method", __call = function(a, kw)
	            local self = a[1]
	            local er = B.None
	            if #a >= 2 then er = a[2]
	            elseif kw and kw.enter_result ~= nil then er = kw.enter_result end
	            self.__dict.enter_result = er
	            return nil
	        end },
	        __enter__ = { __type = "builtin_method", __call = function(a) return a[1].__dict.enter_result end },
	        __exit__ = { __type = "builtin_method", __call = function() return false end }
	    }
	    nullcontext_dict.__aenter__ = nullcontext_dict.__enter__
	    nullcontext_dict.__aexit__ = nullcontext_dict.__exit__
	    C.nullcontext = PyClass.make_class("nullcontext", { C.AbstractContextManager }, nullcontext_dict)
	    C.nullcontext.__dict["__module__"] = "contextlib"
	
	    local closing_dict = {
	        __init__ = { __type = "builtin_method", __call = function(a)
	            if #a < 2 then Runtime.raise("TypeError", "closing() missing required argument 'thing'") end
	            a[1].__dict.thing = a[2]
	            return nil
	        end },
	        __enter__ = { __type = "builtin_method", __call = function(a) return a[1].__dict.thing end },
	        __exit__ = { __type = "builtin_method", __call = function(a)
	            local close_m = PyClass.get_attr(a[1].__dict.thing, "close")
	            Evaluator.invoke(close_m, {}, {})
	            return false
	        end }
	    }
	    closing_dict.__aenter__ = closing_dict.__enter__
	    closing_dict.__aexit__ = { __type = "builtin_method", __call = function(a)
	        local thing = a[1].__dict.thing
	        local ok, aclose_m = pcall(PyClass.get_attr, thing, "aclose")
	        if ok and aclose_m then Evaluator.invoke(aclose_m, {}, {})
	        else Evaluator.invoke(PyClass.get_attr(thing, "close"), {}, {}) end
	        return false
	    end }
	    C.closing = PyClass.make_class("closing", { C.AbstractContextManager }, closing_dict)
	    C.closing.__dict["__module__"] = "contextlib"
	    C.aclosing = PyClass.make_class("aclosing", { C.AbstractAsyncContextManager }, closing_dict)
	    C.aclosing.__dict["__module__"] = "contextlib"
	
	    -- ==========================================
	    -- 4. redirect_stdout & redirect_stderr
	    -- ==========================================
	    local function make_redirect_class(cls_name, stream_attr, intercept_print)
	        local r_dict = {
	            __init__ = { __type = "builtin_method", __call = function(a)
	                a[1].__dict._new_target = a[2]
	                a[1].__dict._old_targets = {}
	                return nil
	            end },
	            __enter__ = { __type = "builtin_method", __call = function(a)
	                local self = a[1]
	                local target = self.__dict._new_target
	                local Sys = require("Module:PythonScript/Librarys/Argparse").Sys
	                local sys_mod = Sys.modules_registry["sys"] or Sys.get_module()
	                Sys.modules_registry["sys"] = sys_mod
	
	                local old_stream = PyClass.get_attr(sys_mod, stream_attr)
	                local old_print = B.print
	                table.insert(self.__dict._old_targets, { stream = old_stream, print_fn = old_print })
	                PyClass.set_attr(sys_mod, stream_attr, target)
	
	                if intercept_print then
	                    B.print = function(p_args, p_kwargs)
	                        local file_arg = p_kwargs and p_kwargs.file
	                        local active_out = (not contextlib_helper.is_none(file_arg)) and file_arg or target
	                        if contextlib_helper.is_none(active_out) then
	                            return B.None
	                        end
	                        local sep = " "
	                        if p_kwargs and not contextlib_helper.is_none(p_kwargs.sep) then
	                            if type(p_kwargs.sep) ~= "string" then Runtime.raise("TypeError", "sep must be None or a string") end
	                            sep = p_kwargs.sep
	                        end
	                        local end_str = "\n"
	                        local raw_end = p_kwargs and (p_kwargs["end"] ~= nil and p_kwargs["end"] or p_kwargs.end_)
	                        if not contextlib_helper.is_none(raw_end) then
	                            if type(raw_end) ~= "string" then Runtime.raise("TypeError", "end must be None or a string") end
	                            end_str = raw_end
	                        end
	                        local parts = {}
	                        for i, v in ipairs(p_args or {}) do parts[i] = B.str.__call({v}) end
	                        local out_str = table.concat(parts, sep) .. end_str
	                        local write_m = PyClass.get_attr(active_out, "write")
	                        Evaluator.invoke(write_m, { out_str }, {})
	                        return B.None
	                    end
	                end
	                return target
	            end },
	            __exit__ = { __type = "builtin_method", __call = function(a)
	                local self = a[1]
	                local saved = table.remove(self.__dict._old_targets)
	                if saved then
	                    local Sys = require("Module:PythonScript/Librarys/Argparse").Sys
	                    local sys_mod = Sys.modules_registry["sys"]
	                    if sys_mod then PyClass.set_attr(sys_mod, stream_attr, saved.stream) end
	                    if intercept_print then B.print = saved.print_fn end
	                end
	                return false
	            end }
	        }
	        local cls = PyClass.make_class(cls_name, { C.AbstractContextManager }, r_dict)
	        cls.__dict["__module__"] = "contextlib"
	        return cls
	    end
	
	    C.redirect_stdout = make_redirect_class("redirect_stdout", "stdout", true)
	    C.redirect_stderr = make_redirect_class("redirect_stderr", "stderr", false)
	
	    -- ==========================================
	    -- 5. ExitStack 動態上下文堆疊
	    -- ==========================================
	    local exit_stack_dict
	    exit_stack_dict = {
	        __init__ = { __type = "builtin_method", __call = function(a)
	            a[1].__dict._exit_callbacks = {}
	            return nil
	        end },
	        __enter__ = { __type = "builtin_method", __call = function(a) return a[1] end },
	        enter_context = { __type = "builtin_method", __call = function(a)
	            local self, cm = a[1], a[2]
	            local enter_m = PyClass.get_attr(cm, "__enter__")
	            local exit_m = PyClass.get_attr(cm, "__exit__")
	            local res = Evaluator.invoke(enter_m, {}, {})
	            table.insert(self.__dict._exit_callbacks, { is_sync = true, fn = exit_m })
	            return res
	        end },
	        push = { __type = "builtin_method", __call = function(a)
	            local self, exit_obj = a[1], a[2]
	            local ok, exit_m = pcall(PyClass.get_attr, exit_obj, "__exit__")
	            if ok and exit_m and type(exit_obj) == "table" and (exit_obj.__type == "instance" or exit_obj.__type == "class") then
	                table.insert(self.__dict._exit_callbacks, { is_sync = true, fn = exit_m })
	            else
	                table.insert(self.__dict._exit_callbacks, { is_sync = true, fn = exit_obj })
	            end
	            return exit_obj
	        end },
	        callback = { __type = "builtin_method", __call = function(a, kw)
	            local self, cb = a[1], a[2]
	            if not cb then Runtime.raise("TypeError", "callback() missing required argument 'callback'") end
	            local cb_args = {}
	            for i = 3, #a do cb_args[#cb_args + 1] = a[i] end
	            local cb_kw = {}
	            for k, v in pairs(kw or {}) do cb_kw[k] = v end
	            table.insert(self.__dict._exit_callbacks, { is_cb = true, fn = cb, args = cb_args, kw = cb_kw })
	            return cb
	        end },
	        pop_all = { __type = "builtin_method", __call = function(a)
	            local self = a[1]
	            local new_stack = PyClass.make_instance(self.__class)
	            new_stack.__dict._exit_callbacks = self.__dict._exit_callbacks
	            self.__dict._exit_callbacks = {}
	            return new_stack
	        end },
	        close = { __type = "builtin_method", __call = function(a)
	            exit_stack_dict.__exit__.__call({ a[1], B.None, B.None, B.None })
	            return B.None
	        end },
	        __exit__ = { __type = "builtin_method", __call = function(a)
	            local self = a[1]
	            local cur_type = a[2] or B.None
	            local cur_val = a[3] or B.None
	            local cur_tb = a[4] or B.None
	            local has_exc = not contextlib_helper.is_none(cur_type)
	            local suppressed = false
	
	            local callbacks = self.__dict._exit_callbacks
	            self.__dict._exit_callbacks = {}
	
	            for i = #callbacks, 1, -1 do
	                local item = callbacks[i]
	                local prev_stack_len = #Runtime.Traceback.stack
	                local prev_depth = Runtime.Traceback.eval_depth
	                local prev_file_idx = Runtime.Traceback.current_file_idx
	                local prev_func_name = Runtime.Traceback.current_func_name
	
	                local ok, res = pcall(function()
	                    if item.is_cb then
	                        Evaluator.invoke(item.fn, item.args, item.kw)
	                        return false
	                    else
	                        return Evaluator.invoke(item.fn, { cur_type, cur_val, cur_tb }, {})
	                    end
	                end)
	                Runtime.Traceback.eval_depth = prev_depth
	
	                if ok then
	                    if has_exc and B.bool.__call({res}) then
	                        suppressed = true
	                        has_exc = false
	                        cur_type, cur_val, cur_tb = B.None, B.None, B.None
	                    end
	                else
	                    while #Runtime.Traceback.stack > prev_stack_len do table.remove(Runtime.Traceback.stack) end
	                    Runtime.Traceback.current_file_idx = prev_file_idx
	                    Runtime.Traceback.current_func_name = prev_func_name
	                    if has_exc and type(res) == "table" and res.__dict and res ~= cur_val then
	                        res.__dict.__context__ = cur_val
	                    end
	                    has_exc = true
	                    suppressed = false
	                    cur_val = res
	                    cur_type = (type(res) == "table" and res.__class) or B.Exception
	                    cur_tb = (type(res) == "table" and res.__dict and res.__dict.__traceback_info__) or B.None
	                end
	            end
	
	            if has_exc then
	                if cur_val ~= a[3] then error(cur_val, 0) end
	                return false
	            end
	            return suppressed
	        end }
	    }
	    C.ExitStack = PyClass.make_class("ExitStack", { C.AbstractContextManager }, exit_stack_dict)
	    C.ExitStack.__dict["__module__"] = "contextlib"
	    C.AsyncExitStack = C.ExitStack
	end
	
	function contextlib_helper.get_module()
	    local PyClass = require("Module:PythonScript/Class")
	    local Runtime = require("Module:PythonScript/Runtime")
	
	    local mod_dict = {
	        __getattr__ = {
	            __type = "builtin_method",
	            __call = function(args)
	                local self, attr = args[1], args[2]
	                contextlib_helper.ensure_init()
	                local val = contextlib_helper.cache[attr]
	                if val ~= nil then
	                    self.__dict[attr] = val
	                    return val
	                end
	                Runtime.raise("AttributeError", "module 'contextlib' has no attribute '" .. tostring(attr) .. "'")
	            end
	        }
	    }
	    local mod = PyClass.make_instance(PyClass.make_class("module", {}, mod_dict))
	    mod.__dict["__name__"] = "contextlib"
	    mod.__dict["__all__"] = {
	        __type = "list",
	        elements = {
	            "asynccontextmanager", "contextmanager", "closing", "aclosing",
	            "nullcontext", "AbstractContextManager", "AbstractAsyncContextManager",
	            "AsyncExitStack", "ContextDecorator", "ExitStack",
	            "redirect_stdout", "redirect_stderr", "suppress"
	        }
	    }
	    return mod
	end
	return contextlib_helper
end

-- ==========================================
-- 3. difflib 模組
-- ==========================================
function StdLogics.difflib()
	local difflib_helper = {
	    initialized = false,
	    cache = {}
	}
	
	-- ==========================================
	-- 1. 基礎型別、序列拆解與雜湊鍵輔助函式
	-- ==========================================
	function difflib_helper.is_none(v)
	    return v == nil or (type(v) == "table" and v.__class and v.__class.__name == "NoneType")
	end
	
	function difflib_helper.to_bool(v)
	    return require("Module:PythonScript/Runtime").builtins.bool.__call({v})
	end
	
	function difflib_helper.call_junk(fn, elem)
	    if difflib_helper.is_none(fn) or fn == false then return false end
	    local Evaluator = require("Module:PythonScript/Evaluator")
	    return difflib_helper.to_bool(Evaluator.invoke(fn, {elem}, {}))
	end
	
	-- 將可雜湊之 Python 物件轉為 Lua table 索引鍵 (供 b2j 字典高速查找與相等比對)
	function difflib_helper.make_key(val)
	    local t = type(val)
	    if t == "string" or t == "number" or t == "boolean" then return val end
	    if t == "table" then
	        if val.__class and val.__class.__name == "NoneType" then
	            return "N:None"
	        elseif val.__type == "int" and val.is_big then
	            local MathCore = require("Module:PythonScript/Runtime/Cmath")
	            return "I:" .. MathCore.BigInt.to_string(val.sign, val.limbs)
	        elseif val.__type == "bytes" or val.__type == "bytearray" or val.__type == "memoryview" then
	            return "B:" .. tostring(val._data)
	        elseif val.__type == "tuple" then
	            local parts = {}
	            for i = 1, #val.elements do
	                parts[i] = tostring(difflib_helper.make_key(val.elements[i]))
	            end
	            return "T:(" .. table.concat(parts, ",") .. ")"
	        elseif val.__type == "frozenset" then
	            local parts = {}
	            for i = 1, #val.elements do
	                parts[i] = tostring(difflib_helper.make_key(val.elements[i]))
	            end
	            table.sort(parts)
	            return "FS:{" .. table.concat(parts, ",") .. "}"
	        elseif val.__type == "instance" then
	            local PyClass = require("Module:PythonScript/Class")
	            -- 1. 針對 @dataclass 實例:直接提取 compare=True 的欄位生成結構鍵
	            if val.__class and val.__class.__dict and val.__class.__dict["__dataclass_fields__"] then
	                local f_dict = val.__class.__dict["__dataclass_fields__"]
	                local parts = {}
	                for _, p in ipairs(f_dict.pairs) do
	                    local f = p.value
	                    if f.__dict.compare then
	                        local ok, fv = pcall(PyClass.get_attr, val, p.key)
	                        parts[#parts + 1] = tostring(p.key) .. "=" .. tostring(difflib_helper.make_key(ok and fv or nil))
	                    end
	                end
	                return "DC:" .. tostring(val.__class.__name) .. "(" .. table.concat(parts, ",") .. ")"
	            end
	            -- 2. 針對其他自定義實例 (Fraction, Decimal, NamedTuple 等)
	            local B = require("Module:PythonScript/Runtime").builtins
	            local ok_r, r = pcall(B.repr, {val})
	            if ok_r and type(r) == "string" and not r:match("^<") then
	                return "R:" .. tostring(val.__class and val.__class.__name or "inst") .. ":" .. r
	            end
	            if val.__dict then
	                local keys = {}
	                for k in pairs(val.__dict) do
	                    if type(k) == "string" and not k:match("^__") then keys[#keys + 1] = k end
	                end
	                table.sort(keys)
	                local parts = {}
	                for _, k in ipairs(keys) do
	                    parts[#parts + 1] = k .. "=" .. tostring(difflib_helper.make_key(val.__dict[k]))
	                end
	                return "INST:" .. tostring(val.__class and val.__class.__name or "inst") .. "(" .. table.concat(parts, ",") .. ")"
	            end
	        end
	    end
	    return val
	end
	
	-- 將 Python 序列 (str, bytes, list, tuple, iterable) 轉為 1-based Lua 陣列
	function difflib_helper.to_seq(seq)
	    if difflib_helper.is_none(seq) then return {} end
	    if type(seq) == "string" then
	        local arr = {}
	        if seq:find("[\128-\255]") then
	            local len = mw.ustring.len(seq)
	            for i = 1, len do arr[i] = mw.ustring.sub(seq, i, i) end
	        else
	            for i = 1, #seq do arr[i] = string.sub(seq, i, i) end
	        end
	        return arr
	    elseif type(seq) == "table" then
	        local pt = seq.__type
	        if pt == "list" or pt == "tuple" then
	            local arr = {}
	            for i = 1, #seq.elements do arr[i] = seq.elements[i] end
	            return arr
	        elseif pt == "bytes" or pt == "bytearray" or pt == "memoryview" then
	            local arr, d = {}, seq._data
	            for i = 1, #d do arr[i] = string.byte(d, i) end
	            return arr
	        elseif not pt and not seq.__class then
	            -- 【關鍵修復】:如果它已經是被解包過的純 Lua 陣列,直接回傳
	            return seq
	        end
	    end
	    local B = require("Module:PythonScript/Runtime").builtins
	    return B.list.__call({seq}).elements
	end
	
	function difflib_helper.calculate_ratio(matches, length)
	    if length == 0 then return 1.0 end
	    return 2.0 * matches / length
	end
	
	function difflib_helper.format_range_unified(start_idx, stop_idx)
	    local beginning = start_idx + 1
	    local length = stop_idx - start_idx
	    if length == 1 then return tostring(beginning) end
	    if length == 0 then beginning = beginning - 1 end
	    return tostring(beginning) .. "," .. tostring(length)
	end
	
	function difflib_helper.format_range_context(start_idx, stop_idx)
	    local beginning = start_idx + 1
	    local length = stop_idx - start_idx
	    if length == 0 then beginning = beginning - 1 end
	    if length <= 1 then return tostring(beginning) end
	    return tostring(beginning) .. "," .. tostring(beginning + length - 1)
	end
	
	-- ==========================================
	-- 2. SequenceMatcher 核心演算法
	-- ==========================================
	function difflib_helper.chain_b(self)
	    local d = self.__dict
	    local b = d._b_seq
	    local b2j, bjunk, bpopular = {}, {}, {}
	    d.b2j = b2j
	    d.bjunk = bjunk
	    d.bpopular = bpopular
	
	    for i = 1, #b do
	        local elt = b[i]
	        local k = difflib_helper.make_key(elt)
	        local indices = b2j[k]
	        if not indices then
	            indices = {}
	            b2j[k] = indices
	        end
	        indices[#indices + 1] = i - 1 -- 儲存 0-based 索引
	    end
	
	    local isjunk = d.isjunk
	    if not difflib_helper.is_none(isjunk) and isjunk ~= false then
	        local checked = {}
	        for i = 1, #b do
	            local elt = b[i]
	            local k = difflib_helper.make_key(elt)
	            if not checked[k] then
	                checked[k] = true
	                if difflib_helper.call_junk(isjunk, elt) then
	                    bjunk[k] = true
	                    b2j[k] = nil
	                end
	            end
	        end
	    end
	
	    local n = #b
	    if d.autojunk and n >= 200 then
	        local ntest = math.floor(n / 100) + 1
	        for k, idxs in pairs(b2j) do
	            if #idxs > ntest then
	                bpopular[k] = true
	            end
	        end
	        for k, _ in pairs(bpopular) do
	            b2j[k] = nil
	        end
	    end
	end
	
	-- 在 a[alo:ahi] 與 b[blo:bhi] (0-based) 中尋找最長連續匹配區塊
	function difflib_helper.find_longest_match_raw(self, alo, ahi, blo, bhi)
	    local d = self.__dict
	    local a, b, b2j, bjunk = d._a_seq, d._b_seq, d.b2j, d.bjunk
	    alo = alo or 0
	    ahi = ahi or #a
	    blo = blo or 0
	    bhi = bhi or #b
	
	    local besti, bestj, bestsize = alo, blo, 0
	    local j2len = {}
	
	    for i = alo, ahi - 1 do
	        local newj2len = {}
	        local k = difflib_helper.make_key(a[i + 1])
	        local j_list = b2j[k]
	        if j_list then
	            for idx = 1, #j_list do
	                local j = j_list[idx]
	                if j >= blo then
	                    if j >= bhi then break end
	                    local klen = (j2len[j - 1] or 0) + 1
	                    newj2len[j] = klen
	                    if klen > bestsize then
	                        besti = i - klen + 1
	                        bestj = j - klen + 1
	                        bestsize = klen
	                    end
	                end
	            end
	        end
	        j2len = newj2len
	    end
	
	    -- 延伸匹配:先延伸非 junk 的熱門元素,再延伸 junk 元素
	    for pass = 1, 2 do
	        local allow_junk = (pass == 2)
	        while besti > alo and bestj > blo do
	            local ka = difflib_helper.make_key(a[besti])
	            local kb = difflib_helper.make_key(b[bestj])
	            local is_j = (bjunk[kb] == true)
	            if (allow_junk == is_j) and (ka == kb) then
	                besti = besti - 1
	                bestj = bestj - 1
	                bestsize = bestsize + 1
	            else
	                break
	            end
	        end
	        while (besti + bestsize) < ahi and (bestj + bestsize) < bhi do
	            local ka = difflib_helper.make_key(a[besti + bestsize + 1])
	            local kb = difflib_helper.make_key(b[bestj + bestsize + 1])
	            local is_j = (bjunk[kb] == true)
	            if (allow_junk == is_j) and (ka == kb) then
	                bestsize = bestsize + 1
	            else
	                break
	            end
	        end
	    end
	
	    return besti, bestj, bestsize
	end
	
	function difflib_helper.get_matching_blocks_raw(self)
	    local d = self.__dict
	    if d._matching_blocks_raw then return d._matching_blocks_raw end
	
	    local la, lb = #d._a_seq, #d._b_seq
	    local queue = { { 0, la, 0, lb } }
	    local matching_blocks = {}
	
	    while #queue > 0 do
	        local frame = table.remove(queue)
	        local alo, ahi, blo, bhi = frame[1], frame[2], frame[3], frame[4]
	        local i, j, k = difflib_helper.find_longest_match_raw(self, alo, ahi, blo, bhi)
	        if k > 0 then
	            matching_blocks[#matching_blocks + 1] = { i, j, k }
	            if alo < i and blo < j then
	                queue[#queue + 1] = { alo, i, blo, j }
	            end
	            if (i + k) < ahi and (j + k) < bhi then
	                queue[#queue + 1] = { i + k, ahi, j + k, bhi }
	            end
	        end
	    end
	
	    table.sort(matching_blocks, function(x, y)
	        if x[1] ~= y[1] then return x[1] < y[1] end
	        return x[2] < y[2]
	    end)
	
	    -- 合併相鄰的區塊
	    local non_adjacent = {}
	    local i1, j1, k1 = 0, 0, 0
	    for _, blk in ipairs(matching_blocks) do
	        local i2, j2, k2 = blk[1], blk[2], blk[3]
	        if (i1 + k1 == i2) and (j1 + k1 == j2) then
	            k1 = k1 + k2
	        else
	            if k1 > 0 then non_adjacent[#non_adjacent + 1] = { i1, j1, k1 } end
	            i1, j1, k1 = i2, j2, k2
	        end
	    end
	    if k1 > 0 then non_adjacent[#non_adjacent + 1] = { i1, j1, k1 } end
	    non_adjacent[#non_adjacent + 1] = { la, lb, 0 }
	
	    d._matching_blocks_raw = non_adjacent
	    return non_adjacent
	end
	
	function difflib_helper.get_opcodes_raw(self)
	    local d = self.__dict
	    if d._opcodes_raw then return d._opcodes_raw end
	
	    local i, j = 0, 0
	    local answer = {}
	    local blocks = difflib_helper.get_matching_blocks_raw(self)
	
	    for _, blk in ipairs(blocks) do
	        local ai, bj, size = blk[1], blk[2], blk[3]
	        local tag = nil
	        if i < ai and j < bj then tag = "replace"
	        elseif i < ai then tag = "delete"
	        elseif j < bj then tag = "insert" end
	        if tag then
	            answer[#answer + 1] = { tag, i, ai, j, bj }
	        end
	        i, j = ai + size, bj + size
	        if size > 0 then
	            answer[#answer + 1] = { "equal", ai, i, bj, j }
	        end
	    end
	
	    d._opcodes_raw = answer
	    return answer
	end
	
	function difflib_helper.get_grouped_opcodes_raw(self, n)
	    n = n or 3
	    local raw_codes = difflib_helper.get_opcodes_raw(self)
	    local codes = {}
	    for idx = 1, #raw_codes do
	        local c = raw_codes[idx]
	        codes[idx] = { c[1], c[2], c[3], c[4], c[5] }
	    end
	
	    if #codes == 0 then
	        codes = { { "equal", 0, 1, 0, 1 } }
	    end
	    if codes[1][1] == "equal" then
	        local c = codes[1]
	        codes[1] = { c[1], math.max(c[2], c[3] - n), c[3], math.max(c[4], c[5] - n), c[5] }
	    end
	    if codes[#codes][1] == "equal" then
	        local c = codes[#codes]
	        codes[#codes] = { c[1], c[2], math.min(c[3], c[2] + n), c[4], math.min(c[5], c[4] + n) }
	    end
	
	    local nn = n + n
	    local groups, group = {}, {}
	    for _, c in ipairs(codes) do
	        local tag, i1, i2, j1, j2 = c[1], c[2], c[3], c[4], c[5]
	        if tag == "equal" and (i2 - i1) > nn then
	            group[#group + 1] = { tag, i1, math.min(i2, i1 + n), j1, math.min(j2, j1 + n) }
	            groups[#groups + 1] = group
	            group = {}
	            i1 = math.max(i1, i2 - n)
	            j1 = math.max(j1, j2 - n)
	        end
	        group[#group + 1] = { tag, i1, i2, j1, j2 }
	    end
	    if #group > 0 and not (#group == 1 and group[1][1] == "equal") then
	        groups[#groups + 1] = group
	    end
	    return groups
	end
	
	function difflib_helper.ratio_raw(self)
	    local blocks = difflib_helper.get_matching_blocks_raw(self)
	    local matches = 0
	    for i = 1, #blocks do matches = matches + blocks[i][3] end
	    return difflib_helper.calculate_ratio(matches, #self.__dict._a_seq + #self.__dict._b_seq)
	end
	
	function difflib_helper.quick_ratio_raw(self)
	    local d = self.__dict
	    local a, b = d._a_seq, d._b_seq
	    if not d._fullbcount then
	        local fc = {}
	        for i = 1, #b do
	            local k = difflib_helper.make_key(b[i])
	            fc[k] = (fc[k] or 0) + 1
	        end
	        d._fullbcount = fc
	    end
	    local fullbcount = d._fullbcount
	    local avail = {}
	    local matches = 0
	    for i = 1, #a do
	        local k = difflib_helper.make_key(a[i])
	        local numb = avail[k]
	        if numb == nil then numb = fullbcount[k] or 0 end
	        avail[k] = numb - 1
	        if numb > 0 then matches = matches + 1 end
	    end
	    return difflib_helper.calculate_ratio(matches, #a + #b)
	end
	
	function difflib_helper.real_quick_ratio_raw(self)
	    local la, lb = #self.__dict._a_seq, #self.__dict._b_seq
	    return difflib_helper.calculate_ratio(math.min(la, lb), la + lb)
	end
	
	-- ==========================================
	-- 3. Differ 行內比對與差異輸出演算法
	-- ==========================================
	function difflib_helper.qformat(aline, bline, atags, btags)
	    local res = {}
	    local function rstrip_nl(s) return (s:gsub("[\r\n]+$", "")) end
	    res[#res + 1] = "- " .. aline
	    atags = rstrip_nl(atags)
	    if atags ~= "" then res[#res + 1] = "? " .. atags .. "\n" end
	    res[#res + 1] = "+ " .. bline
	    btags = rstrip_nl(btags)
	    if btags ~= "" then res[#res + 1] = "? " .. btags .. "\n" end
	    return res
	end
	
	function difflib_helper.fancy_helper(a, alo, ahi, b, blo, bhi, out)
	    if alo < ahi then
	        if blo < bhi then
	            local sub_res = difflib_helper.fancy_replace(a, alo, ahi, b, blo, bhi, out._charjunk)
	            for _, line in ipairs(sub_res) do out[#out + 1] = line end
	        else
	            for i = alo + 1, ahi do out[#out + 1] = "- " .. tostring(a[i]) end
	        end
	    elseif blo < bhi then
	        for j = blo + 1, bhi do out[#out + 1] = "+ " .. tostring(b[j]) end
	    end
	end
	
	function difflib_helper.fancy_replace(a, alo, ahi, b, blo, bhi, charjunk)
	    local best_ratio, cutoff = 0.74, 0.75
	    local eqi, eqj, best_i, best_j = nil, nil, nil, nil
	    local cruncher = difflib_helper.make_sm_internal(charjunk, "", "", true)
	
	    for j = blo, bhi - 1 do
	        local bj = tostring(b[j + 1])
	        difflib_helper.sm_set_seq2(cruncher, bj)
	        for i = alo, ahi - 1 do
	            local ai = tostring(a[i + 1])
	            if ai == bj then
	                if not eqi then eqi, eqj = i, j end
	            else
	                difflib_helper.sm_set_seq1(cruncher, ai)
	                if difflib_helper.real_quick_ratio_raw(cruncher) > best_ratio
	                   and difflib_helper.quick_ratio_raw(cruncher) > best_ratio then
	                    local r = difflib_helper.ratio_raw(cruncher)
	                    if r > best_ratio then
	                        best_ratio, best_i, best_j = r, i, j
	                    end
	                end
	            end
	        end
	    end
	
	    local out = { _charjunk = charjunk }
	    if best_ratio < cutoff then
	        if not eqi then
	            for i = alo + 1, ahi do out[#out + 1] = "- " .. tostring(a[i]) end
	            for j = blo + 1, bhi do out[#out + 1] = "+ " .. tostring(b[j]) end
	            return out
	        end
	        best_i, best_j, best_ratio = eqi, eqj, 1.0
	    else
	        eqi = nil
	    end
	
	    difflib_helper.fancy_helper(a, alo, best_i, b, blo, best_j, out)
	    local aelt, belt = tostring(a[best_i + 1]), tostring(b[best_j + 1])
	    if not eqi then
	        local atags, btags = {}, {}
	        difflib_helper.sm_set_seqs(cruncher, aelt, belt)
	        for _, op in ipairs(difflib_helper.get_opcodes_raw(cruncher)) do
	            local tag, ai1, ai2, bj1, bj2 = op[1], op[2], op[3], op[4], op[5]
	            local la, lb = ai2 - ai1, bj2 - bj1
	            if tag == "replace" then
	                atags[#atags + 1] = string.rep("^", la)
	                btags[#btags + 1] = string.rep("^", lb)
	            elseif tag == "delete" then
	                atags[#atags + 1] = string.rep("-", la)
	            elseif tag == "insert" then
	                btags[#btags + 1] = string.rep("+", lb)
	            elseif tag == "equal" then
	                atags[#atags + 1] = string.rep(" ", la)
	                btags[#btags + 1] = string.rep(" ", lb)
	            end
	        end
	        for _, line in ipairs(difflib_helper.qformat(aelt, belt, table.concat(atags), table.concat(btags))) do
	            out[#out + 1] = line
	        end
	    else
	        out[#out + 1] = "  " .. aelt
	    end
	    difflib_helper.fancy_helper(a, best_i + 1, ahi, b, best_j + 1, bhi, out)
	    return out
	end
	
	function difflib_helper.differ_compare_raw(a_seq, b_seq, linejunk, charjunk)
	    local cruncher = difflib_helper.make_sm_internal(linejunk, a_seq, b_seq, true)
	    local out = {}
	    for _, op in ipairs(difflib_helper.get_opcodes_raw(cruncher)) do
	        local tag, alo, ahi, blo, bhi = op[1], op[2], op[3], op[4], op[5]
	        if tag == "replace" then
	            local fancy = difflib_helper.fancy_replace(a_seq, alo, ahi, b_seq, blo, bhi, charjunk)
	            for _, line in ipairs(fancy) do out[#out + 1] = line end
	        elseif tag == "delete" then
	            for i = alo + 1, ahi do out[#out + 1] = "- " .. tostring(a_seq[i]) end
	        elseif tag == "insert" then
	            for j = blo + 1, bhi do out[#out + 1] = "+ " .. tostring(b_seq[j]) end
	        elseif tag == "equal" then
	            for i = alo + 1, ahi do out[#out + 1] = "  " .. tostring(a_seq[i]) end
	        end
	    end
	    return out
	end
	
	-- 內部快速建構與重設 SequenceMatcher 狀態
	function difflib_helper.sm_set_seq1(sm, a)
	    local d = sm.__dict
	    d.a = a
	    d._a_seq = difflib_helper.to_seq(a)
	    d._matching_blocks_raw = nil
	    d._opcodes_raw = nil
	end
	
	function difflib_helper.sm_set_seq2(sm, b)
	    local d = sm.__dict
	    d.b = b
	    d._b_seq = difflib_helper.to_seq(b)
	    d._matching_blocks_raw = nil
	    d._opcodes_raw = nil
	    d._fullbcount = nil
	    difflib_helper.chain_b(sm)
	end
	
	function difflib_helper.sm_set_seqs(sm, a, b)
	    difflib_helper.sm_set_seq1(sm, a)
	    difflib_helper.sm_set_seq2(sm, b)
	end
	
	function difflib_helper.make_sm_internal(isjunk, a, b, autojunk)
	    difflib_helper.ensure_init()
	    local inst = require("Module:PythonScript/Class").make_instance(difflib_helper.cache.SequenceMatcher)
	    inst.__dict.isjunk = isjunk
	    inst.__dict.autojunk = (autojunk == nil) and true or difflib_helper.to_bool(autojunk)
	    difflib_helper.sm_set_seqs(inst, a or "", b or "")
	    return inst
	end
	
	-- ==========================================
	-- 4. 延遲初始化所有類別與函式
	-- ==========================================
	function difflib_helper.ensure_init()
	    if difflib_helper.initialized then return end
	    difflib_helper.initialized = true
	
	    local PyClass = require("Module:PythonScript/Class")
	    local Runtime = require("Module:PythonScript/Runtime")
	    local B = Runtime.builtins
	    local C = difflib_helper.cache
	
	    -- [A] IS_LINE_JUNK 與 IS_CHARACTER_JUNK
	    C.IS_LINE_JUNK = {
	        __type = "builtin_method", __name = "IS_LINE_JUNK",
	        __call = function(a, kw)
	            local line = tostring(a[1] or "")
	            local pat = (a[2] ~= nil and a[2]) or (kw and kw.pat)
	            if not difflib_helper.is_none(pat) then
	                local Evaluator = require("Module:PythonScript/Evaluator")
	                local res = Evaluator.invoke(pat, {line}, {})
	                return not difflib_helper.is_none(res) and difflib_helper.to_bool(res)
	            end
	            local stripped = line:match("^%s*(.-)%s*$")
	            return stripped == "" or stripped == "#"
	        end
	    }
	
	    C.IS_CHARACTER_JUNK = {
	        __type = "builtin_method", __name = "IS_CHARACTER_JUNK",
	        __call = function(a, kw)
	            local ch = tostring(a[1] or "")
	            local ws = (a[2] ~= nil and a[2]) or (kw and kw.ws) or " \t"
	            if ch == "" then return false end
	            return string.find(ws, ch, 1, true) ~= nil
	        end
	    }
	
	    -- [B] Match namedtuple 類別 (Match(a, b, size))
	    local match_dict = {
	        __init__ = { __type = "builtin_method", __call = function(a, kw)
	            local self = a[1]
	            local va = (a[2] ~= nil and a[2]) or (kw and kw.a) or 0
	            local vb = (a[3] ~= nil and a[3]) or (kw and kw.b) or 0
	            local vs = (a[4] ~= nil and a[4]) or (kw and kw.size) or 0
	            self.__dict.a = va
	            self.__dict.b = vb
	            self.__dict.size = vs
	            self.__dict._elts = { va, vb, vs }
	            self.__builtin_value = { __type = "tuple", elements = { va, vb, vs } }
	            return nil
	        end },
	        __getitem__ = { __type = "builtin_method", __call = function(a)
	            local self, idx = a[1], a[2]
	            if type(idx) == "number" then
	                if idx < 0 then idx = 3 + idx end
	                local v = self.__dict._elts[idx + 1]
	                if v ~= nil then return v end
	            end
	            Runtime.raise("IndexError", "tuple index out of range")
	        end },
	        __len__ = { __type = "builtin_method", __call = function() return 3 end },
	        __iter__ = { __type = "builtin_method", __call = function(a)
	            return B.iter({ { __type = "tuple", elements = a[1].__dict._elts } })
	        end },
	        __eq__ = { __type = "builtin_method", __call = function(a)
	            local self, other = a[1], a[2]
	            local o_elts = (type(other) == "table") and (other.elements or (other.__dict and other.__dict._elts))
	            if not o_elts or #o_elts ~= 3 then return false end
	            local s_elts = self.__dict._elts
	            return s_elts[1] == o_elts[1] and s_elts[2] == o_elts[2] and s_elts[3] == o_elts[3]
	        end },
	        __repr__ = { __type = "builtin_method", __call = function(a)
	            local d = a[1].__dict
	            return string.format("Match(a=%s, b=%s, size=%s)", tostring(d.a), tostring(d.b), tostring(d.size))
	        end }
	    }
	    match_dict.__str__ = match_dict.__repr__
	    C.Match = PyClass.make_class("Match", {}, match_dict)
	    C.Match.__dict["__module__"] = "difflib"
	
	    local function make_match_inst(va, vb, vs)
	        local inst = PyClass.make_instance(C.Match)
	        inst.__dict.a = va; inst.__dict.b = vb; inst.__dict.size = vs
	        inst.__dict._elts = { va, vb, vs }
	        inst.__builtin_value = { __type = "tuple", elements = { va, vb, vs } }
	        return inst
	    end
	
	    -- [C] SequenceMatcher 類別
	    local sm_dict = {
	        __init__ = { __type = "builtin_method", __call = function(a, kw)
	            local self = a[1]
	            kw = kw or {}
	            local isjunk = (a[2] ~= nil and a[2]) or kw.isjunk or B.None
	            local seq1 = (a[3] ~= nil and a[3]) or kw.a or ""
	            local seq2 = (a[4] ~= nil and a[4]) or kw.b or ""
	            local autojunk = true
	            if a[5] ~= nil then autojunk = difflib_helper.to_bool(a[5])
	            elseif kw.autojunk ~= nil then autojunk = difflib_helper.to_bool(kw.autojunk) end
	
	            self.__dict.isjunk = isjunk
	            self.__dict.autojunk = autojunk
	            difflib_helper.sm_set_seqs(self, seq1, seq2)
	            return nil
	        end },
	        set_seqs = { __type = "builtin_method", __call = function(a)
	            difflib_helper.sm_set_seqs(a[1], a[2], a[3])
	            return B.None
	        end },
	        set_seq1 = { __type = "builtin_method", __call = function(a)
	            difflib_helper.sm_set_seq1(a[1], a[2])
	            return B.None
	        end },
	        set_seq2 = { __type = "builtin_method", __call = function(a)
	            difflib_helper.sm_set_seq2(a[1], a[2])
	            return B.None
	        end },
	        find_longest_match = { __type = "builtin_method", __call = function(a, kw)
	            local self = a[1]
	            local alo = (a[2] ~= nil and a[2]) or (kw and kw.alo) or 0
	            local ahi = (a[3] ~= nil and a[3]) or (kw and kw.ahi) or #self.__dict._a_seq
	            local blo = (a[4] ~= nil and a[4]) or (kw and kw.blo) or 0
	            local bhi = (a[5] ~= nil and a[5]) or (kw and kw.bhi) or #self.__dict._b_seq
	            local bi, bj, bs = difflib_helper.find_longest_match_raw(self, alo, ahi, blo, bhi)
	            return make_match_inst(bi, bj, bs)
	        end },
	        get_matching_blocks = { __type = "builtin_method", __call = function(a)
	            local raw = difflib_helper.get_matching_blocks_raw(a[1])
	            local elts = {}
	            for i = 1, #raw do
	                local blk = raw[i]
	                elts[i] = make_match_inst(blk[1], blk[2], blk[3])
	            end
	            return { __type = "list", elements = elts }
	        end },
	        get_opcodes = { __type = "builtin_method", __call = function(a)
	            local raw = difflib_helper.get_opcodes_raw(a[1])
	            local elts = {}
	            for i = 1, #raw do
	                local op = raw[i]
	                elts[i] = { __type = "tuple", elements = { op[1], op[2], op[3], op[4], op[5] } }
	            end
	            return { __type = "list", elements = elts }
	        end },
	        get_grouped_opcodes = { __type = "builtin_method", __call = function(a, kw)
	            local n = (not difflib_helper.is_none(a[2]) and a[2]) or (kw and not difflib_helper.is_none(kw.n) and kw.n) or 3
	            local raw_groups = difflib_helper.get_grouped_opcodes_raw(a[1], n)
	            local py_groups = {}
	            for i = 1, #raw_groups do
	                local g = raw_groups[i]
	                local g_elts = {}
	                for j = 1, #g do
	                    local op = g[j]
	                    g_elts[j] = { __type = "tuple", elements = { op[1], op[2], op[3], op[4], op[5] } }
	                end
	                py_groups[i] = { __type = "list", elements = g_elts }
	            end
	            return { __type = "list", elements = py_groups }
	        end },
	        ratio = { __type = "builtin_method", __call = function(a) return difflib_helper.ratio_raw(a[1]) end },
	        quick_ratio = { __type = "builtin_method", __call = function(a) return difflib_helper.quick_ratio_raw(a[1]) end },
	        real_quick_ratio = { __type = "builtin_method", __call = function(a) return difflib_helper.real_quick_ratio_raw(a[1]) end }
	    }
	    C.SequenceMatcher = PyClass.make_class("SequenceMatcher", {}, sm_dict)
	    C.SequenceMatcher.__dict["__module__"] = "difflib"
	
	    -- [D] Differ 類別
	    local differ_dict = {
	        __init__ = { __type = "builtin_method", __call = function(a, kw)
	            local self = a[1]
	            kw = kw or {}
	            self.__dict.linejunk = (a[2] ~= nil and a[2]) or kw.linejunk or B.None
	            self.__dict.charjunk = (a[3] ~= nil and a[3]) or kw.charjunk or B.None
	            return nil
	        end },
	        compare = { __type = "builtin_method", __call = function(a)
	            local self = a[1]
	            local a_seq = difflib_helper.to_seq(a[2])
	            local b_seq = difflib_helper.to_seq(a[3])
	            local lines = difflib_helper.differ_compare_raw(a_seq, b_seq, self.__dict.linejunk, self.__dict.charjunk)
	            return { __type = "list", elements = lines }
	        end }
	    }
	    C.Differ = PyClass.make_class("Differ", {}, differ_dict)
	    C.Differ.__dict["__module__"] = "difflib"
	
	    -- [E] HtmlDiff 類別
	    local function html_escape(s)
	        return (tostring(s):gsub("&", "&amp;"):gsub("<", "&lt;"):gsub(">", "&gt;"):gsub(" ", "&nbsp;"))
	    end
		local htmldiff_dict
	    htmldiff_dict = {
	        __init__ = { __type = "builtin_method", __call = function(a, kw)
	            local self = a[1]
	            kw = kw or {}
	            self.__dict._tabsize = (a[2] ~= nil and a[2]) or kw.tabsize or 8
	            self.__dict._wrapcolumn = (a[3] ~= nil and a[3]) or kw.wrapcolumn or B.None
	            self.__dict._linejunk = (a[4] ~= nil and a[4]) or kw.linejunk or B.None
	            self.__dict._charjunk = (a[5] ~= nil and a[5]) or kw.charjunk or C.IS_CHARACTER_JUNK
	            return nil
	        end },
	        make_table = { __type = "builtin_method", __call = function(a, kw)
	            local self = a[1]
	            kw = kw or {}
	            local fromlines = difflib_helper.to_seq(a[2] or kw.fromlines)
	            local tolines = difflib_helper.to_seq(a[3] or kw.tolines)
	            local fromdesc = tostring((a[4] ~= nil and a[4]) or kw.fromdesc or "")
	            local todesc = tostring((a[5] ~= nil and a[5]) or kw.todesc or "")
	            local context = difflib_helper.to_bool((a[6] ~= nil and a[6]) or kw.context or false)
	            local numlines = tonumber((a[7] ~= nil and a[7]) or kw.numlines) or 5
	
	            local sm = difflib_helper.make_sm_internal(self.__dict._linejunk, fromlines, tolines, true)
	            local groups = context and difflib_helper.get_grouped_opcodes_raw(sm, numlines)
	                or { difflib_helper.get_opcodes_raw(sm) }
	
	            local rows = {}
	            rows[#rows + 1] = '<table class="diff" id="difflib_chg_to0__top" cellspacing="0" cellpadding="0" rules="groups" >'
	            rows[#rows + 1] = '<colgroup></colgroup> <colgroup></colgroup> <colgroup></colgroup>'
	            rows[#rows + 1] = '<colgroup></colgroup> <colgroup></colgroup> <colgroup></colgroup>'
	            if fromdesc ~= "" or todesc ~= "" then
	                rows[#rows + 1] = string.format('<thead><tr><th class="diff_next"><br /></th><th colspan="2" class="diff_header">%s</th><th class="diff_next"><br /></th><th colspan="2" class="diff_header">%s</th></tr></thead>', html_escape(fromdesc), html_escape(todesc))
	            end
	            rows[#rows + 1] = '<tbody>'
	
	            for g_idx, group in ipairs(groups) do
	                if g_idx > 1 then
	                    rows[#rows + 1] = '</tbody><tbody>'
	                end
	                for _, op in ipairs(group) do
	                    local tag, i1, i2, j1, j2 = op[1], op[2], op[3], op[4], op[5]
	                    if tag == "equal" then
	                        for k = 0, (i2 - i1 - 1) do
	                            local lno1, lno2 = i1 + k + 1, j1 + k + 1
	                            local txt1 = html_escape((tostring(fromlines[lno1] or ""):gsub("[\r\n]+$", "")))
	                            local txt2 = html_escape((tostring(tolines[lno2] or ""):gsub("[\r\n]+$", "")))
	                            rows[#rows + 1] = string.format('<tr><td class="diff_next"></td><td class="diff_header" id="from0_%d">%d</td><td nowrap="nowrap">%s</td><td class="diff_next"></td><td class="diff_header" id="to0_%d">%d</td><td nowrap="nowrap">%s</td></tr>', lno1, lno1, txt1, lno2, lno2, txt2)
	                        end
	                    else
	                        local max_k = math.max(i2 - i1, j2 - j1)
	                        local css_l = (tag == "delete" and "diff_sub") or (tag == "replace" and "diff_chg") or ""
	                        local css_r = (tag == "insert" and "diff_add") or (tag == "replace" and "diff_chg") or ""
	                        for k = 0, max_k - 1 do
	                            local has_l = (i1 + k) < i2
	                            local has_r = (j1 + k) < j2
	                            local lno1 = has_l and tostring(i1 + k + 1) or ""
	                            local lno2 = has_r and tostring(j1 + k + 1) or ""
	                            local txt1 = has_l and html_escape((tostring(fromlines[i1 + k + 1] or ""):gsub("[\r\n]+$", ""))) or ""
	                            local txt2 = has_r and html_escape((tostring(tolines[j1 + k + 1] or ""):gsub("[\r\n]+$", ""))) or ""
	                            if has_l and css_l ~= "" then txt1 = '<span class="' .. css_l .. '">' .. txt1 .. '</span>' end
	                            if has_r and css_r ~= "" then txt2 = '<span class="' .. css_r .. '">' .. txt2 .. '</span>' end
	                            rows[#rows + 1] = string.format('<tr><td class="diff_next"></td><td class="diff_header">%s</td><td nowrap="nowrap">%s</td><td class="diff_next"></td><td class="diff_header">%s</td><td nowrap="nowrap">%s</td></tr>', lno1, txt1, lno2, txt2)
	                        end
	                    end
	                end
	            end
	            rows[#rows + 1] = '</tbody></table>'
	            return table.concat(rows, "\n")
	        end },
	        make_file = { __type = "builtin_method", __call = function(a, kw)
	            local tbl_html = htmldiff_dict.make_table.__call(a, kw)
	            local charset = (kw and kw.charset) or "utf-8"
	            return string.format(
	                '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n' ..
	                '<html>\n<head>\n<meta http-equiv="Content-Type" content="text/html; charset=%s" />\n' ..
	                '<title></title>\n<style type="text/css">\n' ..
	                'table.diff {font-family:Courier; border:medium;}\n' ..
	                '.diff_header {background-color:#e0e0e0}\n' ..
	                'td.diff_header {text-align:right}\n' ..
	                '.diff_next {background-color:#c0c0c0}\n' ..
	                '.diff_add {background-color:#aaffaa}\n' ..
	                '.diff_chg {background-color:#ffff77}\n' ..
	                '.diff_sub {background-color:#ffaaaa}\n' ..
	                '</style>\n</head>\n<body>\n%s\n</body>\n</html>',
	                tostring(charset), tbl_html
	            )
	        end }
	    }
	    C.HtmlDiff = PyClass.make_class("HtmlDiff", {}, htmldiff_dict)
	    C.HtmlDiff.__dict["__module__"] = "difflib"
	
	    -- [F] 模組頂層函式:get_close_matches, unified_diff, context_diff, ndiff, restore, diff_bytes
	    C.get_close_matches = {
	        __type = "builtin_method", __name = "get_close_matches",
	        __call = function(a, kw)
	            kw = kw or {}
	            local word = a[1] or kw.word
	            local possibilities = difflib_helper.to_seq(a[2] or kw.possibilities)
	            local n = tonumber((a[3] ~= nil and a[3]) or kw.n) or 3
	            local cutoff = tonumber((a[4] ~= nil and a[4]) or kw.cutoff) or 0.6
	
	            if n <= 0 then Runtime.raise("ValueError", "n must be > 0: " .. tostring(n)) end
	            if cutoff < 0.0 or cutoff > 1.0 then Runtime.raise("ValueError", "cutoff must be in [0.0, 1.0]: " .. tostring(cutoff)) end
	
	            local result = {}
	            local s = difflib_helper.make_sm_internal(B.None, "", word, true)
	            for idx, x in ipairs(possibilities) do
	                difflib_helper.sm_set_seq1(s, x)
	                if difflib_helper.real_quick_ratio_raw(s) >= cutoff
	                   and difflib_helper.quick_ratio_raw(s) >= cutoff then
	                    local score = difflib_helper.ratio_raw(s)
	                    if score >= cutoff then
	                        result[#result + 1] = { score = score, x = x, idx = idx }
	                    end
	                end
	            end
	
	            table.sort(result, function(p1, p2)
	                if p1.score ~= p2.score then return p1.score > p2.score end
	                if type(p1.x) == "string" and type(p2.x) == "string" and p1.x ~= p2.x then
	                    return p1.x > p2.x
	                end
	                return p1.idx < p2.idx
	            end)
	
	            local out = {}
	            for i = 1, math.min(n, #result) do out[i] = result[i].x end
	            return { __type = "list", elements = out }
	        end
	    }
	
	    C.unified_diff = {
	        __type = "builtin_method", __name = "unified_diff",
	        __call = function(a, kw)
	            kw = kw or {}
	            local seq_a = difflib_helper.to_seq(a[1] or kw.a)
	            local seq_b = difflib_helper.to_seq(a[2] or kw.b)
	            local fromfile = tostring((a[3] ~= nil and a[3]) or kw.fromfile or "")
	            local tofile = tostring((a[4] ~= nil and a[4]) or kw.tofile or "")
	            local fromdate = tostring((a[5] ~= nil and a[5]) or kw.fromfiledate or "")
	            local todate = tostring((a[6] ~= nil and a[6]) or kw.tofiledate or "")
	            local n = tonumber((a[7] ~= nil and a[7]) or kw.n) or 3
	            local lineterm = (a[8] ~= nil and a[8]) or kw.lineterm
	            if lineterm == nil then lineterm = "\n" else lineterm = tostring(lineterm) end
	
	            local started = false
	            local out = {}
	            local sm = difflib_helper.make_sm_internal(B.None, seq_a, seq_b, true)
	
	            for _, group in ipairs(difflib_helper.get_grouped_opcodes_raw(sm, n)) do
	                if not started then
	                    started = true
	                    local from_t = (fromdate ~= "") and ("\t" .. fromdate) or ""
	                    local to_t = (todate ~= "") and ("\t" .. todate) or ""
	                    out[#out + 1] = "--- " .. fromfile .. from_t .. lineterm
	                    out[#out + 1] = "+++ " .. tofile .. to_t .. lineterm
	                end
	                local first, last = group[1], group[#group]
	                local file1_range = difflib_helper.format_range_unified(first[2], last[3])
	                local file2_range = difflib_helper.format_range_unified(first[4], last[5])
	                out[#out + 1] = "@@ -" .. file1_range .. " +" .. file2_range .. " @@" .. lineterm
	
	                for _, op in ipairs(group) do
	                    local tag, i1, i2, j1, j2 = op[1], op[2], op[3], op[4], op[5]
	                    if tag == "equal" then
	                        for i = i1 + 1, i2 do out[#out + 1] = " " .. tostring(seq_a[i]) end
	                    else
	                        if tag == "replace" or tag == "delete" then
	                            for i = i1 + 1, i2 do out[#out + 1] = "-" .. tostring(seq_a[i]) end
	                        end
	                        if tag == "replace" or tag == "insert" then
	                            for j = j1 + 1, j2 do out[#out + 1] = "+" .. tostring(seq_b[j]) end
	                        end
	                    end
	                end
	            end
	            return { __type = "list", elements = out }
	        end
	    }
	
	    C.context_diff = {
	        __type = "builtin_method", __name = "context_diff",
	        __call = function(a, kw)
	            kw = kw or {}
	            local seq_a = difflib_helper.to_seq(a[1] or kw.a)
	            local seq_b = difflib_helper.to_seq(a[2] or kw.b)
	            local fromfile = tostring((a[3] ~= nil and a[3]) or kw.fromfile or "")
	            local tofile = tostring((a[4] ~= nil and a[4]) or kw.tofile or "")
	            local fromdate = tostring((a[5] ~= nil and a[5]) or kw.fromfiledate or "")
	            local todate = tostring((a[6] ~= nil and a[6]) or kw.tofiledate or "")
	            local n = tonumber((a[7] ~= nil and a[7]) or kw.n) or 3
	            local lineterm = (a[8] ~= nil and a[8]) or kw.lineterm
	            if lineterm == nil then lineterm = "\n" else lineterm = tostring(lineterm) end
	
	            local prefix = { insert = "+ ", delete = "- ", replace = "! ", equal = "  " }
	            local started = false
	            local out = {}
	            local sm = difflib_helper.make_sm_internal(B.None, seq_a, seq_b, true)
	
	            for _, group in ipairs(difflib_helper.get_grouped_opcodes_raw(sm, n)) do
	                if not started then
	                    started = true
	                    local from_t = (fromdate ~= "") and ("\t" .. fromdate) or ""
	                    local to_t = (todate ~= "") and ("\t" .. todate) or ""
	                    out[#out + 1] = "*** " .. fromfile .. from_t .. lineterm
	                    out[#out + 1] = "--- " .. tofile .. to_t .. lineterm
	                end
	                local first, last = group[1], group[#group]
	                out[#out + 1] = "***************" .. lineterm
	                local file1_range = difflib_helper.format_range_context(first[2], last[3])
	                out[#out + 1] = "*** " .. file1_range .. " ****" .. lineterm
	
	                local has_a_chg, has_b_chg = false, false
	                for _, op in ipairs(group) do
	                    if op[1] == "replace" or op[1] == "delete" then has_a_chg = true end
	                    if op[1] == "replace" or op[1] == "insert" then has_b_chg = true end
	                end
	                if has_a_chg then
	                    for _, op in ipairs(group) do
	                        local tag, i1, i2 = op[1], op[2], op[3]
	                        if tag ~= "insert" then
	                            for i = i1 + 1, i2 do out[#out + 1] = prefix[tag] .. tostring(seq_a[i]) end
	                        end
	                    end
	                end
	
	                local file2_range = difflib_helper.format_range_context(first[4], last[5])
	                out[#out + 1] = "--- " .. file2_range .. " ----" .. lineterm
	                if has_b_chg then
	                    for _, op in ipairs(group) do
	                        local tag, j1, j2 = op[1], op[4], op[5]
	                        if tag ~= "delete" then
	                            for j = j1 + 1, j2 do out[#out + 1] = prefix[tag] .. tostring(seq_b[j]) end
	                        end
	                    end
	                end
	            end
	            return { __type = "list", elements = out }
	        end
	    }
	
	    C.ndiff = {
	        __type = "builtin_method", __name = "ndiff",
	        __call = function(a, kw)
	            kw = kw or {}
	            local seq_a = difflib_helper.to_seq(a[1] or kw.a)
	            local seq_b = difflib_helper.to_seq(a[2] or kw.b)
	            local lj = (a[3] ~= nil and a[3]) or kw.linejunk or B.None
	            local cj = (a[4] ~= nil and a[4]) or kw.charjunk or C.IS_CHARACTER_JUNK
	            local lines = difflib_helper.differ_compare_raw(seq_a, seq_b, lj, cj)
	            return { __type = "list", elements = lines }
	        end
	    }
	
	    C.restore = {
	        __type = "builtin_method", __name = "restore",
	        __call = function(a, kw)
	            kw = kw or {}
	            local delta = difflib_helper.to_seq(a[1] or kw.delta)
	            local which = tonumber((a[2] ~= nil and a[2]) or kw.which)
	            if which ~= 1 and which ~= 2 then
	                Runtime.raise("ValueError", "unknown delta choice (must be 1 or 2): " .. tostring(which))
	            end
	            local tag = (which == 1) and "- " or "+ "
	            local out = {}
	            for _, line in ipairs(delta) do
	                local s = tostring(line)
	                local pfx = s:sub(1, 2)
	                if pfx == "  " or pfx == tag then
	                    out[#out + 1] = s:sub(3)
	                end
	            end
	            return { __type = "list", elements = out }
	        end
	    }
	
	    C.diff_bytes = {
	        __type = "builtin_method", __name = "diff_bytes",
	        __call = function(a, kw)
	            kw = kw or {}
	            local dfunc = a[1] or kw.dfunc
	            local function b_to_s(b_obj, def)
	                if difflib_helper.is_none(b_obj) then return def end
	                if type(b_obj) == "table" and (b_obj.__type == "bytes" or b_obj.__type == "bytearray" or b_obj.__type == "memoryview") then
	                    return b_obj._data
	                end
	                Runtime.raise("TypeError", "diff_bytes() arguments must be bytes")
	            end
	            local function b_list_to_s(seq)
	                local elts = difflib_helper.to_seq(seq)
	                local res = {}
	                for i = 1, #elts do res[i] = b_to_s(elts[i], "") end
	                return { __type = "list", elements = res }
	            end
	            local sa = b_list_to_s(a[2] or kw.a)
	            local sb = b_list_to_s(a[3] or kw.b)
	            local ff = b_to_s(a[4] or kw.fromfile, "")
	            local tf = b_to_s(a[5] or kw.tofile, "")
	            local fd = b_to_s(a[6] or kw.fromfiledate, "")
	            local td = b_to_s(a[7] or kw.tofiledate, "")
	            local n = (a[8] ~= nil and a[8]) or kw.n or 3
	            local lt = b_to_s(a[9] or kw.lineterm, "\n")
	
	            local Evaluator = require("Module:PythonScript/Evaluator")
	            local str_lines = Evaluator.invoke(dfunc, { sa, sb, ff, tf, fd, td, n, lt }, {})
	            local elts = difflib_helper.to_seq(str_lines)
	            local b_out = {}
	            for i = 1, #elts do
	                b_out[i] = { __type = "bytes", _data = tostring(elts[i]) }
	            end
	            return { __type = "list", elements = b_out }
	        end
	    }
	end
	
	-- ==========================================
	-- 5. 模組匯出工廠
	-- ==========================================
	function difflib_helper.get_module()
	    local PyClass = require("Module:PythonScript/Class")
	    local Runtime = require("Module:PythonScript/Runtime")
	
	    local mod_dict = {
	        __getattr__ = {
	            __type = "builtin_method",
	            __call = function(args)
	                local self, attr = args[1], args[2]
	                difflib_helper.ensure_init()
	                local val = difflib_helper.cache[attr]
	                if val ~= nil then
	                    self.__dict[attr] = val
	                    return val
	                end
	                Runtime.raise("AttributeError", "module 'difflib' has no attribute '" .. tostring(attr) .. "'")
	            end
	        }
	    }
	    local mod = PyClass.make_instance(PyClass.make_class("module", {}, mod_dict))
	    mod.__dict["__name__"] = "difflib"
	    mod.__dict["__all__"] = {
	        __type = "list",
	        elements = {
	            "get_close_matches", "ndiff", "restore", "SequenceMatcher",
	            "Differ", "IS_CHARACTER_JUNK", "IS_LINE_JUNK", "context_diff",
	            "unified_diff", "diff_bytes", "HtmlDiff", "Match"
	        }
	    }
	    return mod
	end
	return difflib_helper
end

return StdLogics