Skip to content

fix(oocana): use dict mapping for compression_suffix instead of if-elif chain - #457

Open
leavesster wants to merge 1 commit into
mainfrom
fix/compression-suffix-dict-mapping
Open

fix(oocana): use dict mapping for compression_suffix instead of if-elif chain#457
leavesster wants to merge 1 commit into
mainfrom
fix/compression-suffix-dict-mapping

Conversation

@leavesster

Copy link
Copy Markdown
Contributor

Summary

  • Replace if-elif chain with COMPRESSION_SUFFIXES dictionary mapping
  • Use .get() to safely handle missing keys
  • Add unit tests for compression_suffix() function

Problem

Original code had long if-elif chain with potential KeyError risk:

ifcompression["method"] =="zip":
return".zip"elifcompression["method"] =="gzip":
return".gz"# ... 6 more branches

Solution

COMPRESSION_SUFFIXES= {
"zip": ".zip", "gzip": ".gz", "bz2": ".bz2",
"zstd": ".zst", "xz": ".xz", "tar": ".tar",
}
defcompression_suffix(context):
compression=compression_options(context)
ifcompressionisNone:
return".pkl"returnCOMPRESSION_SUFFIXES.get(compression.get("method"), ".pkl")

Test Plan

  • Added tests/test_serialization.py with coverage for all compression methods
  • All existing tests pass

Replace if-elif chain with a dictionary mapping for cleaner code.
Also fix potential KeyError by using .get() method.
Changes:
- Add COMPRESSION_SUFFIXES constant mapping method to suffix
- Use .get() to safely access 'method' key
- Add comprehensive unit tests for compression_suffix
CopilotAI review requested due to automatic review settings January 31, 2026 09:27
@coderabbitai

coderabbitaiBot commented Jan 31, 2026

Copy link
Copy Markdown

总体说明

本次变更通过引入 COMPRESSION_SUFFIXES 映射表,将压缩后缀逻辑从多个条件分支重构为单一映射查询机制。同时新增了一个全面的测试模块,用于验证压缩后缀和压缩选项在各种场景下的行为。

变更内容

文件群组 / 文件路径变更摘要
核心序列化重构
oocana/oocana/serialization.py
引入 COMPRESSION_SUFFIXES 常量映射压缩方法与文件后缀;重构 compression_suffix 函数,将多个条件分支替换为映射查询,默认返回 ".pkl";移除显式的按方法分发逻辑。
测试套件新增
oocana/tests/test_serialization.py
新增 164 行测试代码,覆盖 compression_suffix 函数在多种压缩方法(zip、gzip、bz2、zstd、xz、tar)及边界情况下的行为;测试 compression_options 函数处理缺失、有效和无效 JSON 文件的场景;使用临时目录和 mock 上下文完成测试隔离。

代码审查工作量估算

🎯 3 (中等复杂度) | ⏱️ ~20 分钟

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description check✅ PassedPR description is well-related to the changeset, providing clear problem statement, solution details with code examples, and test plan that align with the actual changes made.
Title check✅ PassedThe pull request title follows the required format with type(scope): subject pattern, clearly describing the main refactoring change from if-elif chain to dict mapping.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Refactors compression_suffix() to use a dictionary mapping for compression method → file suffix (instead of an if/elif chain) and adds unit tests to validate behavior across supported and edge-case methods.

Changes:

  • Introduced COMPRESSION_SUFFIXES mapping and updated compression_suffix() to use .get()-based lookup with defaults.
  • Updated compression_suffix() docstring to match actual default behavior (.pkl).
  • Added unit tests covering supported methods and fallback behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

FileDescription
oocana/oocana/serialization.pyReplaces if/elif suffix selection with a mapping constant and simplified lookup logic.
oocana/tests/test_serialization.pyAdds tests for compression_suffix() and compression_options() behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -0,0 +1,164 @@
import unittest
from unittest.mock import MagicMock, patch

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

patch is imported but never used in this test module; removing it avoids lint warnings and keeps the test file tidy.

Suggested change
fromunittest.mockimportMagicMock, patch
fromunittest.mockimportMagicMock

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +93
method = compression.get("method")
if method is None:

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

COMPRESSION_SUFFIXES.get(method, ...) assumes method is a hashable key. If the options file contains a non-string (e.g., a list/dict from valid-but-unexpected JSON), this will raise TypeError and crash, whereas the previous if/elif chain would safely fall back. Consider guarding with isinstance(method, str) (and/or isinstance(compression, dict)) before doing the dict lookup, otherwise return the default suffix.

Suggested change
method=compression.get("method")
ifmethodisNone:
# Ensure we have a dictionary before accessing keys. Malformed or unexpected
# JSON in the options file may result in a non-dict value here.
ifnotisinstance(compression, dict):
return".pkl"
method=compression.get("method")
# Guard against non-string (and thus potentially unhashable) methods.
ifnotisinstance(method, str):

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +80
# Mapping from compression method to file suffix
COMPRESSION_SUFFIXES = {
"zip": ".zip",
"gzip": ".gz",
"bz2": ".bz2",
"zstd": ".zst",
"xz": ".xz",
"tar": ".tar",
}

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

The compression methods are now duplicated in three places (SUPPORTED_COMPRESSION_METHODS, the CompressionOptions Literal, and COMPRESSION_SUFFIXES). This can drift over time (e.g., a method added to SUPPORTED_COMPRESSION_METHODS but missing here would silently fall back to .pkl). Consider making one source of truth (e.g., derive SUPPORTED_COMPRESSION_METHODS from COMPRESSION_SUFFIXES.keys()), and keep the type Literal in sync with that constant.

Copilot uses AI. Check for mistakes.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@oocana/oocana/serialization.py`:
- Around line 87-96: compression_options 返回的 compression 可能不是 dict,从而在
compression.get("method") 处抛出 AttributeError;在函数/片段中(使用
compression_options、compression、method、COMPRESSION_SUFFIXES 的地方)先对 compression
做类型保护(例如 isinstance(compression, dict) 或
collections.abc.Mapping),若不是合适的映射类型则直接返回默认后缀 ".pkl";若是映射再安全读取 method 并用
COMPRESSION_SUFFIXES.get(method, ".pkl") 返回结果。
🧹 Nitpick comments (2)
oocana/oocana/serialization.py (1)

72-80: 避免与 SUPPORTED_COMPRESSION_METHODS 重复来源,防止漂移
目前方法列表在 SUPPORTED_COMPRESSION_METHODSCOMPRESSION_SUFFIXES 中重复维护,后续新增/删除方法容易不同步。建议以 COMPRESSION_SUFFIXES 作为单一来源生成列表。若该常量希望对外公开,也可同步加入 __all__

🔧 参考改法(统一来源)
-SUPPORTED_COMPRESSION_METHODS = ["zip", "gzip", "bz2", "zstd", "xz", "tar"]+# Mapping from compression method to file suffix+COMPRESSION_SUFFIXES = {+ "zip": ".zip",+ "gzip": ".gz",+ "bz2": ".bz2",+ "zstd": ".zst",+ "xz": ".xz",+ "tar": ".tar",+}+SUPPORTED_COMPRESSION_METHODS = list(COMPRESSION_SUFFIXES.keys())
oocana/tests/test_serialization.py (1)

29-119: 建议参数化这些重复的后缀测试
zip/gzip/bz2/zstd/xz/tar 的测试结构完全一致,后续维护成本偏高。可以用 subTest + 参数表合并为一个测试。

♻️ 参考改法(参数化)
- def test_compression_suffix_zip(self):- """Test compression suffix for zip method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "zip"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".zip")-- def test_compression_suffix_gzip(self):- """Test compression suffix for gzip method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "gzip"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".gz")-- ...-- def test_compression_suffix_tar(self):- """Test compression suffix for tar method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "tar"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".tar")+ def test_compression_suffix_methods(self):+ """Test compression suffix for supported methods."""+ from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE++ cases = {+ "zip": ".zip",+ "gzip": ".gz",+ "bz2": ".bz2",+ "zstd": ".zst",+ "xz": ".xz",+ "tar": ".tar",+ }+ for method, expected in cases.items():+ with self.subTest(method=method):+ with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:+ json.dump({"method": method}, f)+ self.assertEqual(compression_suffix(self.mock_context), expected)

Comment on lines 87 to +96
compression = compression_options(context)

if compression is None or compression["method"] is None:
if compression is None:
return ".pkl"

method = compression["method"]
if method == "zip":
return ".zip"
elif method == "gzip":
return ".gz"
elif method == "bz2":
return ".bz2"
elif method == "zstd":
return ".zst"
elif method == "xz":
return ".xz"
elif method == "tar":
return ".tar"
else:
return ".pkl" # Default case if method is not recognized No newline at end of file

method = compression.get("method")
if method is None:
return ".pkl"

return COMPRESSION_SUFFIXES.get(method, ".pkl") No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

防止压缩配置为非 dict 时触发 AttributeError
compression_options 读取的是任意 JSON,若文件内容为合法但非 dict(如字符串/列表),compression.get(...) 会直接报错。建议加类型保护并回退到默认后缀。

🛡️ 参考修复
 compression = compression_options(context)
- if compression is None:+ if not isinstance(compression, dict):
return ".pkl"
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
compression=compression_options(context)
ifcompressionisNoneorcompression["method"] isNone:
ifcompressionisNone:
return".pkl"
method=compression["method"]
ifmethod=="zip":
return".zip"
elifmethod=="gzip":
return".gz"
elifmethod=="bz2":
return".bz2"
elifmethod=="zstd":
return".zst"
elifmethod=="xz":
return".xz"
elifmethod=="tar":
return".tar"
else:
return".pkl"# Default case if method is not recognized
\ Nonewlineatendoffile
method=compression.get("method")
ifmethodisNone:
return".pkl"
returnCOMPRESSION_SUFFIXES.get(method, ".pkl")
compression=compression_options(context)
ifnotisinstance(compression, dict):
return".pkl"
method=compression.get("method")
ifmethodisNone:
return".pkl"
returnCOMPRESSION_SUFFIXES.get(method, ".pkl")
🤖 Prompt for AI Agents
In `@oocana/oocana/serialization.py` around lines 87 - 96, compression_options 返回的
compression 可能不是 dict,从而在 compression.get("method") 处抛出
AttributeError;在函数/片段中(使用
compression_options、compression、method、COMPRESSION_SUFFIXES 的地方)先对 compression
做类型保护(例如 isinstance(compression, dict) 或
collections.abc.Mapping),若不是合适的映射类型则直接返回默认后缀 ".pkl";若是映射再安全读取 method 并用
COMPRESSION_SUFFIXES.get(method, ".pkl") 返回结果。

@leavessterleavesster changed the title fix: use dict mapping for compression_suffix instead of if-elif chainfix(oocana): use dict mapping for compression_suffix instead of if-elif chainJan 31, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@leavesster
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
fix(oocana): use dict mapping for compression_suffix instead of if-elif chain by leavesster · Pull Request #457 · oomol/oocana-python · GitHub
Skip to content

fix(oocana): use dict mapping for compression_suffix instead of if-elif chain - #457

Open
leavesster wants to merge 1 commit into
mainfrom
fix/compression-suffix-dict-mapping
Open

fix(oocana): use dict mapping for compression_suffix instead of if-elif chain#457
leavesster wants to merge 1 commit into
mainfrom
fix/compression-suffix-dict-mapping

Conversation

@leavesster

Copy link
Copy Markdown
Contributor

Summary

  • Replace if-elif chain with COMPRESSION_SUFFIXES dictionary mapping
  • Use .get() to safely handle missing keys
  • Add unit tests for compression_suffix() function

Problem

Original code had long if-elif chain with potential KeyError risk:

ifcompression["method"] =="zip":
return".zip"elifcompression["method"] =="gzip":
return".gz"# ... 6 more branches

Solution

COMPRESSION_SUFFIXES= {
"zip": ".zip", "gzip": ".gz", "bz2": ".bz2",
"zstd": ".zst", "xz": ".xz", "tar": ".tar",
}
defcompression_suffix(context):
compression=compression_options(context)
ifcompressionisNone:
return".pkl"returnCOMPRESSION_SUFFIXES.get(compression.get("method"), ".pkl")

Test Plan

  • Added tests/test_serialization.py with coverage for all compression methods
  • All existing tests pass

Replace if-elif chain with a dictionary mapping for cleaner code.
Also fix potential KeyError by using .get() method.
Changes:
- Add COMPRESSION_SUFFIXES constant mapping method to suffix
- Use .get() to safely access 'method' key
- Add comprehensive unit tests for compression_suffix
CopilotAI review requested due to automatic review settings January 31, 2026 09:27
@coderabbitai

coderabbitaiBot commented Jan 31, 2026

Copy link
Copy Markdown

总体说明

本次变更通过引入 COMPRESSION_SUFFIXES 映射表,将压缩后缀逻辑从多个条件分支重构为单一映射查询机制。同时新增了一个全面的测试模块,用于验证压缩后缀和压缩选项在各种场景下的行为。

变更内容

文件群组 / 文件路径变更摘要
核心序列化重构
oocana/oocana/serialization.py
引入 COMPRESSION_SUFFIXES 常量映射压缩方法与文件后缀;重构 compression_suffix 函数,将多个条件分支替换为映射查询,默认返回 ".pkl";移除显式的按方法分发逻辑。
测试套件新增
oocana/tests/test_serialization.py
新增 164 行测试代码,覆盖 compression_suffix 函数在多种压缩方法(zip、gzip、bz2、zstd、xz、tar)及边界情况下的行为;测试 compression_options 函数处理缺失、有效和无效 JSON 文件的场景;使用临时目录和 mock 上下文完成测试隔离。

代码审查工作量估算

🎯 3 (中等复杂度) | ⏱️ ~20 分钟

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description check✅ PassedPR description is well-related to the changeset, providing clear problem statement, solution details with code examples, and test plan that align with the actual changes made.
Title check✅ PassedThe pull request title follows the required format with type(scope): subject pattern, clearly describing the main refactoring change from if-elif chain to dict mapping.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Refactors compression_suffix() to use a dictionary mapping for compression method → file suffix (instead of an if/elif chain) and adds unit tests to validate behavior across supported and edge-case methods.

Changes:

  • Introduced COMPRESSION_SUFFIXES mapping and updated compression_suffix() to use .get()-based lookup with defaults.
  • Updated compression_suffix() docstring to match actual default behavior (.pkl).
  • Added unit tests covering supported methods and fallback behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

FileDescription
oocana/oocana/serialization.pyReplaces if/elif suffix selection with a mapping constant and simplified lookup logic.
oocana/tests/test_serialization.pyAdds tests for compression_suffix() and compression_options() behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -0,0 +1,164 @@
import unittest
from unittest.mock import MagicMock, patch

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

patch is imported but never used in this test module; removing it avoids lint warnings and keeps the test file tidy.

Suggested change
fromunittest.mockimportMagicMock, patch
fromunittest.mockimportMagicMock

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +93
method = compression.get("method")
if method is None:

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

COMPRESSION_SUFFIXES.get(method, ...) assumes method is a hashable key. If the options file contains a non-string (e.g., a list/dict from valid-but-unexpected JSON), this will raise TypeError and crash, whereas the previous if/elif chain would safely fall back. Consider guarding with isinstance(method, str) (and/or isinstance(compression, dict)) before doing the dict lookup, otherwise return the default suffix.

Suggested change
method=compression.get("method")
ifmethodisNone:
# Ensure we have a dictionary before accessing keys. Malformed or unexpected
# JSON in the options file may result in a non-dict value here.
ifnotisinstance(compression, dict):
return".pkl"
method=compression.get("method")
# Guard against non-string (and thus potentially unhashable) methods.
ifnotisinstance(method, str):

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +80
# Mapping from compression method to file suffix
COMPRESSION_SUFFIXES = {
"zip": ".zip",
"gzip": ".gz",
"bz2": ".bz2",
"zstd": ".zst",
"xz": ".xz",
"tar": ".tar",
}

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

The compression methods are now duplicated in three places (SUPPORTED_COMPRESSION_METHODS, the CompressionOptions Literal, and COMPRESSION_SUFFIXES). This can drift over time (e.g., a method added to SUPPORTED_COMPRESSION_METHODS but missing here would silently fall back to .pkl). Consider making one source of truth (e.g., derive SUPPORTED_COMPRESSION_METHODS from COMPRESSION_SUFFIXES.keys()), and keep the type Literal in sync with that constant.

Copilot uses AI. Check for mistakes.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@oocana/oocana/serialization.py`:
- Around line 87-96: compression_options 返回的 compression 可能不是 dict,从而在
compression.get("method") 处抛出 AttributeError;在函数/片段中(使用
compression_options、compression、method、COMPRESSION_SUFFIXES 的地方)先对 compression
做类型保护(例如 isinstance(compression, dict) 或
collections.abc.Mapping),若不是合适的映射类型则直接返回默认后缀 ".pkl";若是映射再安全读取 method 并用
COMPRESSION_SUFFIXES.get(method, ".pkl") 返回结果。
🧹 Nitpick comments (2)
oocana/oocana/serialization.py (1)

72-80: 避免与 SUPPORTED_COMPRESSION_METHODS 重复来源,防止漂移
目前方法列表在 SUPPORTED_COMPRESSION_METHODSCOMPRESSION_SUFFIXES 中重复维护,后续新增/删除方法容易不同步。建议以 COMPRESSION_SUFFIXES 作为单一来源生成列表。若该常量希望对外公开,也可同步加入 __all__

🔧 参考改法(统一来源)
-SUPPORTED_COMPRESSION_METHODS = ["zip", "gzip", "bz2", "zstd", "xz", "tar"]+# Mapping from compression method to file suffix+COMPRESSION_SUFFIXES = {+ "zip": ".zip",+ "gzip": ".gz",+ "bz2": ".bz2",+ "zstd": ".zst",+ "xz": ".xz",+ "tar": ".tar",+}+SUPPORTED_COMPRESSION_METHODS = list(COMPRESSION_SUFFIXES.keys())
oocana/tests/test_serialization.py (1)

29-119: 建议参数化这些重复的后缀测试
zip/gzip/bz2/zstd/xz/tar 的测试结构完全一致,后续维护成本偏高。可以用 subTest + 参数表合并为一个测试。

♻️ 参考改法(参数化)
- def test_compression_suffix_zip(self):- """Test compression suffix for zip method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "zip"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".zip")-- def test_compression_suffix_gzip(self):- """Test compression suffix for gzip method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "gzip"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".gz")-- ...-- def test_compression_suffix_tar(self):- """Test compression suffix for tar method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "tar"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".tar")+ def test_compression_suffix_methods(self):+ """Test compression suffix for supported methods."""+ from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE++ cases = {+ "zip": ".zip",+ "gzip": ".gz",+ "bz2": ".bz2",+ "zstd": ".zst",+ "xz": ".xz",+ "tar": ".tar",+ }+ for method, expected in cases.items():+ with self.subTest(method=method):+ with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:+ json.dump({"method": method}, f)+ self.assertEqual(compression_suffix(self.mock_context), expected)

Comment on lines 87 to +96
compression = compression_options(context)

if compression is None or compression["method"] is None:
if compression is None:
return ".pkl"

method = compression["method"]
if method == "zip":
return ".zip"
elif method == "gzip":
return ".gz"
elif method == "bz2":
return ".bz2"
elif method == "zstd":
return ".zst"
elif method == "xz":
return ".xz"
elif method == "tar":
return ".tar"
else:
return ".pkl" # Default case if method is not recognized No newline at end of file

method = compression.get("method")
if method is None:
return ".pkl"

return COMPRESSION_SUFFIXES.get(method, ".pkl") No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

防止压缩配置为非 dict 时触发 AttributeError
compression_options 读取的是任意 JSON,若文件内容为合法但非 dict(如字符串/列表),compression.get(...) 会直接报错。建议加类型保护并回退到默认后缀。

🛡️ 参考修复
 compression = compression_options(context)
- if compression is None:+ if not isinstance(compression, dict):
return ".pkl"
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
compression=compression_options(context)
ifcompressionisNoneorcompression["method"] isNone:
ifcompressionisNone:
return".pkl"
method=compression["method"]
ifmethod=="zip":
return".zip"
elifmethod=="gzip":
return".gz"
elifmethod=="bz2":
return".bz2"
elifmethod=="zstd":
return".zst"
elifmethod=="xz":
return".xz"
elifmethod=="tar":
return".tar"
else:
return".pkl"# Default case if method is not recognized
\ Nonewlineatendoffile
method=compression.get("method")
ifmethodisNone:
return".pkl"
returnCOMPRESSION_SUFFIXES.get(method, ".pkl")
compression=compression_options(context)
ifnotisinstance(compression, dict):
return".pkl"
method=compression.get("method")
ifmethodisNone:
return".pkl"
returnCOMPRESSION_SUFFIXES.get(method, ".pkl")
🤖 Prompt for AI Agents
In `@oocana/oocana/serialization.py` around lines 87 - 96, compression_options 返回的
compression 可能不是 dict,从而在 compression.get("method") 处抛出
AttributeError;在函数/片段中(使用
compression_options、compression、method、COMPRESSION_SUFFIXES 的地方)先对 compression
做类型保护(例如 isinstance(compression, dict) 或
collections.abc.Mapping),若不是合适的映射类型则直接返回默认后缀 ".pkl";若是映射再安全读取 method 并用
COMPRESSION_SUFFIXES.get(method, ".pkl") 返回结果。

@leavessterleavesster changed the title fix: use dict mapping for compression_suffix instead of if-elif chainfix(oocana): use dict mapping for compression_suffix instead of if-elif chainJan 31, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@leavesster
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(oocana): use dict mapping for compression_suffix instead of if-elif chain by leavesster · Pull Request #457 · oomol/oocana-python · GitHub
Skip to content

fix(oocana): use dict mapping for compression_suffix instead of if-elif chain - #457

Open
leavesster wants to merge 1 commit into
mainfrom
fix/compression-suffix-dict-mapping
Open

fix(oocana): use dict mapping for compression_suffix instead of if-elif chain#457
leavesster wants to merge 1 commit into
mainfrom
fix/compression-suffix-dict-mapping

Conversation

@leavesster

Copy link
Copy Markdown
Contributor

Summary

  • Replace if-elif chain with COMPRESSION_SUFFIXES dictionary mapping
  • Use .get() to safely handle missing keys
  • Add unit tests for compression_suffix() function

Problem

Original code had long if-elif chain with potential KeyError risk:

ifcompression["method"] =="zip":
return".zip"elifcompression["method"] =="gzip":
return".gz"# ... 6 more branches

Solution

COMPRESSION_SUFFIXES= {
"zip": ".zip", "gzip": ".gz", "bz2": ".bz2",
"zstd": ".zst", "xz": ".xz", "tar": ".tar",
}
defcompression_suffix(context):
compression=compression_options(context)
ifcompressionisNone:
return".pkl"returnCOMPRESSION_SUFFIXES.get(compression.get("method"), ".pkl")

Test Plan

  • Added tests/test_serialization.py with coverage for all compression methods
  • All existing tests pass

Replace if-elif chain with a dictionary mapping for cleaner code.
Also fix potential KeyError by using .get() method.
Changes:
- Add COMPRESSION_SUFFIXES constant mapping method to suffix
- Use .get() to safely access 'method' key
- Add comprehensive unit tests for compression_suffix
CopilotAI review requested due to automatic review settings January 31, 2026 09:27
@coderabbitai

coderabbitaiBot commented Jan 31, 2026

Copy link
Copy Markdown

总体说明

本次变更通过引入 COMPRESSION_SUFFIXES 映射表,将压缩后缀逻辑从多个条件分支重构为单一映射查询机制。同时新增了一个全面的测试模块,用于验证压缩后缀和压缩选项在各种场景下的行为。

变更内容

文件群组 / 文件路径变更摘要
核心序列化重构
oocana/oocana/serialization.py
引入 COMPRESSION_SUFFIXES 常量映射压缩方法与文件后缀;重构 compression_suffix 函数,将多个条件分支替换为映射查询,默认返回 ".pkl";移除显式的按方法分发逻辑。
测试套件新增
oocana/tests/test_serialization.py
新增 164 行测试代码,覆盖 compression_suffix 函数在多种压缩方法(zip、gzip、bz2、zstd、xz、tar)及边界情况下的行为;测试 compression_options 函数处理缺失、有效和无效 JSON 文件的场景;使用临时目录和 mock 上下文完成测试隔离。

代码审查工作量估算

🎯 3 (中等复杂度) | ⏱️ ~20 分钟

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description check✅ PassedPR description is well-related to the changeset, providing clear problem statement, solution details with code examples, and test plan that align with the actual changes made.
Title check✅ PassedThe pull request title follows the required format with type(scope): subject pattern, clearly describing the main refactoring change from if-elif chain to dict mapping.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Refactors compression_suffix() to use a dictionary mapping for compression method → file suffix (instead of an if/elif chain) and adds unit tests to validate behavior across supported and edge-case methods.

Changes:

  • Introduced COMPRESSION_SUFFIXES mapping and updated compression_suffix() to use .get()-based lookup with defaults.
  • Updated compression_suffix() docstring to match actual default behavior (.pkl).
  • Added unit tests covering supported methods and fallback behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

FileDescription
oocana/oocana/serialization.pyReplaces if/elif suffix selection with a mapping constant and simplified lookup logic.
oocana/tests/test_serialization.pyAdds tests for compression_suffix() and compression_options() behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -0,0 +1,164 @@
import unittest
from unittest.mock import MagicMock, patch

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

patch is imported but never used in this test module; removing it avoids lint warnings and keeps the test file tidy.

Suggested change
fromunittest.mockimportMagicMock, patch
fromunittest.mockimportMagicMock

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +93
method = compression.get("method")
if method is None:

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

COMPRESSION_SUFFIXES.get(method, ...) assumes method is a hashable key. If the options file contains a non-string (e.g., a list/dict from valid-but-unexpected JSON), this will raise TypeError and crash, whereas the previous if/elif chain would safely fall back. Consider guarding with isinstance(method, str) (and/or isinstance(compression, dict)) before doing the dict lookup, otherwise return the default suffix.

Suggested change
method=compression.get("method")
ifmethodisNone:
# Ensure we have a dictionary before accessing keys. Malformed or unexpected
# JSON in the options file may result in a non-dict value here.
ifnotisinstance(compression, dict):
return".pkl"
method=compression.get("method")
# Guard against non-string (and thus potentially unhashable) methods.
ifnotisinstance(method, str):

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +80
# Mapping from compression method to file suffix
COMPRESSION_SUFFIXES = {
"zip": ".zip",
"gzip": ".gz",
"bz2": ".bz2",
"zstd": ".zst",
"xz": ".xz",
"tar": ".tar",
}

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

The compression methods are now duplicated in three places (SUPPORTED_COMPRESSION_METHODS, the CompressionOptions Literal, and COMPRESSION_SUFFIXES). This can drift over time (e.g., a method added to SUPPORTED_COMPRESSION_METHODS but missing here would silently fall back to .pkl). Consider making one source of truth (e.g., derive SUPPORTED_COMPRESSION_METHODS from COMPRESSION_SUFFIXES.keys()), and keep the type Literal in sync with that constant.

Copilot uses AI. Check for mistakes.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@oocana/oocana/serialization.py`:
- Around line 87-96: compression_options 返回的 compression 可能不是 dict,从而在
compression.get("method") 处抛出 AttributeError;在函数/片段中(使用
compression_options、compression、method、COMPRESSION_SUFFIXES 的地方)先对 compression
做类型保护(例如 isinstance(compression, dict) 或
collections.abc.Mapping),若不是合适的映射类型则直接返回默认后缀 ".pkl";若是映射再安全读取 method 并用
COMPRESSION_SUFFIXES.get(method, ".pkl") 返回结果。
🧹 Nitpick comments (2)
oocana/oocana/serialization.py (1)

72-80: 避免与 SUPPORTED_COMPRESSION_METHODS 重复来源,防止漂移
目前方法列表在 SUPPORTED_COMPRESSION_METHODSCOMPRESSION_SUFFIXES 中重复维护,后续新增/删除方法容易不同步。建议以 COMPRESSION_SUFFIXES 作为单一来源生成列表。若该常量希望对外公开,也可同步加入 __all__

🔧 参考改法(统一来源)
-SUPPORTED_COMPRESSION_METHODS = ["zip", "gzip", "bz2", "zstd", "xz", "tar"]+# Mapping from compression method to file suffix+COMPRESSION_SUFFIXES = {+ "zip": ".zip",+ "gzip": ".gz",+ "bz2": ".bz2",+ "zstd": ".zst",+ "xz": ".xz",+ "tar": ".tar",+}+SUPPORTED_COMPRESSION_METHODS = list(COMPRESSION_SUFFIXES.keys())
oocana/tests/test_serialization.py (1)

29-119: 建议参数化这些重复的后缀测试
zip/gzip/bz2/zstd/xz/tar 的测试结构完全一致,后续维护成本偏高。可以用 subTest + 参数表合并为一个测试。

♻️ 参考改法(参数化)
- def test_compression_suffix_zip(self):- """Test compression suffix for zip method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "zip"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".zip")-- def test_compression_suffix_gzip(self):- """Test compression suffix for gzip method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "gzip"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".gz")-- ...-- def test_compression_suffix_tar(self):- """Test compression suffix for tar method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "tar"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".tar")+ def test_compression_suffix_methods(self):+ """Test compression suffix for supported methods."""+ from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE++ cases = {+ "zip": ".zip",+ "gzip": ".gz",+ "bz2": ".bz2",+ "zstd": ".zst",+ "xz": ".xz",+ "tar": ".tar",+ }+ for method, expected in cases.items():+ with self.subTest(method=method):+ with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:+ json.dump({"method": method}, f)+ self.assertEqual(compression_suffix(self.mock_context), expected)

Comment on lines 87 to +96
compression = compression_options(context)

if compression is None or compression["method"] is None:
if compression is None:
return ".pkl"

method = compression["method"]
if method == "zip":
return ".zip"
elif method == "gzip":
return ".gz"
elif method == "bz2":
return ".bz2"
elif method == "zstd":
return ".zst"
elif method == "xz":
return ".xz"
elif method == "tar":
return ".tar"
else:
return ".pkl" # Default case if method is not recognized No newline at end of file

method = compression.get("method")
if method is None:
return ".pkl"

return COMPRESSION_SUFFIXES.get(method, ".pkl") No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

防止压缩配置为非 dict 时触发 AttributeError
compression_options 读取的是任意 JSON,若文件内容为合法但非 dict(如字符串/列表),compression.get(...) 会直接报错。建议加类型保护并回退到默认后缀。

🛡️ 参考修复
 compression = compression_options(context)
- if compression is None:+ if not isinstance(compression, dict):
return ".pkl"
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
compression=compression_options(context)
ifcompressionisNoneorcompression["method"] isNone:
ifcompressionisNone:
return".pkl"
method=compression["method"]
ifmethod=="zip":
return".zip"
elifmethod=="gzip":
return".gz"
elifmethod=="bz2":
return".bz2"
elifmethod=="zstd":
return".zst"
elifmethod=="xz":
return".xz"
elifmethod=="tar":
return".tar"
else:
return".pkl"# Default case if method is not recognized
\ Nonewlineatendoffile
method=compression.get("method")
ifmethodisNone:
return".pkl"
returnCOMPRESSION_SUFFIXES.get(method, ".pkl")
compression=compression_options(context)
ifnotisinstance(compression, dict):
return".pkl"
method=compression.get("method")
ifmethodisNone:
return".pkl"
returnCOMPRESSION_SUFFIXES.get(method, ".pkl")
🤖 Prompt for AI Agents
In `@oocana/oocana/serialization.py` around lines 87 - 96, compression_options 返回的
compression 可能不是 dict,从而在 compression.get("method") 处抛出
AttributeError;在函数/片段中(使用
compression_options、compression、method、COMPRESSION_SUFFIXES 的地方)先对 compression
做类型保护(例如 isinstance(compression, dict) 或
collections.abc.Mapping),若不是合适的映射类型则直接返回默认后缀 ".pkl";若是映射再安全读取 method 并用
COMPRESSION_SUFFIXES.get(method, ".pkl") 返回结果。

@leavessterleavesster changed the title fix: use dict mapping for compression_suffix instead of if-elif chainfix(oocana): use dict mapping for compression_suffix instead of if-elif chainJan 31, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@leavesster
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(oocana): use dict mapping for compression_suffix instead of if-elif chain by leavesster · Pull Request #457 · oomol/oocana-python · GitHub
Skip to content

fix(oocana): use dict mapping for compression_suffix instead of if-elif chain - #457

Open
leavesster wants to merge 1 commit into
mainfrom
fix/compression-suffix-dict-mapping
Open

fix(oocana): use dict mapping for compression_suffix instead of if-elif chain#457
leavesster wants to merge 1 commit into
mainfrom
fix/compression-suffix-dict-mapping

Conversation

@leavesster

Copy link
Copy Markdown
Contributor

Summary

  • Replace if-elif chain with COMPRESSION_SUFFIXES dictionary mapping
  • Use .get() to safely handle missing keys
  • Add unit tests for compression_suffix() function

Problem

Original code had long if-elif chain with potential KeyError risk:

ifcompression["method"] =="zip":
return".zip"elifcompression["method"] =="gzip":
return".gz"# ... 6 more branches

Solution

COMPRESSION_SUFFIXES= {
"zip": ".zip", "gzip": ".gz", "bz2": ".bz2",
"zstd": ".zst", "xz": ".xz", "tar": ".tar",
}
defcompression_suffix(context):
compression=compression_options(context)
ifcompressionisNone:
return".pkl"returnCOMPRESSION_SUFFIXES.get(compression.get("method"), ".pkl")

Test Plan

  • Added tests/test_serialization.py with coverage for all compression methods
  • All existing tests pass

Replace if-elif chain with a dictionary mapping for cleaner code.
Also fix potential KeyError by using .get() method.
Changes:
- Add COMPRESSION_SUFFIXES constant mapping method to suffix
- Use .get() to safely access 'method' key
- Add comprehensive unit tests for compression_suffix
CopilotAI review requested due to automatic review settings January 31, 2026 09:27
@coderabbitai

coderabbitaiBot commented Jan 31, 2026

Copy link
Copy Markdown

总体说明

本次变更通过引入 COMPRESSION_SUFFIXES 映射表,将压缩后缀逻辑从多个条件分支重构为单一映射查询机制。同时新增了一个全面的测试模块,用于验证压缩后缀和压缩选项在各种场景下的行为。

变更内容

文件群组 / 文件路径变更摘要
核心序列化重构
oocana/oocana/serialization.py
引入 COMPRESSION_SUFFIXES 常量映射压缩方法与文件后缀;重构 compression_suffix 函数,将多个条件分支替换为映射查询,默认返回 ".pkl";移除显式的按方法分发逻辑。
测试套件新增
oocana/tests/test_serialization.py
新增 164 行测试代码,覆盖 compression_suffix 函数在多种压缩方法(zip、gzip、bz2、zstd、xz、tar)及边界情况下的行为;测试 compression_options 函数处理缺失、有效和无效 JSON 文件的场景;使用临时目录和 mock 上下文完成测试隔离。

代码审查工作量估算

🎯 3 (中等复杂度) | ⏱️ ~20 分钟

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description check✅ PassedPR description is well-related to the changeset, providing clear problem statement, solution details with code examples, and test plan that align with the actual changes made.
Title check✅ PassedThe pull request title follows the required format with type(scope): subject pattern, clearly describing the main refactoring change from if-elif chain to dict mapping.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Refactors compression_suffix() to use a dictionary mapping for compression method → file suffix (instead of an if/elif chain) and adds unit tests to validate behavior across supported and edge-case methods.

Changes:

  • Introduced COMPRESSION_SUFFIXES mapping and updated compression_suffix() to use .get()-based lookup with defaults.
  • Updated compression_suffix() docstring to match actual default behavior (.pkl).
  • Added unit tests covering supported methods and fallback behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

FileDescription
oocana/oocana/serialization.pyReplaces if/elif suffix selection with a mapping constant and simplified lookup logic.
oocana/tests/test_serialization.pyAdds tests for compression_suffix() and compression_options() behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -0,0 +1,164 @@
import unittest
from unittest.mock import MagicMock, patch

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

patch is imported but never used in this test module; removing it avoids lint warnings and keeps the test file tidy.

Suggested change
fromunittest.mockimportMagicMock, patch
fromunittest.mockimportMagicMock

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +93
method = compression.get("method")
if method is None:

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

COMPRESSION_SUFFIXES.get(method, ...) assumes method is a hashable key. If the options file contains a non-string (e.g., a list/dict from valid-but-unexpected JSON), this will raise TypeError and crash, whereas the previous if/elif chain would safely fall back. Consider guarding with isinstance(method, str) (and/or isinstance(compression, dict)) before doing the dict lookup, otherwise return the default suffix.

Suggested change
method=compression.get("method")
ifmethodisNone:
# Ensure we have a dictionary before accessing keys. Malformed or unexpected
# JSON in the options file may result in a non-dict value here.
ifnotisinstance(compression, dict):
return".pkl"
method=compression.get("method")
# Guard against non-string (and thus potentially unhashable) methods.
ifnotisinstance(method, str):

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +80
# Mapping from compression method to file suffix
COMPRESSION_SUFFIXES = {
"zip": ".zip",
"gzip": ".gz",
"bz2": ".bz2",
"zstd": ".zst",
"xz": ".xz",
"tar": ".tar",
}

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

The compression methods are now duplicated in three places (SUPPORTED_COMPRESSION_METHODS, the CompressionOptions Literal, and COMPRESSION_SUFFIXES). This can drift over time (e.g., a method added to SUPPORTED_COMPRESSION_METHODS but missing here would silently fall back to .pkl). Consider making one source of truth (e.g., derive SUPPORTED_COMPRESSION_METHODS from COMPRESSION_SUFFIXES.keys()), and keep the type Literal in sync with that constant.

Copilot uses AI. Check for mistakes.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@oocana/oocana/serialization.py`:
- Around line 87-96: compression_options 返回的 compression 可能不是 dict,从而在
compression.get("method") 处抛出 AttributeError;在函数/片段中(使用
compression_options、compression、method、COMPRESSION_SUFFIXES 的地方)先对 compression
做类型保护(例如 isinstance(compression, dict) 或
collections.abc.Mapping),若不是合适的映射类型则直接返回默认后缀 ".pkl";若是映射再安全读取 method 并用
COMPRESSION_SUFFIXES.get(method, ".pkl") 返回结果。
🧹 Nitpick comments (2)
oocana/oocana/serialization.py (1)

72-80: 避免与 SUPPORTED_COMPRESSION_METHODS 重复来源,防止漂移
目前方法列表在 SUPPORTED_COMPRESSION_METHODSCOMPRESSION_SUFFIXES 中重复维护,后续新增/删除方法容易不同步。建议以 COMPRESSION_SUFFIXES 作为单一来源生成列表。若该常量希望对外公开,也可同步加入 __all__

🔧 参考改法(统一来源)
-SUPPORTED_COMPRESSION_METHODS = ["zip", "gzip", "bz2", "zstd", "xz", "tar"]+# Mapping from compression method to file suffix+COMPRESSION_SUFFIXES = {+ "zip": ".zip",+ "gzip": ".gz",+ "bz2": ".bz2",+ "zstd": ".zst",+ "xz": ".xz",+ "tar": ".tar",+}+SUPPORTED_COMPRESSION_METHODS = list(COMPRESSION_SUFFIXES.keys())
oocana/tests/test_serialization.py (1)

29-119: 建议参数化这些重复的后缀测试
zip/gzip/bz2/zstd/xz/tar 的测试结构完全一致,后续维护成本偏高。可以用 subTest + 参数表合并为一个测试。

♻️ 参考改法(参数化)
- def test_compression_suffix_zip(self):- """Test compression suffix for zip method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "zip"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".zip")-- def test_compression_suffix_gzip(self):- """Test compression suffix for gzip method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "gzip"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".gz")-- ...-- def test_compression_suffix_tar(self):- """Test compression suffix for tar method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "tar"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".tar")+ def test_compression_suffix_methods(self):+ """Test compression suffix for supported methods."""+ from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE++ cases = {+ "zip": ".zip",+ "gzip": ".gz",+ "bz2": ".bz2",+ "zstd": ".zst",+ "xz": ".xz",+ "tar": ".tar",+ }+ for method, expected in cases.items():+ with self.subTest(method=method):+ with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:+ json.dump({"method": method}, f)+ self.assertEqual(compression_suffix(self.mock_context), expected)

Comment on lines 87 to +96
compression = compression_options(context)

if compression is None or compression["method"] is None:
if compression is None:
return ".pkl"

method = compression["method"]
if method == "zip":
return ".zip"
elif method == "gzip":
return ".gz"
elif method == "bz2":
return ".bz2"
elif method == "zstd":
return ".zst"
elif method == "xz":
return ".xz"
elif method == "tar":
return ".tar"
else:
return ".pkl" # Default case if method is not recognized No newline at end of file

method = compression.get("method")
if method is None:
return ".pkl"

return COMPRESSION_SUFFIXES.get(method, ".pkl") No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

防止压缩配置为非 dict 时触发 AttributeError
compression_options 读取的是任意 JSON,若文件内容为合法但非 dict(如字符串/列表),compression.get(...) 会直接报错。建议加类型保护并回退到默认后缀。

🛡️ 参考修复
 compression = compression_options(context)
- if compression is None:+ if not isinstance(compression, dict):
return ".pkl"
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
compression=compression_options(context)
ifcompressionisNoneorcompression["method"] isNone:
ifcompressionisNone:
return".pkl"
method=compression["method"]
ifmethod=="zip":
return".zip"
elifmethod=="gzip":
return".gz"
elifmethod=="bz2":
return".bz2"
elifmethod=="zstd":
return".zst"
elifmethod=="xz":
return".xz"
elifmethod=="tar":
return".tar"
else:
return".pkl"# Default case if method is not recognized
\ Nonewlineatendoffile
method=compression.get("method")
ifmethodisNone:
return".pkl"
returnCOMPRESSION_SUFFIXES.get(method, ".pkl")
compression=compression_options(context)
ifnotisinstance(compression, dict):
return".pkl"
method=compression.get("method")
ifmethodisNone:
return".pkl"
returnCOMPRESSION_SUFFIXES.get(method, ".pkl")
🤖 Prompt for AI Agents
In `@oocana/oocana/serialization.py` around lines 87 - 96, compression_options 返回的
compression 可能不是 dict,从而在 compression.get("method") 处抛出
AttributeError;在函数/片段中(使用
compression_options、compression、method、COMPRESSION_SUFFIXES 的地方)先对 compression
做类型保护(例如 isinstance(compression, dict) 或
collections.abc.Mapping),若不是合适的映射类型则直接返回默认后缀 ".pkl";若是映射再安全读取 method 并用
COMPRESSION_SUFFIXES.get(method, ".pkl") 返回结果。

@leavessterleavesster changed the title fix: use dict mapping for compression_suffix instead of if-elif chainfix(oocana): use dict mapping for compression_suffix instead of if-elif chainJan 31, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@leavesster
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' fix(oocana): use dict mapping for compression_suffix instead of if-elif chain by leavesster · Pull Request #457 · oomol/oocana-python · GitHub
Skip to content

fix(oocana): use dict mapping for compression_suffix instead of if-elif chain - #457

Open
leavesster wants to merge 1 commit into
mainfrom
fix/compression-suffix-dict-mapping
Open

fix(oocana): use dict mapping for compression_suffix instead of if-elif chain#457
leavesster wants to merge 1 commit into
mainfrom
fix/compression-suffix-dict-mapping

Conversation

@leavesster

Copy link
Copy Markdown
Contributor

Summary

  • Replace if-elif chain with COMPRESSION_SUFFIXES dictionary mapping
  • Use .get() to safely handle missing keys
  • Add unit tests for compression_suffix() function

Problem

Original code had long if-elif chain with potential KeyError risk:

ifcompression["method"] =="zip":
return".zip"elifcompression["method"] =="gzip":
return".gz"# ... 6 more branches

Solution

COMPRESSION_SUFFIXES= {
"zip": ".zip", "gzip": ".gz", "bz2": ".bz2",
"zstd": ".zst", "xz": ".xz", "tar": ".tar",
}
defcompression_suffix(context):
compression=compression_options(context)
ifcompressionisNone:
return".pkl"returnCOMPRESSION_SUFFIXES.get(compression.get("method"), ".pkl")

Test Plan

  • Added tests/test_serialization.py with coverage for all compression methods
  • All existing tests pass

Replace if-elif chain with a dictionary mapping for cleaner code.
Also fix potential KeyError by using .get() method.
Changes:
- Add COMPRESSION_SUFFIXES constant mapping method to suffix
- Use .get() to safely access 'method' key
- Add comprehensive unit tests for compression_suffix
CopilotAI review requested due to automatic review settings January 31, 2026 09:27
@coderabbitai

coderabbitaiBot commented Jan 31, 2026

Copy link
Copy Markdown

总体说明

本次变更通过引入 COMPRESSION_SUFFIXES 映射表,将压缩后缀逻辑从多个条件分支重构为单一映射查询机制。同时新增了一个全面的测试模块,用于验证压缩后缀和压缩选项在各种场景下的行为。

变更内容

文件群组 / 文件路径变更摘要
核心序列化重构
oocana/oocana/serialization.py
引入 COMPRESSION_SUFFIXES 常量映射压缩方法与文件后缀;重构 compression_suffix 函数,将多个条件分支替换为映射查询,默认返回 ".pkl";移除显式的按方法分发逻辑。
测试套件新增
oocana/tests/test_serialization.py
新增 164 行测试代码,覆盖 compression_suffix 函数在多种压缩方法(zip、gzip、bz2、zstd、xz、tar)及边界情况下的行为;测试 compression_options 函数处理缺失、有效和无效 JSON 文件的场景;使用临时目录和 mock 上下文完成测试隔离。

代码审查工作量估算

🎯 3 (中等复杂度) | ⏱️ ~20 分钟

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description check✅ PassedPR description is well-related to the changeset, providing clear problem statement, solution details with code examples, and test plan that align with the actual changes made.
Title check✅ PassedThe pull request title follows the required format with type(scope): subject pattern, clearly describing the main refactoring change from if-elif chain to dict mapping.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Refactors compression_suffix() to use a dictionary mapping for compression method → file suffix (instead of an if/elif chain) and adds unit tests to validate behavior across supported and edge-case methods.

Changes:

  • Introduced COMPRESSION_SUFFIXES mapping and updated compression_suffix() to use .get()-based lookup with defaults.
  • Updated compression_suffix() docstring to match actual default behavior (.pkl).
  • Added unit tests covering supported methods and fallback behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

FileDescription
oocana/oocana/serialization.pyReplaces if/elif suffix selection with a mapping constant and simplified lookup logic.
oocana/tests/test_serialization.pyAdds tests for compression_suffix() and compression_options() behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -0,0 +1,164 @@
import unittest
from unittest.mock import MagicMock, patch

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

patch is imported but never used in this test module; removing it avoids lint warnings and keeps the test file tidy.

Suggested change
fromunittest.mockimportMagicMock, patch
fromunittest.mockimportMagicMock

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +93
method = compression.get("method")
if method is None:

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

COMPRESSION_SUFFIXES.get(method, ...) assumes method is a hashable key. If the options file contains a non-string (e.g., a list/dict from valid-but-unexpected JSON), this will raise TypeError and crash, whereas the previous if/elif chain would safely fall back. Consider guarding with isinstance(method, str) (and/or isinstance(compression, dict)) before doing the dict lookup, otherwise return the default suffix.

Suggested change
method=compression.get("method")
ifmethodisNone:
# Ensure we have a dictionary before accessing keys. Malformed or unexpected
# JSON in the options file may result in a non-dict value here.
ifnotisinstance(compression, dict):
return".pkl"
method=compression.get("method")
# Guard against non-string (and thus potentially unhashable) methods.
ifnotisinstance(method, str):

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +80
# Mapping from compression method to file suffix
COMPRESSION_SUFFIXES = {
"zip": ".zip",
"gzip": ".gz",
"bz2": ".bz2",
"zstd": ".zst",
"xz": ".xz",
"tar": ".tar",
}

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

The compression methods are now duplicated in three places (SUPPORTED_COMPRESSION_METHODS, the CompressionOptions Literal, and COMPRESSION_SUFFIXES). This can drift over time (e.g., a method added to SUPPORTED_COMPRESSION_METHODS but missing here would silently fall back to .pkl). Consider making one source of truth (e.g., derive SUPPORTED_COMPRESSION_METHODS from COMPRESSION_SUFFIXES.keys()), and keep the type Literal in sync with that constant.

Copilot uses AI. Check for mistakes.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@oocana/oocana/serialization.py`:
- Around line 87-96: compression_options 返回的 compression 可能不是 dict,从而在
compression.get("method") 处抛出 AttributeError;在函数/片段中(使用
compression_options、compression、method、COMPRESSION_SUFFIXES 的地方)先对 compression
做类型保护(例如 isinstance(compression, dict) 或
collections.abc.Mapping),若不是合适的映射类型则直接返回默认后缀 ".pkl";若是映射再安全读取 method 并用
COMPRESSION_SUFFIXES.get(method, ".pkl") 返回结果。
🧹 Nitpick comments (2)
oocana/oocana/serialization.py (1)

72-80: 避免与 SUPPORTED_COMPRESSION_METHODS 重复来源,防止漂移
目前方法列表在 SUPPORTED_COMPRESSION_METHODSCOMPRESSION_SUFFIXES 中重复维护,后续新增/删除方法容易不同步。建议以 COMPRESSION_SUFFIXES 作为单一来源生成列表。若该常量希望对外公开,也可同步加入 __all__

🔧 参考改法(统一来源)
-SUPPORTED_COMPRESSION_METHODS = ["zip", "gzip", "bz2", "zstd", "xz", "tar"]+# Mapping from compression method to file suffix+COMPRESSION_SUFFIXES = {+ "zip": ".zip",+ "gzip": ".gz",+ "bz2": ".bz2",+ "zstd": ".zst",+ "xz": ".xz",+ "tar": ".tar",+}+SUPPORTED_COMPRESSION_METHODS = list(COMPRESSION_SUFFIXES.keys())
oocana/tests/test_serialization.py (1)

29-119: 建议参数化这些重复的后缀测试
zip/gzip/bz2/zstd/xz/tar 的测试结构完全一致,后续维护成本偏高。可以用 subTest + 参数表合并为一个测试。

♻️ 参考改法(参数化)
- def test_compression_suffix_zip(self):- """Test compression suffix for zip method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "zip"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".zip")-- def test_compression_suffix_gzip(self):- """Test compression suffix for gzip method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "gzip"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".gz")-- ...-- def test_compression_suffix_tar(self):- """Test compression suffix for tar method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "tar"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".tar")+ def test_compression_suffix_methods(self):+ """Test compression suffix for supported methods."""+ from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE++ cases = {+ "zip": ".zip",+ "gzip": ".gz",+ "bz2": ".bz2",+ "zstd": ".zst",+ "xz": ".xz",+ "tar": ".tar",+ }+ for method, expected in cases.items():+ with self.subTest(method=method):+ with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:+ json.dump({"method": method}, f)+ self.assertEqual(compression_suffix(self.mock_context), expected)

Comment on lines 87 to +96
compression = compression_options(context)

if compression is None or compression["method"] is None:
if compression is None:
return ".pkl"

method = compression["method"]
if method == "zip":
return ".zip"
elif method == "gzip":
return ".gz"
elif method == "bz2":
return ".bz2"
elif method == "zstd":
return ".zst"
elif method == "xz":
return ".xz"
elif method == "tar":
return ".tar"
else:
return ".pkl" # Default case if method is not recognized No newline at end of file

method = compression.get("method")
if method is None:
return ".pkl"

return COMPRESSION_SUFFIXES.get(method, ".pkl") No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

防止压缩配置为非 dict 时触发 AttributeError
compression_options 读取的是任意 JSON,若文件内容为合法但非 dict(如字符串/列表),compression.get(...) 会直接报错。建议加类型保护并回退到默认后缀。

🛡️ 参考修复
 compression = compression_options(context)
- if compression is None:+ if not isinstance(compression, dict):
return ".pkl"
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
compression=compression_options(context)
ifcompressionisNoneorcompression["method"] isNone:
ifcompressionisNone:
return".pkl"
method=compression["method"]
ifmethod=="zip":
return".zip"
elifmethod=="gzip":
return".gz"
elifmethod=="bz2":
return".bz2"
elifmethod=="zstd":
return".zst"
elifmethod=="xz":
return".xz"
elifmethod=="tar":
return".tar"
else:
return".pkl"# Default case if method is not recognized
\ Nonewlineatendoffile
method=compression.get("method")
ifmethodisNone:
return".pkl"
returnCOMPRESSION_SUFFIXES.get(method, ".pkl")
compression=compression_options(context)
ifnotisinstance(compression, dict):
return".pkl"
method=compression.get("method")
ifmethodisNone:
return".pkl"
returnCOMPRESSION_SUFFIXES.get(method, ".pkl")
🤖 Prompt for AI Agents
In `@oocana/oocana/serialization.py` around lines 87 - 96, compression_options 返回的
compression 可能不是 dict,从而在 compression.get("method") 处抛出
AttributeError;在函数/片段中(使用
compression_options、compression、method、COMPRESSION_SUFFIXES 的地方)先对 compression
做类型保护(例如 isinstance(compression, dict) 或
collections.abc.Mapping),若不是合适的映射类型则直接返回默认后缀 ".pkl";若是映射再安全读取 method 并用
COMPRESSION_SUFFIXES.get(method, ".pkl") 返回结果。

@leavessterleavesster changed the title fix: use dict mapping for compression_suffix instead of if-elif chainfix(oocana): use dict mapping for compression_suffix instead of if-elif chainJan 31, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@leavesster
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(oocana): use dict mapping for compression_suffix instead of if-elif chain by leavesster · Pull Request #457 · oomol/oocana-python · GitHub
Skip to content

fix(oocana): use dict mapping for compression_suffix instead of if-elif chain - #457

Open
leavesster wants to merge 1 commit into
mainfrom
fix/compression-suffix-dict-mapping
Open

fix(oocana): use dict mapping for compression_suffix instead of if-elif chain#457
leavesster wants to merge 1 commit into
mainfrom
fix/compression-suffix-dict-mapping

Conversation

@leavesster

Copy link
Copy Markdown
Contributor

Summary

  • Replace if-elif chain with COMPRESSION_SUFFIXES dictionary mapping
  • Use .get() to safely handle missing keys
  • Add unit tests for compression_suffix() function

Problem

Original code had long if-elif chain with potential KeyError risk:

ifcompression["method"] =="zip":
return".zip"elifcompression["method"] =="gzip":
return".gz"# ... 6 more branches

Solution

COMPRESSION_SUFFIXES= {
"zip": ".zip", "gzip": ".gz", "bz2": ".bz2",
"zstd": ".zst", "xz": ".xz", "tar": ".tar",
}
defcompression_suffix(context):
compression=compression_options(context)
ifcompressionisNone:
return".pkl"returnCOMPRESSION_SUFFIXES.get(compression.get("method"), ".pkl")

Test Plan

  • Added tests/test_serialization.py with coverage for all compression methods
  • All existing tests pass

Replace if-elif chain with a dictionary mapping for cleaner code.
Also fix potential KeyError by using .get() method.
Changes:
- Add COMPRESSION_SUFFIXES constant mapping method to suffix
- Use .get() to safely access 'method' key
- Add comprehensive unit tests for compression_suffix
CopilotAI review requested due to automatic review settings January 31, 2026 09:27
@coderabbitai

coderabbitaiBot commented Jan 31, 2026

Copy link
Copy Markdown

总体说明

本次变更通过引入 COMPRESSION_SUFFIXES 映射表,将压缩后缀逻辑从多个条件分支重构为单一映射查询机制。同时新增了一个全面的测试模块,用于验证压缩后缀和压缩选项在各种场景下的行为。

变更内容

文件群组 / 文件路径变更摘要
核心序列化重构
oocana/oocana/serialization.py
引入 COMPRESSION_SUFFIXES 常量映射压缩方法与文件后缀;重构 compression_suffix 函数,将多个条件分支替换为映射查询,默认返回 ".pkl";移除显式的按方法分发逻辑。
测试套件新增
oocana/tests/test_serialization.py
新增 164 行测试代码,覆盖 compression_suffix 函数在多种压缩方法(zip、gzip、bz2、zstd、xz、tar)及边界情况下的行为;测试 compression_options 函数处理缺失、有效和无效 JSON 文件的场景;使用临时目录和 mock 上下文完成测试隔离。

代码审查工作量估算

🎯 3 (中等复杂度) | ⏱️ ~20 分钟

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description check✅ PassedPR description is well-related to the changeset, providing clear problem statement, solution details with code examples, and test plan that align with the actual changes made.
Title check✅ PassedThe pull request title follows the required format with type(scope): subject pattern, clearly describing the main refactoring change from if-elif chain to dict mapping.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Refactors compression_suffix() to use a dictionary mapping for compression method → file suffix (instead of an if/elif chain) and adds unit tests to validate behavior across supported and edge-case methods.

Changes:

  • Introduced COMPRESSION_SUFFIXES mapping and updated compression_suffix() to use .get()-based lookup with defaults.
  • Updated compression_suffix() docstring to match actual default behavior (.pkl).
  • Added unit tests covering supported methods and fallback behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

FileDescription
oocana/oocana/serialization.pyReplaces if/elif suffix selection with a mapping constant and simplified lookup logic.
oocana/tests/test_serialization.pyAdds tests for compression_suffix() and compression_options() behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -0,0 +1,164 @@
import unittest
from unittest.mock import MagicMock, patch

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

patch is imported but never used in this test module; removing it avoids lint warnings and keeps the test file tidy.

Suggested change
fromunittest.mockimportMagicMock, patch
fromunittest.mockimportMagicMock

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +93
method = compression.get("method")
if method is None:

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

COMPRESSION_SUFFIXES.get(method, ...) assumes method is a hashable key. If the options file contains a non-string (e.g., a list/dict from valid-but-unexpected JSON), this will raise TypeError and crash, whereas the previous if/elif chain would safely fall back. Consider guarding with isinstance(method, str) (and/or isinstance(compression, dict)) before doing the dict lookup, otherwise return the default suffix.

Suggested change
method=compression.get("method")
ifmethodisNone:
# Ensure we have a dictionary before accessing keys. Malformed or unexpected
# JSON in the options file may result in a non-dict value here.
ifnotisinstance(compression, dict):
return".pkl"
method=compression.get("method")
# Guard against non-string (and thus potentially unhashable) methods.
ifnotisinstance(method, str):

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +80
# Mapping from compression method to file suffix
COMPRESSION_SUFFIXES = {
"zip": ".zip",
"gzip": ".gz",
"bz2": ".bz2",
"zstd": ".zst",
"xz": ".xz",
"tar": ".tar",
}

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

The compression methods are now duplicated in three places (SUPPORTED_COMPRESSION_METHODS, the CompressionOptions Literal, and COMPRESSION_SUFFIXES). This can drift over time (e.g., a method added to SUPPORTED_COMPRESSION_METHODS but missing here would silently fall back to .pkl). Consider making one source of truth (e.g., derive SUPPORTED_COMPRESSION_METHODS from COMPRESSION_SUFFIXES.keys()), and keep the type Literal in sync with that constant.

Copilot uses AI. Check for mistakes.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@oocana/oocana/serialization.py`:
- Around line 87-96: compression_options 返回的 compression 可能不是 dict,从而在
compression.get("method") 处抛出 AttributeError;在函数/片段中(使用
compression_options、compression、method、COMPRESSION_SUFFIXES 的地方)先对 compression
做类型保护(例如 isinstance(compression, dict) 或
collections.abc.Mapping),若不是合适的映射类型则直接返回默认后缀 ".pkl";若是映射再安全读取 method 并用
COMPRESSION_SUFFIXES.get(method, ".pkl") 返回结果。
🧹 Nitpick comments (2)
oocana/oocana/serialization.py (1)

72-80: 避免与 SUPPORTED_COMPRESSION_METHODS 重复来源,防止漂移
目前方法列表在 SUPPORTED_COMPRESSION_METHODSCOMPRESSION_SUFFIXES 中重复维护,后续新增/删除方法容易不同步。建议以 COMPRESSION_SUFFIXES 作为单一来源生成列表。若该常量希望对外公开,也可同步加入 __all__

🔧 参考改法(统一来源)
-SUPPORTED_COMPRESSION_METHODS = ["zip", "gzip", "bz2", "zstd", "xz", "tar"]+# Mapping from compression method to file suffix+COMPRESSION_SUFFIXES = {+ "zip": ".zip",+ "gzip": ".gz",+ "bz2": ".bz2",+ "zstd": ".zst",+ "xz": ".xz",+ "tar": ".tar",+}+SUPPORTED_COMPRESSION_METHODS = list(COMPRESSION_SUFFIXES.keys())
oocana/tests/test_serialization.py (1)

29-119: 建议参数化这些重复的后缀测试
zip/gzip/bz2/zstd/xz/tar 的测试结构完全一致,后续维护成本偏高。可以用 subTest + 参数表合并为一个测试。

♻️ 参考改法(参数化)
- def test_compression_suffix_zip(self):- """Test compression suffix for zip method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "zip"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".zip")-- def test_compression_suffix_gzip(self):- """Test compression suffix for gzip method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "gzip"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".gz")-- ...-- def test_compression_suffix_tar(self):- """Test compression suffix for tar method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "tar"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".tar")+ def test_compression_suffix_methods(self):+ """Test compression suffix for supported methods."""+ from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE++ cases = {+ "zip": ".zip",+ "gzip": ".gz",+ "bz2": ".bz2",+ "zstd": ".zst",+ "xz": ".xz",+ "tar": ".tar",+ }+ for method, expected in cases.items():+ with self.subTest(method=method):+ with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:+ json.dump({"method": method}, f)+ self.assertEqual(compression_suffix(self.mock_context), expected)

Comment on lines 87 to +96
compression = compression_options(context)

if compression is None or compression["method"] is None:
if compression is None:
return ".pkl"

method = compression["method"]
if method == "zip":
return ".zip"
elif method == "gzip":
return ".gz"
elif method == "bz2":
return ".bz2"
elif method == "zstd":
return ".zst"
elif method == "xz":
return ".xz"
elif method == "tar":
return ".tar"
else:
return ".pkl" # Default case if method is not recognized No newline at end of file

method = compression.get("method")
if method is None:
return ".pkl"

return COMPRESSION_SUFFIXES.get(method, ".pkl") No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

防止压缩配置为非 dict 时触发 AttributeError
compression_options 读取的是任意 JSON,若文件内容为合法但非 dict(如字符串/列表),compression.get(...) 会直接报错。建议加类型保护并回退到默认后缀。

🛡️ 参考修复
 compression = compression_options(context)
- if compression is None:+ if not isinstance(compression, dict):
return ".pkl"
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
compression=compression_options(context)
ifcompressionisNoneorcompression["method"] isNone:
ifcompressionisNone:
return".pkl"
method=compression["method"]
ifmethod=="zip":
return".zip"
elifmethod=="gzip":
return".gz"
elifmethod=="bz2":
return".bz2"
elifmethod=="zstd":
return".zst"
elifmethod=="xz":
return".xz"
elifmethod=="tar":
return".tar"
else:
return".pkl"# Default case if method is not recognized
\ Nonewlineatendoffile
method=compression.get("method")
ifmethodisNone:
return".pkl"
returnCOMPRESSION_SUFFIXES.get(method, ".pkl")
compression=compression_options(context)
ifnotisinstance(compression, dict):
return".pkl"
method=compression.get("method")
ifmethodisNone:
return".pkl"
returnCOMPRESSION_SUFFIXES.get(method, ".pkl")
🤖 Prompt for AI Agents
In `@oocana/oocana/serialization.py` around lines 87 - 96, compression_options 返回的
compression 可能不是 dict,从而在 compression.get("method") 处抛出
AttributeError;在函数/片段中(使用
compression_options、compression、method、COMPRESSION_SUFFIXES 的地方)先对 compression
做类型保护(例如 isinstance(compression, dict) 或
collections.abc.Mapping),若不是合适的映射类型则直接返回默认后缀 ".pkl";若是映射再安全读取 method 并用
COMPRESSION_SUFFIXES.get(method, ".pkl") 返回结果。

@leavessterleavesster changed the title fix: use dict mapping for compression_suffix instead of if-elif chainfix(oocana): use dict mapping for compression_suffix instead of if-elif chainJan 31, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@leavesster
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(oocana): use dict mapping for compression_suffix instead of if-elif chain by leavesster · Pull Request #457 · oomol/oocana-python · GitHub
Skip to content

fix(oocana): use dict mapping for compression_suffix instead of if-elif chain - #457

Open
leavesster wants to merge 1 commit into
mainfrom
fix/compression-suffix-dict-mapping
Open

fix(oocana): use dict mapping for compression_suffix instead of if-elif chain#457
leavesster wants to merge 1 commit into
mainfrom
fix/compression-suffix-dict-mapping

Conversation

@leavesster

Copy link
Copy Markdown
Contributor

Summary

  • Replace if-elif chain with COMPRESSION_SUFFIXES dictionary mapping
  • Use .get() to safely handle missing keys
  • Add unit tests for compression_suffix() function

Problem

Original code had long if-elif chain with potential KeyError risk:

ifcompression["method"] =="zip":
return".zip"elifcompression["method"] =="gzip":
return".gz"# ... 6 more branches

Solution

COMPRESSION_SUFFIXES= {
"zip": ".zip", "gzip": ".gz", "bz2": ".bz2",
"zstd": ".zst", "xz": ".xz", "tar": ".tar",
}
defcompression_suffix(context):
compression=compression_options(context)
ifcompressionisNone:
return".pkl"returnCOMPRESSION_SUFFIXES.get(compression.get("method"), ".pkl")

Test Plan

  • Added tests/test_serialization.py with coverage for all compression methods
  • All existing tests pass

Replace if-elif chain with a dictionary mapping for cleaner code.
Also fix potential KeyError by using .get() method.
Changes:
- Add COMPRESSION_SUFFIXES constant mapping method to suffix
- Use .get() to safely access 'method' key
- Add comprehensive unit tests for compression_suffix
CopilotAI review requested due to automatic review settings January 31, 2026 09:27
@coderabbitai

coderabbitaiBot commented Jan 31, 2026

Copy link
Copy Markdown

总体说明

本次变更通过引入 COMPRESSION_SUFFIXES 映射表,将压缩后缀逻辑从多个条件分支重构为单一映射查询机制。同时新增了一个全面的测试模块,用于验证压缩后缀和压缩选项在各种场景下的行为。

变更内容

文件群组 / 文件路径变更摘要
核心序列化重构
oocana/oocana/serialization.py
引入 COMPRESSION_SUFFIXES 常量映射压缩方法与文件后缀;重构 compression_suffix 函数,将多个条件分支替换为映射查询,默认返回 ".pkl";移除显式的按方法分发逻辑。
测试套件新增
oocana/tests/test_serialization.py
新增 164 行测试代码,覆盖 compression_suffix 函数在多种压缩方法(zip、gzip、bz2、zstd、xz、tar)及边界情况下的行为;测试 compression_options 函数处理缺失、有效和无效 JSON 文件的场景;使用临时目录和 mock 上下文完成测试隔离。

代码审查工作量估算

🎯 3 (中等复杂度) | ⏱️ ~20 分钟

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description check✅ PassedPR description is well-related to the changeset, providing clear problem statement, solution details with code examples, and test plan that align with the actual changes made.
Title check✅ PassedThe pull request title follows the required format with type(scope): subject pattern, clearly describing the main refactoring change from if-elif chain to dict mapping.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Refactors compression_suffix() to use a dictionary mapping for compression method → file suffix (instead of an if/elif chain) and adds unit tests to validate behavior across supported and edge-case methods.

Changes:

  • Introduced COMPRESSION_SUFFIXES mapping and updated compression_suffix() to use .get()-based lookup with defaults.
  • Updated compression_suffix() docstring to match actual default behavior (.pkl).
  • Added unit tests covering supported methods and fallback behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

FileDescription
oocana/oocana/serialization.pyReplaces if/elif suffix selection with a mapping constant and simplified lookup logic.
oocana/tests/test_serialization.pyAdds tests for compression_suffix() and compression_options() behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -0,0 +1,164 @@
import unittest
from unittest.mock import MagicMock, patch

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

patch is imported but never used in this test module; removing it avoids lint warnings and keeps the test file tidy.

Suggested change
fromunittest.mockimportMagicMock, patch
fromunittest.mockimportMagicMock

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +93
method = compression.get("method")
if method is None:

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

COMPRESSION_SUFFIXES.get(method, ...) assumes method is a hashable key. If the options file contains a non-string (e.g., a list/dict from valid-but-unexpected JSON), this will raise TypeError and crash, whereas the previous if/elif chain would safely fall back. Consider guarding with isinstance(method, str) (and/or isinstance(compression, dict)) before doing the dict lookup, otherwise return the default suffix.

Suggested change
method=compression.get("method")
ifmethodisNone:
# Ensure we have a dictionary before accessing keys. Malformed or unexpected
# JSON in the options file may result in a non-dict value here.
ifnotisinstance(compression, dict):
return".pkl"
method=compression.get("method")
# Guard against non-string (and thus potentially unhashable) methods.
ifnotisinstance(method, str):

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +80
# Mapping from compression method to file suffix
COMPRESSION_SUFFIXES = {
"zip": ".zip",
"gzip": ".gz",
"bz2": ".bz2",
"zstd": ".zst",
"xz": ".xz",
"tar": ".tar",
}

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

The compression methods are now duplicated in three places (SUPPORTED_COMPRESSION_METHODS, the CompressionOptions Literal, and COMPRESSION_SUFFIXES). This can drift over time (e.g., a method added to SUPPORTED_COMPRESSION_METHODS but missing here would silently fall back to .pkl). Consider making one source of truth (e.g., derive SUPPORTED_COMPRESSION_METHODS from COMPRESSION_SUFFIXES.keys()), and keep the type Literal in sync with that constant.

Copilot uses AI. Check for mistakes.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@oocana/oocana/serialization.py`:
- Around line 87-96: compression_options 返回的 compression 可能不是 dict,从而在
compression.get("method") 处抛出 AttributeError;在函数/片段中(使用
compression_options、compression、method、COMPRESSION_SUFFIXES 的地方)先对 compression
做类型保护(例如 isinstance(compression, dict) 或
collections.abc.Mapping),若不是合适的映射类型则直接返回默认后缀 ".pkl";若是映射再安全读取 method 并用
COMPRESSION_SUFFIXES.get(method, ".pkl") 返回结果。
🧹 Nitpick comments (2)
oocana/oocana/serialization.py (1)

72-80: 避免与 SUPPORTED_COMPRESSION_METHODS 重复来源,防止漂移
目前方法列表在 SUPPORTED_COMPRESSION_METHODSCOMPRESSION_SUFFIXES 中重复维护,后续新增/删除方法容易不同步。建议以 COMPRESSION_SUFFIXES 作为单一来源生成列表。若该常量希望对外公开,也可同步加入 __all__

🔧 参考改法(统一来源)
-SUPPORTED_COMPRESSION_METHODS = ["zip", "gzip", "bz2", "zstd", "xz", "tar"]+# Mapping from compression method to file suffix+COMPRESSION_SUFFIXES = {+ "zip": ".zip",+ "gzip": ".gz",+ "bz2": ".bz2",+ "zstd": ".zst",+ "xz": ".xz",+ "tar": ".tar",+}+SUPPORTED_COMPRESSION_METHODS = list(COMPRESSION_SUFFIXES.keys())
oocana/tests/test_serialization.py (1)

29-119: 建议参数化这些重复的后缀测试
zip/gzip/bz2/zstd/xz/tar 的测试结构完全一致,后续维护成本偏高。可以用 subTest + 参数表合并为一个测试。

♻️ 参考改法(参数化)
- def test_compression_suffix_zip(self):- """Test compression suffix for zip method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "zip"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".zip")-- def test_compression_suffix_gzip(self):- """Test compression suffix for gzip method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "gzip"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".gz")-- ...-- def test_compression_suffix_tar(self):- """Test compression suffix for tar method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "tar"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".tar")+ def test_compression_suffix_methods(self):+ """Test compression suffix for supported methods."""+ from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE++ cases = {+ "zip": ".zip",+ "gzip": ".gz",+ "bz2": ".bz2",+ "zstd": ".zst",+ "xz": ".xz",+ "tar": ".tar",+ }+ for method, expected in cases.items():+ with self.subTest(method=method):+ with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:+ json.dump({"method": method}, f)+ self.assertEqual(compression_suffix(self.mock_context), expected)

Comment on lines 87 to +96
compression = compression_options(context)

if compression is None or compression["method"] is None:
if compression is None:
return ".pkl"

method = compression["method"]
if method == "zip":
return ".zip"
elif method == "gzip":
return ".gz"
elif method == "bz2":
return ".bz2"
elif method == "zstd":
return ".zst"
elif method == "xz":
return ".xz"
elif method == "tar":
return ".tar"
else:
return ".pkl" # Default case if method is not recognized No newline at end of file

method = compression.get("method")
if method is None:
return ".pkl"

return COMPRESSION_SUFFIXES.get(method, ".pkl") No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

防止压缩配置为非 dict 时触发 AttributeError
compression_options 读取的是任意 JSON,若文件内容为合法但非 dict(如字符串/列表),compression.get(...) 会直接报错。建议加类型保护并回退到默认后缀。

🛡️ 参考修复
 compression = compression_options(context)
- if compression is None:+ if not isinstance(compression, dict):
return ".pkl"
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
compression=compression_options(context)
ifcompressionisNoneorcompression["method"] isNone:
ifcompressionisNone:
return".pkl"
method=compression["method"]
ifmethod=="zip":
return".zip"
elifmethod=="gzip":
return".gz"
elifmethod=="bz2":
return".bz2"
elifmethod=="zstd":
return".zst"
elifmethod=="xz":
return".xz"
elifmethod=="tar":
return".tar"
else:
return".pkl"# Default case if method is not recognized
\ Nonewlineatendoffile
method=compression.get("method")
ifmethodisNone:
return".pkl"
returnCOMPRESSION_SUFFIXES.get(method, ".pkl")
compression=compression_options(context)
ifnotisinstance(compression, dict):
return".pkl"
method=compression.get("method")
ifmethodisNone:
return".pkl"
returnCOMPRESSION_SUFFIXES.get(method, ".pkl")
🤖 Prompt for AI Agents
In `@oocana/oocana/serialization.py` around lines 87 - 96, compression_options 返回的
compression 可能不是 dict,从而在 compression.get("method") 处抛出
AttributeError;在函数/片段中(使用
compression_options、compression、method、COMPRESSION_SUFFIXES 的地方)先对 compression
做类型保护(例如 isinstance(compression, dict) 或
collections.abc.Mapping),若不是合适的映射类型则直接返回默认后缀 ".pkl";若是映射再安全读取 method 并用
COMPRESSION_SUFFIXES.get(method, ".pkl") 返回结果。

@leavessterleavesster changed the title fix: use dict mapping for compression_suffix instead of if-elif chainfix(oocana): use dict mapping for compression_suffix instead of if-elif chainJan 31, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@leavesster
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); fix(oocana): use dict mapping for compression_suffix instead of if-elif chain by leavesster · Pull Request #457 · oomol/oocana-python · GitHub
Skip to content

fix(oocana): use dict mapping for compression_suffix instead of if-elif chain - #457

Open
leavesster wants to merge 1 commit into
mainfrom
fix/compression-suffix-dict-mapping
Open

fix(oocana): use dict mapping for compression_suffix instead of if-elif chain#457
leavesster wants to merge 1 commit into
mainfrom
fix/compression-suffix-dict-mapping

Conversation

@leavesster

Copy link
Copy Markdown
Contributor

Summary

  • Replace if-elif chain with COMPRESSION_SUFFIXES dictionary mapping
  • Use .get() to safely handle missing keys
  • Add unit tests for compression_suffix() function

Problem

Original code had long if-elif chain with potential KeyError risk:

ifcompression["method"] =="zip":
return".zip"elifcompression["method"] =="gzip":
return".gz"# ... 6 more branches

Solution

COMPRESSION_SUFFIXES= {
"zip": ".zip", "gzip": ".gz", "bz2": ".bz2",
"zstd": ".zst", "xz": ".xz", "tar": ".tar",
}
defcompression_suffix(context):
compression=compression_options(context)
ifcompressionisNone:
return".pkl"returnCOMPRESSION_SUFFIXES.get(compression.get("method"), ".pkl")

Test Plan

  • Added tests/test_serialization.py with coverage for all compression methods
  • All existing tests pass

Replace if-elif chain with a dictionary mapping for cleaner code.
Also fix potential KeyError by using .get() method.
Changes:
- Add COMPRESSION_SUFFIXES constant mapping method to suffix
- Use .get() to safely access 'method' key
- Add comprehensive unit tests for compression_suffix
CopilotAI review requested due to automatic review settings January 31, 2026 09:27
@coderabbitai

coderabbitaiBot commented Jan 31, 2026

Copy link
Copy Markdown

总体说明

本次变更通过引入 COMPRESSION_SUFFIXES 映射表,将压缩后缀逻辑从多个条件分支重构为单一映射查询机制。同时新增了一个全面的测试模块,用于验证压缩后缀和压缩选项在各种场景下的行为。

变更内容

文件群组 / 文件路径变更摘要
核心序列化重构
oocana/oocana/serialization.py
引入 COMPRESSION_SUFFIXES 常量映射压缩方法与文件后缀;重构 compression_suffix 函数,将多个条件分支替换为映射查询,默认返回 ".pkl";移除显式的按方法分发逻辑。
测试套件新增
oocana/tests/test_serialization.py
新增 164 行测试代码,覆盖 compression_suffix 函数在多种压缩方法(zip、gzip、bz2、zstd、xz、tar)及边界情况下的行为;测试 compression_options 函数处理缺失、有效和无效 JSON 文件的场景;使用临时目录和 mock 上下文完成测试隔离。

代码审查工作量估算

🎯 3 (中等复杂度) | ⏱️ ~20 分钟

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description check✅ PassedPR description is well-related to the changeset, providing clear problem statement, solution details with code examples, and test plan that align with the actual changes made.
Title check✅ PassedThe pull request title follows the required format with type(scope): subject pattern, clearly describing the main refactoring change from if-elif chain to dict mapping.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Refactors compression_suffix() to use a dictionary mapping for compression method → file suffix (instead of an if/elif chain) and adds unit tests to validate behavior across supported and edge-case methods.

Changes:

  • Introduced COMPRESSION_SUFFIXES mapping and updated compression_suffix() to use .get()-based lookup with defaults.
  • Updated compression_suffix() docstring to match actual default behavior (.pkl).
  • Added unit tests covering supported methods and fallback behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

FileDescription
oocana/oocana/serialization.pyReplaces if/elif suffix selection with a mapping constant and simplified lookup logic.
oocana/tests/test_serialization.pyAdds tests for compression_suffix() and compression_options() behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -0,0 +1,164 @@
import unittest
from unittest.mock import MagicMock, patch

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

patch is imported but never used in this test module; removing it avoids lint warnings and keeps the test file tidy.

Suggested change
fromunittest.mockimportMagicMock, patch
fromunittest.mockimportMagicMock

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +93
method = compression.get("method")
if method is None:

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

COMPRESSION_SUFFIXES.get(method, ...) assumes method is a hashable key. If the options file contains a non-string (e.g., a list/dict from valid-but-unexpected JSON), this will raise TypeError and crash, whereas the previous if/elif chain would safely fall back. Consider guarding with isinstance(method, str) (and/or isinstance(compression, dict)) before doing the dict lookup, otherwise return the default suffix.

Suggested change
method=compression.get("method")
ifmethodisNone:
# Ensure we have a dictionary before accessing keys. Malformed or unexpected
# JSON in the options file may result in a non-dict value here.
ifnotisinstance(compression, dict):
return".pkl"
method=compression.get("method")
# Guard against non-string (and thus potentially unhashable) methods.
ifnotisinstance(method, str):

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +80
# Mapping from compression method to file suffix
COMPRESSION_SUFFIXES = {
"zip": ".zip",
"gzip": ".gz",
"bz2": ".bz2",
"zstd": ".zst",
"xz": ".xz",
"tar": ".tar",
}

CopilotAIJan 31, 2026

Copy link

Choose a reason for hiding this comment

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

The compression methods are now duplicated in three places (SUPPORTED_COMPRESSION_METHODS, the CompressionOptions Literal, and COMPRESSION_SUFFIXES). This can drift over time (e.g., a method added to SUPPORTED_COMPRESSION_METHODS but missing here would silently fall back to .pkl). Consider making one source of truth (e.g., derive SUPPORTED_COMPRESSION_METHODS from COMPRESSION_SUFFIXES.keys()), and keep the type Literal in sync with that constant.

Copilot uses AI. Check for mistakes.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@oocana/oocana/serialization.py`:
- Around line 87-96: compression_options 返回的 compression 可能不是 dict,从而在
compression.get("method") 处抛出 AttributeError;在函数/片段中(使用
compression_options、compression、method、COMPRESSION_SUFFIXES 的地方)先对 compression
做类型保护(例如 isinstance(compression, dict) 或
collections.abc.Mapping),若不是合适的映射类型则直接返回默认后缀 ".pkl";若是映射再安全读取 method 并用
COMPRESSION_SUFFIXES.get(method, ".pkl") 返回结果。
🧹 Nitpick comments (2)
oocana/oocana/serialization.py (1)

72-80: 避免与 SUPPORTED_COMPRESSION_METHODS 重复来源,防止漂移
目前方法列表在 SUPPORTED_COMPRESSION_METHODSCOMPRESSION_SUFFIXES 中重复维护,后续新增/删除方法容易不同步。建议以 COMPRESSION_SUFFIXES 作为单一来源生成列表。若该常量希望对外公开,也可同步加入 __all__

🔧 参考改法(统一来源)
-SUPPORTED_COMPRESSION_METHODS = ["zip", "gzip", "bz2", "zstd", "xz", "tar"]+# Mapping from compression method to file suffix+COMPRESSION_SUFFIXES = {+ "zip": ".zip",+ "gzip": ".gz",+ "bz2": ".bz2",+ "zstd": ".zst",+ "xz": ".xz",+ "tar": ".tar",+}+SUPPORTED_COMPRESSION_METHODS = list(COMPRESSION_SUFFIXES.keys())
oocana/tests/test_serialization.py (1)

29-119: 建议参数化这些重复的后缀测试
zip/gzip/bz2/zstd/xz/tar 的测试结构完全一致,后续维护成本偏高。可以用 subTest + 参数表合并为一个测试。

♻️ 参考改法(参数化)
- def test_compression_suffix_zip(self):- """Test compression suffix for zip method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "zip"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".zip")-- def test_compression_suffix_gzip(self):- """Test compression suffix for gzip method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "gzip"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".gz")-- ...-- def test_compression_suffix_tar(self):- """Test compression suffix for tar method."""- from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE-- with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:- json.dump({"method": "tar"}, f)-- result = compression_suffix(self.mock_context)- self.assertEqual(result, ".tar")+ def test_compression_suffix_methods(self):+ """Test compression suffix for supported methods."""+ from oocana.oocana.serialization import compression_suffix, COMPRESSION_OPTIONS_FILE++ cases = {+ "zip": ".zip",+ "gzip": ".gz",+ "bz2": ".bz2",+ "zstd": ".zst",+ "xz": ".xz",+ "tar": ".tar",+ }+ for method, expected in cases.items():+ with self.subTest(method=method):+ with open(os.path.join(self.temp_dir, COMPRESSION_OPTIONS_FILE), "w") as f:+ json.dump({"method": method}, f)+ self.assertEqual(compression_suffix(self.mock_context), expected)

Comment on lines 87 to +96
compression = compression_options(context)

if compression is None or compression["method"] is None:
if compression is None:
return ".pkl"

method = compression["method"]
if method == "zip":
return ".zip"
elif method == "gzip":
return ".gz"
elif method == "bz2":
return ".bz2"
elif method == "zstd":
return ".zst"
elif method == "xz":
return ".xz"
elif method == "tar":
return ".tar"
else:
return ".pkl" # Default case if method is not recognized No newline at end of file

method = compression.get("method")
if method is None:
return ".pkl"

return COMPRESSION_SUFFIXES.get(method, ".pkl") No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

防止压缩配置为非 dict 时触发 AttributeError
compression_options 读取的是任意 JSON,若文件内容为合法但非 dict(如字符串/列表),compression.get(...) 会直接报错。建议加类型保护并回退到默认后缀。

🛡️ 参考修复
 compression = compression_options(context)
- if compression is None:+ if not isinstance(compression, dict):
return ".pkl"
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
compression=compression_options(context)
ifcompressionisNoneorcompression["method"] isNone:
ifcompressionisNone:
return".pkl"
method=compression["method"]
ifmethod=="zip":
return".zip"
elifmethod=="gzip":
return".gz"
elifmethod=="bz2":
return".bz2"
elifmethod=="zstd":
return".zst"
elifmethod=="xz":
return".xz"
elifmethod=="tar":
return".tar"
else:
return".pkl"# Default case if method is not recognized
\ Nonewlineatendoffile
method=compression.get("method")
ifmethodisNone:
return".pkl"
returnCOMPRESSION_SUFFIXES.get(method, ".pkl")
compression=compression_options(context)
ifnotisinstance(compression, dict):
return".pkl"
method=compression.get("method")
ifmethodisNone:
return".pkl"
returnCOMPRESSION_SUFFIXES.get(method, ".pkl")
🤖 Prompt for AI Agents
In `@oocana/oocana/serialization.py` around lines 87 - 96, compression_options 返回的
compression 可能不是 dict,从而在 compression.get("method") 处抛出
AttributeError;在函数/片段中(使用
compression_options、compression、method、COMPRESSION_SUFFIXES 的地方)先对 compression
做类型保护(例如 isinstance(compression, dict) 或
collections.abc.Mapping),若不是合适的映射类型则直接返回默认后缀 ".pkl";若是映射再安全读取 method 并用
COMPRESSION_SUFFIXES.get(method, ".pkl") 返回结果。

@leavessterleavesster changed the title fix: use dict mapping for compression_suffix instead of if-elif chainfix(oocana): use dict mapping for compression_suffix instead of if-elif chainJan 31, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@leavesster