code2logic 1.0.45__tar.gz → 1.0.47__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 (59) hide show
  1. {code2logic-1.0.45 → code2logic-1.0.47}/PKG-INFO +1 -1
  2. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/__init__.py +1 -1
  3. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/analyzer.py +177 -45
  4. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/cli.py +7 -0
  5. {code2logic-1.0.45 → code2logic-1.0.47}/pyproject.toml +1 -1
  6. {code2logic-1.0.45 → code2logic-1.0.47}/LICENSE +0 -0
  7. {code2logic-1.0.45 → code2logic-1.0.47}/README.md +0 -0
  8. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/__main__.py +0 -0
  9. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/adaptive.py +0 -0
  10. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/base.py +0 -0
  11. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/base_generator.py +0 -0
  12. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/benchmark.py +0 -0
  13. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/benchmarks/__init__.py +0 -0
  14. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/benchmarks/common.py +0 -0
  15. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/benchmarks/results.py +0 -0
  16. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/benchmarks/runner.py +0 -0
  17. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/chunked_reproduction.py +0 -0
  18. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/code_review.py +0 -0
  19. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/config.py +0 -0
  20. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/core/__init__.py +0 -0
  21. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/dependency.py +0 -0
  22. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/errors.py +0 -0
  23. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/file_formats.py +0 -0
  24. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/formats/__init__.py +0 -0
  25. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/function_logic.py +0 -0
  26. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/generators.py +0 -0
  27. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/gherkin.py +0 -0
  28. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/integrations/__init__.py +0 -0
  29. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/intent.py +0 -0
  30. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/llm/__init__.py +0 -0
  31. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/llm.py +0 -0
  32. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/llm_clients.py +0 -0
  33. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/llm_profiler.py +0 -0
  34. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/logicml.py +0 -0
  35. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/markdown_format.py +0 -0
  36. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/mcp_server.py +0 -0
  37. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/metrics.py +0 -0
  38. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/models.py +0 -0
  39. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/parsers.py +0 -0
  40. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/project_comparison.md +0 -0
  41. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/project_reproducer.py +0 -0
  42. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/prompts.py +0 -0
  43. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/py.typed +0 -0
  44. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/quality.py +0 -0
  45. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/refactor.py +0 -0
  46. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/reproducer.py +0 -0
  47. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/reproduction.py +0 -0
  48. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/schemas/__init__.py +0 -0
  49. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/schemas/json_schema.py +0 -0
  50. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/schemas/logicml_schema.py +0 -0
  51. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/schemas/markdown_schema.py +0 -0
  52. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/schemas/yaml_schema.py +0 -0
  53. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/shared_utils.py +0 -0
  54. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/similarity.py +0 -0
  55. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/terminal.py +0 -0
  56. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/tools/__init__.py +0 -0
  57. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/toon_format.py +0 -0
  58. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/universal.py +0 -0
  59. {code2logic-1.0.45 → code2logic-1.0.47}/code2logic/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code2logic
3
- Version: 1.0.45
3
+ Version: 1.0.47
4
4
  Summary: Code2Logic - Source code to logical representation converter for LLM analysis, featuring Tree-sitter parsing, dependency graph analysis, and multi-language support.
5
5
  License: Apache-2.0
6
6
  License-File: LICENSE
@@ -18,7 +18,7 @@ Example:
18
18
  >>> print(output)
19
19
  """
20
20
 
21
- __version__ = "1.0.45"
21
+ __version__ = "1.0.47"
22
22
  __author__ = "Softreck"
23
23
  __email__ = "info@softreck.dev"
24
24
  __license__ = "MIT"
@@ -5,6 +5,8 @@ Provides the high-level API for analyzing codebases.
5
5
  """
6
6
 
7
7
  import logging
8
+ import os
9
+ import subprocess
8
10
  import sys
9
11
  import time
10
12
  from collections import defaultdict
@@ -108,6 +110,7 @@ class ProjectAnalyzer:
108
110
  verbose: bool = False,
109
111
  include_private: bool = False,
110
112
  enable_similarity: bool = True,
113
+ respect_gitignore: bool = True,
111
114
  ):
112
115
  """
113
116
  Initialize the project analyzer.
@@ -123,6 +126,7 @@ class ProjectAnalyzer:
123
126
  self.verbose = verbose
124
127
  self.include_private = include_private
125
128
  self.enable_similarity = enable_similarity
129
+ self.respect_gitignore = respect_gitignore
126
130
  self.modules: List[ModuleInfo] = []
127
131
  self.languages: Dict[str, int] = defaultdict(int)
128
132
 
@@ -218,63 +222,191 @@ class ProjectAnalyzer:
218
222
 
219
223
  def _scan_files(self):
220
224
  """Scan and parse all source files."""
221
- for fp in self.root_path.rglob('*'):
222
- if not fp.is_file():
223
- continue
225
+ scan_start = time.time()
226
+ files_seen = 0
227
+ files_parsed = 0
228
+ files_matched = 0
229
+ scan_progress_every = 500
230
+
231
+ git_file_list: Optional[List[Path]] = None
232
+ if self.respect_gitignore:
233
+ git_file_list = self._get_git_nonignored_files()
234
+ if git_file_list is not None and self.verbose:
235
+ log.info("Using git file list (non-ignored): files=%d", len(git_file_list))
236
+
237
+ if git_file_list is not None:
238
+ for fp in git_file_list:
239
+ files_seen += 1
240
+ filename = fp.name
241
+
242
+ if filename in self.IGNORE_FILES:
243
+ continue
224
244
 
225
- # Skip ignored directories
226
- if any(d in fp.parts for d in self.IGNORE_DIRS):
227
- continue
245
+ ext = fp.suffix.lower()
246
+ language = self.LANGUAGE_EXTENSIONS.get(ext)
247
+ if language is None and ext == '':
248
+ try:
249
+ with fp.open('r', encoding='utf-8', errors='ignore') as f:
250
+ language = self._language_from_shebang(f.readline())
251
+ except Exception:
252
+ language = None
228
253
 
229
- # Skip ignored files
230
- if fp.name in self.IGNORE_FILES:
231
- continue
254
+ if language is None:
255
+ continue
256
+
257
+ files_matched += 1
258
+ self.languages[language] += 1
259
+
260
+ if self.verbose and files_seen > 0 and (files_seen % scan_progress_every) == 0:
261
+ log.info(
262
+ "Scan progress: seen=%d matched=%d parsed=%d modules=%d time=%.2fs",
263
+ files_seen,
264
+ files_matched,
265
+ files_parsed,
266
+ len(self.modules),
267
+ time.time() - scan_start,
268
+ )
232
269
 
233
- ext = fp.suffix.lower()
234
- language = self.LANGUAGE_EXTENSIONS.get(ext)
235
- if language is None and ext == '':
236
270
  try:
237
- with fp.open('r', encoding='utf-8', errors='ignore') as f:
238
- language = self._language_from_shebang(f.readline())
271
+ content = fp.read_text(encoding='utf-8', errors='ignore')
239
272
  except Exception:
240
- language = None
273
+ continue
241
274
 
242
- if language is None:
243
- continue
275
+ try:
276
+ rel_path = str(fp.relative_to(self.root_path))
277
+ except Exception:
278
+ rel_path = str(fp)
244
279
 
245
- self.languages[language] += 1
280
+ module = None
281
+ try:
282
+ if self.ts_parser and self.ts_parser.is_available(language):
283
+ module = self.ts_parser.parse(rel_path, content, language)
284
+ except Exception as e:
285
+ if self.verbose:
286
+ log.debug("Tree-sitter parser failed for %s: %s", rel_path, e)
287
+
288
+ if module is None:
289
+ try:
290
+ module = self.fallback_parser.parse(rel_path, content, language)
291
+ except Exception as e:
292
+ if self.verbose:
293
+ log.debug("Fallback parser failed for %s: %s", rel_path, e)
294
+ continue
295
+
296
+ if module:
297
+ files_parsed += 1
298
+ try:
299
+ module.file_bytes = fp.stat().st_size
300
+ except Exception:
301
+ module.file_bytes = len(content.encode('utf-8', errors='ignore'))
302
+ self.modules.append(module)
246
303
 
247
- # Read file
248
- try:
249
- content = fp.read_text(encoding='utf-8', errors='ignore')
250
- except Exception:
251
- continue
304
+ else:
305
+ for root, dirnames, filenames in os.walk(self.root_path):
306
+ dirnames[:] = [d for d in dirnames if d not in self.IGNORE_DIRS]
307
+ for filename in filenames:
308
+ files_seen += 1
309
+ fp = Path(root) / filename
310
+
311
+ if filename in self.IGNORE_FILES:
312
+ continue
313
+
314
+ ext = fp.suffix.lower()
315
+ language = self.LANGUAGE_EXTENSIONS.get(ext)
316
+ if language is None and ext == '':
317
+ try:
318
+ with fp.open('r', encoding='utf-8', errors='ignore') as f:
319
+ language = self._language_from_shebang(f.readline())
320
+ except Exception:
321
+ language = None
322
+
323
+ if language is None:
324
+ continue
325
+
326
+ files_matched += 1
327
+ self.languages[language] += 1
328
+
329
+ if self.verbose and files_seen > 0 and (files_seen % scan_progress_every) == 0:
330
+ log.info(
331
+ "Scan progress: seen=%d matched=%d parsed=%d modules=%d time=%.2fs",
332
+ files_seen,
333
+ files_matched,
334
+ files_parsed,
335
+ len(self.modules),
336
+ time.time() - scan_start,
337
+ )
338
+
339
+ try:
340
+ content = fp.read_text(encoding='utf-8', errors='ignore')
341
+ except Exception:
342
+ continue
343
+
344
+ try:
345
+ rel_path = str(fp.relative_to(self.root_path))
346
+ except Exception:
347
+ rel_path = str(fp)
348
+
349
+ module = None
350
+ try:
351
+ if self.ts_parser and self.ts_parser.is_available(language):
352
+ module = self.ts_parser.parse(rel_path, content, language)
353
+ except Exception as e:
354
+ if self.verbose:
355
+ log.debug("Tree-sitter parser failed for %s: %s", rel_path, e)
356
+
357
+ if module is None:
358
+ try:
359
+ module = self.fallback_parser.parse(rel_path, content, language)
360
+ except Exception as e:
361
+ if self.verbose:
362
+ log.debug("Fallback parser failed for %s: %s", rel_path, e)
363
+ continue
364
+
365
+ if module:
366
+ files_parsed += 1
367
+ try:
368
+ module.file_bytes = fp.stat().st_size
369
+ except Exception:
370
+ module.file_bytes = len(content.encode('utf-8', errors='ignore'))
371
+ self.modules.append(module)
252
372
 
253
- rel_path = str(fp.relative_to(self.root_path))
373
+ if self.verbose:
374
+ log.info(
375
+ "Scan finished: seen=%d matched=%d parsed=%d modules=%d time=%.2fs",
376
+ files_seen,
377
+ files_matched,
378
+ files_parsed,
379
+ len(self.modules),
380
+ time.time() - scan_start,
381
+ )
254
382
 
255
- # Try Tree-sitter first, then fallback
256
- module = None
257
- try:
258
- if self.ts_parser and self.ts_parser.is_available(language):
259
- module = self.ts_parser.parse(rel_path, content, language)
260
- except Exception as e:
261
- if self.verbose:
262
- log.debug("Tree-sitter parser failed for %s: %s", rel_path, e)
383
+ def _get_git_nonignored_files(self) -> Optional[List[Path]]:
384
+ """Return list of non-ignored files according to git, or None if unavailable."""
385
+ git_dir = self.root_path / '.git'
386
+ if not git_dir.exists():
387
+ return None
263
388
 
264
- if module is None:
265
- try:
266
- module = self.fallback_parser.parse(rel_path, content, language)
267
- except Exception as e:
268
- if self.verbose:
269
- log.debug("Fallback parser failed for %s: %s", rel_path, e)
270
- continue
389
+ try:
390
+ proc = subprocess.run(
391
+ ['git', '-C', str(self.root_path), 'ls-files', '-co', '--exclude-standard'],
392
+ check=False,
393
+ stdout=subprocess.PIPE,
394
+ stderr=subprocess.DEVNULL,
395
+ text=True,
396
+ )
397
+ except Exception:
398
+ return None
271
399
 
272
- if module:
273
- try:
274
- module.file_bytes = fp.stat().st_size
275
- except Exception:
276
- module.file_bytes = len(content.encode('utf-8', errors='ignore'))
277
- self.modules.append(module)
400
+ if proc.returncode != 0:
401
+ return None
402
+
403
+ files: List[Path] = []
404
+ for line in (proc.stdout or '').splitlines():
405
+ rel = (line or '').strip()
406
+ if not rel:
407
+ continue
408
+ files.append(self.root_path / rel)
409
+ return files
278
410
 
279
411
  def _detect_entrypoints(self) -> List[str]:
280
412
  """Detect project entry points."""
@@ -510,6 +510,7 @@ def _code2logic_llm_cli(argv: list[str]) -> None:
510
510
 
511
511
 
512
512
  def main(argv=None):
513
+ cli_start = time.time()
513
514
  parser = argparse.ArgumentParser(
514
515
  description='Analyze source code and generate logical representations',
515
516
  formatter_class=argparse.RawDescriptionHelpFormatter
@@ -644,6 +645,11 @@ Detail levels (columns in csv/json/yaml):
644
645
  action='store_true',
645
646
  help='Disable Tree-sitter (use fallback parser)'
646
647
  )
648
+ parser.add_argument(
649
+ '--no-gitignore',
650
+ action='store_true',
651
+ help='Do not respect .gitignore (scan all files under path)'
652
+ )
647
653
  parser.add_argument(
648
654
  '--no-similarity',
649
655
  action='store_true',
@@ -828,6 +834,7 @@ Detail levels (columns in csv/json/yaml):
828
834
  use_treesitter=not args.no_treesitter,
829
835
  verbose=args.verbose or args.debug,
830
836
  enable_similarity=not args.no_similarity,
837
+ respect_gitignore=not args.no_gitignore,
831
838
  )
832
839
  project = analyzer.analyze()
833
840
  analyze_time = time.time() - analyze_start
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
6
  name = "code2logic"
7
- version = "1.0.45"
7
+ version = "1.0.47"
8
8
  description = "Code2Logic - Source code to logical representation converter for LLM analysis, featuring Tree-sitter parsing, dependency graph analysis, and multi-language support."
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
File without changes
File without changes