Findings from a code-quality/architecture pass over ontolearn/ (core reasoning
modules, the learners/ package) and the surrounding infra (tests, packaging,
lint, docs). Each item cites the file/line where the issue was observed.
Prioritized roughly high → low impact within each section.
These are actual defects, not style nits — worth fixing regardless of any broader refactor.
All correctness bugs originally found in this pass have been fixed; none remain open as of this writing.
All code duplication issues originally found in this pass have been fixed; none remain open as of this writing.
- Logging infra is built but essentially unused.
ontolearn/utils/log_config.pyandoplogging.pyprovide a real fileConfig-based setup with a TRACE level, but only ~8 call sites acrossontolearn/actually usegetLogger/oplogging/log_config.print(calls have been routed through module-levellogger = logging.getLogger(__name__)calls (with appropriate levels —info/warning/debug/error) inknowledge_base.py,semantic_caching.py,learners/tree_learner_refinement_inherit.py,learners/spell_kit/structures.py(exceptstructure_to_dot, whoseprint()s are genuine DOT-graph text output, not log messages), andlearners/drill.py.print(still appears ~270 times across the rest ofontolearn/**/*.py; remaining offenders includelearners/nces.py(17),learners/nces2.py(11),learners/tree_learner.py(16),learners/celoe.py(11),learners/sparql_query_learner.py(4), anddata_struct.py(10) — several of these overlap with the broad-except cleanup below and are best converted alongside that work. Routing the rest through the existing logger (with levels) would make output controllable/filterable instead of unconditionally printed. learners/celoe.py:290-311—_add_node_evaldis dead code, a near-duplicate of_add_node(255-288) with zero call sites anywhere in the repo. Remove it.learners/base.py:167-173—BaseConceptLearner.train()is a no-oppassstub, yetdrill.py:251defines its own realtrain()outside that contract. The shared abstraction isn't actually shared; either give the base method real shared behavior or drop it and documenttrain()as learner-specific.
learners/tree_learner.py:287andlearners/tree_learner_refinement_inherit.py:59—kwargs_grid_search: dict = {}is a classic mutable-default-argument bug. The same dict is shared across everyTDL/TDL_refinementinstance created without explicitly passing this argument, and it's mutated in place (.setdefault("cv", 10)at tree_learner.py:317) — state can leak between unrelated learner instances. UseNoneas the default and construct a fresh dict inside__init__.
learners/drill.py— fixed:Drill.__init__now accepts arandom_stateparam, seeding a dedicatedrandom.Randominstance (used for exploration/example sampling instead of the globalrandommodule) plustorch/CUDA.EvoLearner's DEAP-driven GA still has the same gap — no seed parameter exposed. Worth adding the samerandom_statetreatment there, threaded through tonumpy/DEAP, consistent with the sklearn convention this codebase otherwise follows (e.g. itsfit/predictnaming).- GPU/CUDA handling itself is fine —
clip.py:138,nero.py:107,drill.py:92all correctly guard withtorch.device("cuda" if torch.cuda.is_available() else "cpu"); no hardcoded.cuda()calls found.
- Two test files are 100% commented out and run zero assertions while
still being collected by pytest:
tests/test_semantic_cache.py(68/68 lines) andtests/test_example_concept_learning_neural_evaluation.py(168/168 lines). Either restore them or delete them — as-is they give a false sense of coverage. - The committed coverage report (
docs/usage/09_further_resources.md:191-244, v0.10.0, 82% overall) shows specific weak spots worth targeted tests:ontolearn/incomplete_kb.py8% (73/79 statements missed),ontolearn/quality_funcs.py31%,ontolearn/nces_utils.py39%,ontolearn/triple_store.py53% (237/501 missed),ontolearn/data_struct.py60%. README.md:3badge claims 86% coverage; the committed report indocs/usage/09_further_resources.md:243says 82%. Pick one source of truth and keep the badge in sync with it (ideally generated by CI rather than hand-updated).- CI (
.github/workflows/test.yml) scopesruff checktoontolearn/learnersonly (excludingspell_kit), not the whole package — most ofontolearn/(core reasoning modules,utils/, etc.) isn't linted in CI at all.
- No
pyproject.toml— packaging is still pure legacysetup.py. Migrating topyproject.toml(PEP 621) would be a larger, separate effort, but is worth planning for sincesetup.py-only packaging is increasingly unsupported by newer tooling. - Dependency pinning is inconsistent with no explanation: most deps are
>=range-pinned, butowlapy==1.6.6,dicee==0.3.2,lxml==5.3.0,python-sat==0.1.7.dev23, andshap==0.49.1are exact-pinned (setup.py:42-70) with no comment on why those five specifically need exact pins. A short comment per exact-pin (e.g. "pinned: breaking change in X") would keep this from looking accidental. setup.py:122setspython_requires='>=3.11'but the trove classifier atsetup.py:119still says"Programming Language :: Python :: 3.10"— stale, should read 3.11 (CI only tests 3.11.14 anyway).
ruff.tomlis pinned to a minimal ruleset (E4,E7,E9,F) with a 200-char line length and no line-length rule, no import-sort (I), and no complexity/naming checks. The comment in the file explains this was to avoid the 0.15→0.16 default-ruleset jump (60→415 rules) — reasonable as a stopgap, but worth revisiting deliberately (e.g. opt intoIfor import sorting andUPfor pyupgrade) rather than leaving it at the bare minimum indefinitely.
ontolearn/incomplete_kb.pyhas zero real imports anywhere inontolearn/,tests/, orexamples/(only mentioned in a docstring inontolearn/utils/_lazy_owlready2.py:29), and 8% test coverage. Effectively orphaned — either wire it into a test/example or remove it, similar to the now-deletedtentris.py.ontolearn/logging_tentris.confis a leftover config file from the just-removedtentris.py(PR #602) and is now unused — safe to delete in a follow-up.ontolearn/binders.pyandontolearn/executor.pyare each used by exactly one example script and nowhere else inontolearn/ortests/— worth confirming they're still meant to be supported public surface rather than vestigial.
- All three correctness bugs originally listed in §1 are fixed; none remain.
- Fix the two mutable-default-argument bugs in §4 (cheap, real risk).
- Delete or restore the two fully-commented-out test files in §6.
- Tackle the
tree_learner_refinement_inherit.pyduplication in §2 as a dedicated refactor (largest single win, but the biggest single change). - Everything else (logging migration, packaging modernization, lint tightening) as incremental follow-ups, not blocking.