django-orm-lens 1.2.5__tar.gz → 1.2.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/PKG-INFO +1 -1
  2. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/django_orm_lens/parser.py +6 -1
  3. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/django_orm_lens.egg-info/PKG-INFO +1 -1
  4. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/django_orm_lens.egg-info/SOURCES.txt +2 -1
  5. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/pyproject.toml +1 -1
  6. django_orm_lens-1.2.6/tests/test_tab_indented_models.py +54 -0
  7. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/README.md +0 -0
  8. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/django_orm_lens/__init__.py +0 -0
  9. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/django_orm_lens/cli.py +0 -0
  10. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/django_orm_lens/diff.py +0 -0
  11. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/django_orm_lens/formatters.py +0 -0
  12. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/django_orm_lens/mcp_server.py +0 -0
  13. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/django_orm_lens/migrations_parser.py +0 -0
  14. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/django_orm_lens/models.py +0 -0
  15. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/django_orm_lens/py.typed +0 -0
  16. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/django_orm_lens/query_analyzer.py +0 -0
  17. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/django_orm_lens/signals_parser.py +0 -0
  18. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/django_orm_lens.egg-info/dependency_links.txt +0 -0
  19. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/django_orm_lens.egg-info/entry_points.txt +0 -0
  20. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/django_orm_lens.egg-info/requires.txt +0 -0
  21. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/django_orm_lens.egg-info/top_level.txt +0 -0
  22. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/setup.cfg +0 -0
  23. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/tests/test_abstract_and_auth_user.py +0 -0
  24. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/tests/test_aliased_module_and_third_party_fields.py +0 -0
  25. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/tests/test_cli_hint.py +0 -0
  26. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/tests/test_cli_subcommands_smoke.py +0 -0
  27. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/tests/test_cli_verbose.py +0 -0
  28. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/tests/test_cross_module_bases.py +0 -0
  29. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/tests/test_diff_command.py +0 -0
  30. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/tests/test_golden_fixtures.py +0 -0
  31. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/tests/test_kwarg_order_and_auth_user.py +0 -0
  32. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/tests/test_list_command.py +0 -0
  33. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/tests/test_migration_risk.py +0 -0
  34. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/tests/test_migrations_parser.py +0 -0
  35. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/tests/test_nplusone_detector.py +0 -0
  36. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/tests/test_parity.py +0 -0
  37. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/tests/test_pep526_type_hints.py +0 -0
  38. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/tests/test_pep695_generic_classes.py +0 -0
  39. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/tests/test_query_analyzer.py +0 -0
  40. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/tests/test_scan_root.py +0 -0
  41. {django_orm_lens-1.2.5 → django_orm_lens-1.2.6}/tests/test_signals_parser.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-orm-lens
3
- Version: 1.2.5
3
+ Version: 1.2.6
4
4
  Summary: Static analysis + MCP server for Django models. Sidebar tree, ER diagrams, and JSON output for terminals and AI coding agents.
5
5
  Author: frowningdev
6
6
  License: MIT
@@ -398,7 +398,12 @@ def _collect_defs(file_path: str, content: str) -> List[ParsedModel]:
398
398
  result with definitions from other files before calling
399
399
  ``_resolve_and_filter``.
400
400
  """
401
- lines = content.splitlines()
401
+ # Expand tab characters to 4 spaces so the ``\s{indent}`` prefix used in
402
+ # FIELD_RE / BARE_FIELD_RE / META_ITEM_RE matches tab-indented code too.
403
+ # A single ``\t`` character otherwise contributes 1 to ``\s`` even though
404
+ # it's visually 4 columns — tab-indented models used to have zero fields
405
+ # detected. Line numbers are preserved (per-line expansion only).
406
+ lines = [line.expandtabs(4) for line in content.splitlines()]
402
407
  all_defs: List[ParsedModel] = []
403
408
  parent = os.path.basename(os.path.dirname(file_path))
404
409
  if parent == "models":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-orm-lens
3
- Version: 1.2.5
3
+ Version: 1.2.6
4
4
  Summary: Static analysis + MCP server for Django models. Sidebar tree, ER diagrams, and JSON output for terminals and AI coding agents.
5
5
  Author: frowningdev
6
6
  License: MIT
@@ -35,4 +35,5 @@ tests/test_pep526_type_hints.py
35
35
  tests/test_pep695_generic_classes.py
36
36
  tests/test_query_analyzer.py
37
37
  tests/test_scan_root.py
38
- tests/test_signals_parser.py
38
+ tests/test_signals_parser.py
39
+ tests/test_tab_indented_models.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "django-orm-lens"
7
- version = "1.2.5"
7
+ version = "1.2.6"
8
8
  description = "Static analysis + MCP server for Django models. Sidebar tree, ER diagrams, and JSON output for terminals and AI coding agents."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -0,0 +1,54 @@
1
+ """Regression: tab-indented model bodies must parse.
2
+
3
+ Editors that default to tabs (or projects that use PEP-8 exceptions with
4
+ tabs) produced empty models - every field silently dropped. Root cause:
5
+ ``FIELD_RE`` uses ``\\s{indent}`` as its column prefix and
6
+ ``_detect_class_indent`` expands tabs to width 4, but a single ``\\t``
7
+ character is only one match for ``\\s``, not four. Fixed by pre-expanding
8
+ tabs to spaces in the line buffer before regex matching.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import unittest
14
+
15
+ from django_orm_lens.parser import parse_models_file
16
+
17
+
18
+ class TabIndentationTest(unittest.TestCase):
19
+ def test_pure_tab_indented_body(self) -> None:
20
+ src = (
21
+ "class Post(models.Model):\n"
22
+ "\ttitle = models.CharField(max_length=100)\n"
23
+ "\tauthor = models.CharField(max_length=100)\n"
24
+ "\tbody = models.TextField()\n"
25
+ )
26
+ models = parse_models_file("blog/models.py", src)
27
+ self.assertEqual(len(models), 1)
28
+ self.assertEqual(
29
+ [f.name for f in models[0].fields],
30
+ ["title", "author", "body"],
31
+ )
32
+
33
+ def test_mixed_tab_then_space(self) -> None:
34
+ # Editors that mid-migrate to tabs sometimes end up with a tab
35
+ # followed by a space; that used to fail equally silently.
36
+ src = (
37
+ "class M(models.Model):\n"
38
+ "\t x = models.CharField(max_length=5)\n"
39
+ )
40
+ models = parse_models_file("t/models.py", src)
41
+ self.assertEqual([f.name for f in models[0].fields], ["x"])
42
+
43
+ def test_space_indented_still_works(self) -> None:
44
+ # Backward-compat guard.
45
+ src = (
46
+ "class M(models.Model):\n"
47
+ " x = models.CharField(max_length=5)\n"
48
+ )
49
+ models = parse_models_file("t/models.py", src)
50
+ self.assertEqual([f.name for f in models[0].fields], ["x"])
51
+
52
+
53
+ if __name__ == "__main__":
54
+ unittest.main()