Skip to content

Commit d71c1d3

Browse files
fix: filter non-integer metadata from GitHub languages API response (#322)
PyGithub's get_languages() returns raw API JSON which in some environments includes non-integer metadata keys (e.g., "url"), causing a TypeError in sum(). Now filters to integer values only before calculating percentages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 336ab6a commit d71c1d3

4 files changed

Lines changed: 36 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Fixed
11+
- **GitHub language detection crashes with `TypeError`** when API response contains non-integer metadata keys (e.g., `"url"`) — now filters to integer values only (#322)
12+
1013
## [3.4.0] - 2026-03-21
1114

1215
### Added

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
66

77
**Skill Seekers** converts documentation from 17 source types into production-ready formats for 24+ AI platforms (LLM platforms, RAG frameworks, vector databases, AI coding assistants). Published on PyPI as `skill-seekers`.
88

9-
**Version:** 3.3.0 | **Python:** 3.10+ | **Website:** https://skillseekersweb.com/
9+
**Version:** 3.4.0 | **Python:** 3.10+ | **Website:** https://skillseekersweb.com/
1010

1111
**Architecture:** See `docs/UML_ARCHITECTURE.md` for UML diagrams and module overview. StarUML project at `docs/UML/skill_seekers.mdj`.
1212

src/skill_seekers/cli/github_scraper.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,13 @@ def _extract_languages(self):
519519

520520
try:
521521
languages = self.repo.get_languages()
522+
# Filter out non-integer metadata (e.g., "url" key from some API configurations)
523+
non_lang_keys = {k for k, v in languages.items() if not isinstance(v, int)}
524+
if non_lang_keys:
525+
logger.debug(
526+
f"Filtered non-language keys from API response: {non_lang_keys}"
527+
)
528+
languages = {k: v for k, v in languages.items() if isinstance(v, int)}
522529
total_bytes = sum(languages.values())
523530

524531
self.extracted_data["languages"] = {

tests/test_github_scraper.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,31 @@ def test_extract_languages_empty(self):
230230
self.assertIn("languages", scraper.extracted_data)
231231
self.assertEqual(scraper.extracted_data["languages"], {})
232232

233+
def test_extract_languages_filters_non_integer_metadata(self):
234+
"""Test that non-integer metadata keys (e.g., 'url') are filtered out (#322)"""
235+
config = {"repo": "xyflow/xyflow", "name": "xyflow", "github_token": None}
236+
237+
with patch("skill_seekers.cli.github_scraper.Github"):
238+
scraper = self.GitHubScraper(config)
239+
scraper.repo = Mock()
240+
scraper.repo.get_languages.return_value = {
241+
"TypeScript": 707330,
242+
"Svelte": 95784,
243+
"url": "https://api.github.com/repos/xyflow/xyflow/languages",
244+
}
245+
246+
scraper._extract_languages()
247+
248+
self.assertIn("languages", scraper.extracted_data)
249+
self.assertIn("TypeScript", scraper.extracted_data["languages"])
250+
self.assertIn("Svelte", scraper.extracted_data["languages"])
251+
self.assertNotIn("url", scraper.extracted_data["languages"])
252+
253+
# Percentages should be calculated only from real languages
254+
ts_data = scraper.extracted_data["languages"]["TypeScript"]
255+
total = 707330 + 95784
256+
self.assertEqual(ts_data["percentage"], round(707330 / total * 100, 2))
257+
233258

234259
class TestIssuesExtraction(unittest.TestCase):
235260
"""Test GitHub Issues extraction (C1.7)"""

0 commit comments

Comments
 (0)