Skip to content

Conversation

@slyang08
Copy link
Contributor

Summary

The check command supports three more optional features,

  1. --allow-circular-deps: Allow or not allow circular dependencies
  2. --select deps: Make warning if any circular dependencies in files
  3. --max-cycles N: Allow N cycles of circular dependencies
    These for better control code quality in Python project.

Type of Change

  • Bug fix (non-breaking change)
  • New feature (non-breaking change)
  • Breaking change
  • Documentation update
  • Performance improvement
  • Refactoring

Related Issues

Closes #175 for new feature made

Changes

Add files to implement the feature and Adjust the code to match the requirements in issue #175

Testing

  • make test passes locally
  • make lint passes locally
  • Added tests for new functionality (if applicable)
  • Manual testing completed (if applicable)

Documentation

  • Updated godoc comments
  • Updated README or other docs (if needed)

Additional Context

Result of usage

pyscn check --select deps

yang@Mac pyscn % ./pyscn check --select deps testdata/python/circular                 
🔍 Running quality check ()...
File: main.py has dependency on testdata/python/circular/player.py
File: physics.py has dependency on testdata/python/circular/player.py
File: player.py has dependency on testdata/python/circular/physics.py
player.py:6:1: circular dependency detected: player.py -> physics.py -> player.py
❌ Circular dependency check failed: too many circular dependencies
Error: too many circular dependencies
Usage:
  pyscn check [files...] [flags]

Flags:
      --allow-circular-deps   Allow circular dependencies (warnings only)
      --allow-dead-code       Allow dead code (don't fail)
  -c, --config string         Configuration file path
  -h, --help                  help for check
      --max-complexity int    Maximum allowed complexity (default 10)
      --max-cycles int        Maximum allowed circular dependency cycles before failing
  -q, --quiet                 Suppress output unless issues found
  -s, --select strings        Comma-separated list of analyses to run: complexity, deadcode, clones
      --skip-clones           Skip clone detection

Global Flags:
  -v, --verbose   Enable verbose output

yang@Mac pyscn % 

pyscn check --max-cycles 3

yang@Mac pyscn % ./pyscn check --max-cycles 3 testdata/python/circular 
🔍 Running quality check (complexity, deadcode, clones)...
File: main.py has dependency on testdata/python/circular/player.py
File: physics.py has dependency on testdata/python/circular/player.py
File: player.py has dependency on testdata/python/circular/physics.py
player.py:6:1: circular dependency detected: player.py -> physics.py -> player.py
❌ Found 1 quality issue(s)
yang@Mac pyscn %

pyscn check --allow-circular-deps

yang@Mac pyscn % ./pyscn check --allow-circular-deps testdata/python/circular         
🔍 Running quality check (complexity, deadcode, clones)...
File: main.py has dependency on testdata/python/circular/player.py
File: physics.py has dependency on testdata/python/circular/player.py
File: player.py has dependency on testdata/python/circular/physics.py
player.py:6:1: circular dependency detected: player.py -> physics.py -> player.py
! Found 1 circular dependency warning(s) (allowed by flag)
✅ Code quality check passed
yang@Mac pyscn % 

@slyang08 slyang08 marked this pull request as ready for review October 23, 2025 05:00
@slyang08 slyang08 force-pushed the feature/issue-175-circular-dependency-check branch from 8ee244d to f0512c0 Compare October 23, 2025 05:23
desiredStart := "a.py"
cycles := graph.DetectCyclesWithStart(desiredStart)

if len(cycles) != 1 {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this test (TestDetectCycles_NoCycle) should expect no circular dependencies but the code expect one cycles. len(cycles) != 0 should be correct. Could you check the behavour of this test?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will check it soon, thank you for the response

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I modified as len(cycles) != 0, and got the result as the following:

=== RUN   TestDetectCycles_NoCycle
--- PASS: TestDetectCycles_NoCycle (0.00s)


// Dynamically generate the prefix using the first path as the base, ensuring it ends with a slash
if len(args) > 0 {
c.prefix = strings.TrimSuffix(args[0], "/") + "/"
Copy link
Member

Choose a reason for hiding this comment

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

args[0]="." creates prefix="./", but parsed imports like "testdata/python/circular/player.py" don't start with "./". The strings.HasPrefix check always fails, leaving the graph empty.

I suggest that when args[0]=".", set prefix="" instead of "./".

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think the modification has matched what you were mentioned, and these are the result as I tested with . and testdata/python/circular

yang@Mac pyscn % ./pyscn check .                       
🔍 Running quality check (complexity, deadcode, clones)...
testdata/python/complex/comprehensions.py:0:1: __main__ is too complex (48 > 10)
...
testdata/python/edge_cases/nested_structures.py:0:1: __main__ is too complex (23 > 10)
testdata/python/complex/dead_code_complex.py:30:1: unreachable_after_return (critical)
testdata/python/complex/dead_code_complex.py:74:1: unreachable_after_raise (critical)
...
testdata/python/simple/dead_code_simple.py:60:1: unreachable_after_return (critical)
testdata/python/simple/dead_code_simple.py:12:1: unreachable_after_return (critical)
testdata/python/simple/dead_code_simple.py:34:1: unreachable_after_break (critical)
python/src/pyscn/mcp_main.py:14:1: clone of python/src/pyscn_mcp/__main__.py:14:1 (similarity: 100.0%)
testdata/python/edge_cases/python310_features.py:116:1: clone of testdata/python/simple/control_flow.py:133:1 (similarity: 99.3%)
testdata/python/edge_cases/python310_features.py:49:1: clone of testdata/python/edge_cases/python310_features.py:143:1 (similarity: 99.2%)
testdata/python/edge_cases/python310_features.py:32:1: clone of testdata/python/edge_cases/python310_features.py:94:1 (similarity: 99.0%)
...
testdata/python/edge_cases/dead_code_examples.py:110:1: clone of testdata/python/edge_cases/nested_structures.py:141:1 (similarity: 70.7%)
testdata/python/edge_cases/python310_features.py:94:1: clone of testdata/python/simple/classes.py:48:1 (similarity: 70.0%)
testdata/python/edge_cases/python310_features.py:32:1: clone of testdata/python/simple/classes.py:48:1 (similarity: 70.0%)
⚠️  Found 245 code clone(s) (informational)
testdata/python/circular/player.py:6:1: circular dependency detected: testdata/python/circular/player.py -> testdata/python/circular/physics.py -> testdata/python/circular/player.py
❌ Circular dependency check failed: too many circular dependencies
Error: too many circular dependencies
Usage:
  pyscn check [files...] [flags]

Flags:
      --allow-circular-deps   Allow circular dependencies (warnings only)
      --allow-dead-code       Allow dead code (don't fail)
  -c, --config string         Configuration file path
  -h, --help                  help for check
      --max-complexity int    Maximum allowed complexity (default 10)
      --max-cycles int        Maximum allowed circular dependency cycles before failing
  -q, --quiet                 Suppress output unless issues found
  -s, --select strings        Comma-separated list of analyses to run: complexity, deadcode, clones
      --skip-clones           Skip clone detection

Global Flags:
  -v, --verbose   Enable verbose output

yang@Mac pyscn % 
yang@Mac pyscn % ./pyscn check testdata/python/circular 
🔍 Running quality check (complexity, deadcode, clones)...
player.py:6:1: circular dependency detected: player.py -> physics.py -> player.py
❌ Circular dependency check failed: too many circular dependencies
Error: too many circular dependencies
Usage:
  pyscn check [files...] [flags]

Flags:
      --allow-circular-deps   Allow circular dependencies (warnings only)
      --allow-dead-code       Allow dead code (don't fail)
  -c, --config string         Configuration file path
  -h, --help                  help for check
      --max-complexity int    Maximum allowed complexity (default 10)
      --max-cycles int        Maximum allowed circular dependency cycles before failing
  -q, --quiet                 Suppress output unless issues found
  -s, --select strings        Comma-separated list of analyses to run: complexity, deadcode, clones
      --skip-clones           Skip clone detection

Global Flags:
  -v, --verbose   Enable verbose output

yang@Mac pyscn % 

imported := matches[1]
// Convert dotted module path to relative file path, e.g., 'player.module' => 'player/module.py'
importedRelPath := strings.ReplaceAll(imported, ".", "/") + ".py"
fmt.Printf("File: %s has dependency on %s\n", relPath, importedRelPath)
Copy link
Member

Choose a reason for hiding this comment

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

service/circular_dependency_service.go:199 prints every import statement unconditionally. This causes thousands of lines of output on large projects. Maybe better to remove this print statement.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, I will remove this print function to get clear result.

But does not need to print anything like A dependency on B message on the result?

Copy link
Contributor

Choose a reason for hiding this comment

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

A plain “A imports B” dependency is just noise for the user, and dumping thousands of lines buries the circular-dependency warnings they actually care about. What we need to show are only the warnings when a cycle is detected, so printing the full dependency list isn’t the right behavior.

@DaisukeYoda
Copy link
Member

@slyang08 Hello thank you for working on this PR. Could you check the comments that I found during my review? Thanks!

@slyang08 slyang08 force-pushed the feature/issue-175-circular-dependency-check branch from f0512c0 to f18bd44 Compare October 23, 2025 18:26
@LudoTechnologies
Copy link
Contributor

I found that our test fails because pyscn check doesn’t recognize the deps/circular selector. Could you amend cmd/pyscn/check.go so those options are accepted and the test passes?

You can check the tests with make build && make test

@LudoTechnologies
Copy link
Contributor

Also there is a lint issue. golangci-lint flags cmd/pyscn/check.go:147 with “ineffectual assignment to skipCircular” because we reassign the variable immediately afterward. We’ll need to tidy up that initialization so make lint stops complaining.

@slyang08 slyang08 force-pushed the feature/issue-175-circular-dependency-check branch from f18bd44 to 8b3d1c4 Compare October 23, 2025 19:32
@slyang08
Copy link
Contributor Author

slyang08 commented Oct 23, 2025

I am trying to make sure it will accept deps as selector.
Or should I add circular as selector as well?

When I tested with make build && make test that I always got FAIL and there is one line kept showing Warning: Failed to read file ../testdata/non_existent_file.py: failed to read file ../testdata/non_existent_file.py: open ../testdata/non_existent_file.py: no such file or directory
It seems not from this new feature, and what should I do for passing this CI?

@DaisukeYoda
Copy link
Member

I am trying to make sure it will accept deps as selector. Or should I add circular as selector as well?

Yes, please make the CLI accept both aliases. The README already advertises --select deps, and earlier revisions used --select circular, so supporting both keeps the UX consistent.

Regarding the warning: Failed to read, it comes from existing service-layer tests that deliberately exercise a missing-file code path. It isn’t new and it isn’t fatal. Don't worry.

@slyang08 slyang08 force-pushed the feature/issue-175-circular-dependency-check branch from 8b3d1c4 to 9ba4e97 Compare October 24, 2025 16:27
@slyang08
Copy link
Contributor Author

slyang08 commented Oct 24, 2025

I am trying to make sure it will accept deps as selector. Or should I add circular as selector as well?

Yes, please make the CLI accept both aliases. The README already advertises --select deps, and earlier revisions used --select circular, so supporting both keeps the UX consistent.

Regarding the warning: Failed to read, it comes from existing service-layer tests that deliberately exercise a missing-file code path. It isn’t new and it isn’t fatal. Don't worry.

Hi DaisukeYoda, I made two optionals available to improve UX

The following were the testing results I did:

Use circular

yang@YangdeMacBook-Pro pyscn % ./pyscn check --select circular testdata/python/circular                      
🔍 Running quality check ()...
player.py:6:1: circular dependency detected: player.py -> physics.py -> player.py
❌ Circular dependency check failed: too many circular dependencies
Error: too many circular dependencies
Usage:
  pyscn check [files...] [flags]

Flags:
      --allow-circular-deps   Allow circular dependencies (warnings only)
      --allow-dead-code       Allow dead code (don't fail)
  -c, --config string         Configuration file path
  -h, --help                  help for check
      --max-complexity int    Maximum allowed complexity (default 10)
      --max-cycles int        Maximum allowed circular dependency cycles before failing
  -q, --quiet                 Suppress output unless issues found
  -s, --select strings        Comma-separated list of analyses to run: complexity, deadcode, clones
      --skip-clones           Skip clone detection

Global Flags:
  -v, --verbose   Enable verbose output

yang@YangdeMacBook-Pro pyscn % 

Use deps

yang@YangdeMacBook-Pro pyscn % ./pyscn check --select deps testdata/python/circular 
🔍 Running quality check ()...
player.py:6:1: circular dependency detected: player.py -> physics.py -> player.py
❌ Circular dependency check failed: too many circular dependencies
Error: too many circular dependencies
Usage:
  pyscn check [files...] [flags]

Flags:
      --allow-circular-deps   Allow circular dependencies (warnings only)
      --allow-dead-code       Allow dead code (don't fail)
  -c, --config string         Configuration file path
  -h, --help                  help for check
      --max-complexity int    Maximum allowed complexity (default 10)
      --max-cycles int        Maximum allowed circular dependency cycles before failing
  -q, --quiet                 Suppress output unless issues found
  -s, --select strings        Comma-separated list of analyses to run: complexity, deadcode, clones
      --skip-clones           Skip clone detection

Global Flags:
  -v, --verbose   Enable verbose output

yang@YangdeMacBook-Pro pyscn % 

@slyang08
Copy link
Contributor Author

I made some changes after I saw the recommendation by Claude Code.
The first one I ran make build && make test that kept getting error about path.
The second one I did and it ran okay.

@slyang08 slyang08 force-pushed the feature/issue-175-circular-dependency-check branch from 9ba4e97 to b3e1b12 Compare October 27, 2025 04:33
@DaisukeYoda
Copy link
Member

Hello,
I am reviewing the implementation and seeing some issues (there might be other issues which was suggested by Claude) . I think the main problems are the below two that cause test failure:

  1. Path prefix matching fails in most cases
    The code compares module-style import paths (testdata/python/circular/physics.py) against filesystem prefixes (../../testdata/python/) at service/circular_dependency_service.go:205. This fails for relative paths, absolute paths, and different working directories.

  2. --max-cycles flag doesn't work
    cmd/pyscn/check.go:209 adds circularIssues to issueCount unconditionally, even when cycles are within the allowed threshold. So --max-cycles 1 still fails with 1 cycle detected.

@slyang08
Could you check these points? Many thanks.

@slyang08
Copy link
Contributor Author

slyang08 commented Oct 28, 2025

Hi DaisukeYoda,
I improved my code with path and made --max-cycles flag working

All the testing I tested as the following pictures:

test case: --select deps with --max-cycles

Screenshot 2025-10-28 at 18 26 22

test case: --select circular with --max-cycles

Screenshot 2025-10-28 at 18 27 04

test case: make build && make test with make lint

Screenshot 2025-10-28 at 18 28 13

test case: go test -v ./cmd/pyscn

Screenshot 2025-10-28 at 18 28 54

If you think these test cases are okay, I will push the latest version.

@DaisukeYoda
Copy link
Member

@slyang08 Thanks! Yes, your screenshot looks good. Please push your latest version.

@slyang08 slyang08 force-pushed the feature/issue-175-circular-dependency-check branch from b3e1b12 to 3776875 Compare October 29, 2025 02:17
@DaisukeYoda
Copy link
Member

@slyang08
Thanks for the fixes—the tests are green on my side now. There’s just one more thing to double-check: the --max-cycles flag doesn’t seem to honor the limit yet. Even when the detected cycle count is within the configured threshold we still exit with status 1, so the flag isn’t providing the expected grace. Could you adjust the issue counting/exit logic so that cycles up to the allowed maximum are treated as non-blocking?

@slyang08
Copy link
Contributor Author

Test case: --select circular with --max-cycles and --allow-circular-deps

Screenshot 2025-10-29 at 16 13 00

Test case: --select deps with --max-cycles and --allow-circular-deps

Screenshot 2025-10-29 at 16 11 20

@slyang08 slyang08 force-pushed the feature/issue-175-circular-dependency-check branch from 3776875 to b8f9329 Compare October 29, 2025 20:15
@DaisukeYoda
Copy link
Member

@slyang08

Appreciate all the revisions you’ve made so far. Now what I’m seeing:

  • In service/circular_dependency_service.go, both the source file (relPath) and the imported module (importedRelPath) are collapsed via filepath.
  • The implementation skips our existing dependency pipeline entirely. We already parse Python files via tree-sitter, build the dependency graph, and detect cycles using Tarjan’s algorithm in internal/analyzer/circular_detector.go. This PR reimplements the same thing with regexes and another graph, duplicating logic and drifting from our architecture.
  • The summary branch in cmd/pyscn/check.go (if c.allowCircularDeps && issueCount == c.circularIssueCount) never fires, so the README promise of ! Found … circular dependency warning(s) is currently unreachable.

Could we rework this PR to reuse the existing SystemAnalysisService / CircularDependencyDetector instead of maintaining a parallel implementation? If check calls into AnalyzeDependencies, we get the same CircularDependencies data structure that feeds the HTML report (and PR176) for free. Then --max-cycles and --allow-circular-deps can just operate on that result, and we avoid maintaining two different detectors.

If you find any difficulites, I am pleased to share my sample codes.

@slyang08
Copy link
Contributor Author

slyang08 commented Oct 30, 2025

Hi @DaisukeYoda ,

If any possible, can you share your code, please?

New info, I can track the circular dependency by the files and functions that you mentioned. However, I stuck at showing line and column right now.

@DaisukeYoda
Copy link
Member

Hi @slyang08,

I've created a reference implementation in PR #220 that you can use! It reuses the existing internal/analyzer components as we discussed.

Key Implementation Details

Line/Column Tracking

For the check command, we use a simplified approach since precise import positions aren't critical for CI/CD:

func (c *CheckCommand) checkCircularDependencies(cmd *cobra.Command, args []string) (int, error) {
    // ... module analyzer setup ...
    
    graph, err := moduleAnalyzer.AnalyzeProject()
    result := analyzer.DetectCircularDependencies(graph)
    
    // Output in linter format
    for _, cycle := range result.CircularDependencies {
        firstModule := cycle.Modules[0]
        node := graph.Nodes[firstModule]
        
        // Simple approach: use line 1 for now
        cyclePath := strings.Join(cycle.Modules, " -> ")
        fmt.Fprintf(cmd.ErrOrStderr(), "%s:1:1: circular dependency detected: %s\n",
            node.FilePath, cyclePath)
    }
    
    return result.TotalCycles, nil
}

Why Line 1?

The existing analyzer infrastructure doesn't currently track exact import statement positions in the dependency graph. For check command purposes:

  • Line 1 is acceptable - CI/CD tools and linters can still jump to the file
  • The important info is the cycle path (module1 -> module2 -> module1)
  • Users can see which files are involved

If You Need Precise Lines

To get actual import line numbers, you'd need to:

  1. Extend DependencyEdge struct in internal/analyzer/dependency_graph.go:
type DependencyEdge struct {
    From       string
    To         string
    EdgeType   DependencyEdgeType
    ImportInfo *ImportInfo  // This already has Line field!
}
  1. Use the ImportInfo when outputting:
// In checkCircularDependencies
for _, cycle := range result.CircularDependencies {
    if len(cycle.Dependencies) > 0 {
        firstDep := cycle.Dependencies[0]
        // cycle.Dependencies already contains the import info
        // but you need to map it back to the edge in the graph
    }
}

However, this adds complexity for minimal benefit in the check command use case.

Full Code

You can see the complete implementation here:

The implementation is only 58 lines and reuses all existing components. No need for regex or custom graph implementations!

Let me know if you have any questions about the approach.

@DaisukeYoda
Copy link
Member

Sorry for late response!

@slyang08
Copy link
Contributor Author

slyang08 commented Nov 6, 2025

Hi @DaisukeYoda,

Sorry to modify the code late.
I got reference from your sample code, and used them.
I tested what you shared and made Line and Column show on the screen
Screenshot 2025-11-06 at 15 14 43

But I cannot be sure is the column showing accurately in every Python files; therefore, I did a test case for Node Columns in new_commands_test.go file:

func TestNodeColumns(t *testing.T) {
	testDir := filepath.Join("..", "..", "testdata", "python")
	err := filepath.Walk(testDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() || !strings.HasSuffix(path, ".py") {
			return nil
		}

		source, err := os.ReadFile(path)
		if err != nil {
			t.Errorf("failed to read file %s: %v", path, err)
			return nil
		}

		p := parser.New() // Initialized the Parser
		result, err := p.Parse(context.Background(), source)
		if err != nil {
			t.Errorf("parsing failed for %s: %v", path, err)
			return nil
		}

		root := result.AST
		if root == nil {
			t.Errorf("AST is nil for %s", path)
			return nil
		}

		checkNodeColumns(t, root, source, path)
		return nil
	})
	if err != nil {
		t.Fatalf("failed to walk test directory: %v", err)
	}
}

func checkNodeColumns(t *testing.T, node *parser.Node, src []byte, filename string) {
	lines := strings.Split(string(src), "\n")

	// Start and End positions
	startLine := node.Location.StartLine - 1
	startCol := node.Location.StartCol - 1
	endLine := node.Location.EndLine - 1
	endCol := node.Location.EndCol - 1

	// Check StartLine and EndLine
	if startLine < 0 || startLine >= len(lines) {
		t.Errorf("[%s] Node %s start line out of range: %d", filename, node.Type, node.Location.StartLine)
	} else if endLine < 0 || endLine >= len(lines) {
		t.Errorf("[%s] Node %s end line out of range: %d", filename, node.Type, node.Location.EndLine)
	} else {
		// StartCol and EndCol
		lineLen := len(lines[startLine])
		if startCol < 0 || startCol > lineLen {
			t.Errorf("[%s] Node %s start column out of range: %d (line length %d)", filename, node.Type, node.Location.StartCol, lineLen)
		}

		lineLenEnd := len(lines[endLine])
		if endCol < 0 || endCol > lineLenEnd {
			t.Errorf("[%s] Node %s end column out of range: %d (line length %d)", filename, node.Type, node.Location.EndCol, lineLenEnd)
		}

		// Verify whether the source code corresponding to the node is valid
		if startLine <= endLine {
			var nodeText string
			if startLine == endLine {
				if startCol <= endCol && endCol <= len(lines[startLine]) {
					nodeText = lines[startLine][startCol:endCol]
				} else {
					t.Errorf("[%s] Node %s start/end columns invalid: start %d, end %d (line length %d)", filename, node.Type, node.Location.StartCol, node.Location.EndCol, len(lines[startLine]))
				}
			} else {
				// Multi-line node: Extract the first and last parts
				firstLinePart := lines[startLine][startCol:]
				lastLinePart := lines[endLine][:endCol]
				nodeText = firstLinePart + "\n" + lastLinePart
			}

			if len(strings.TrimSpace(nodeText)) == 0 {
				t.Logf("[%s] Node %s at lines %d-%d may be empty or whitespace", filename, node.Type, node.Location.StartLine, node.Location.EndLine)
			}
		}
	}

	// Recursively check child nodes
	for _, child := range node.Children {
		checkNodeColumns(t, child, src, filename)
	}
}

If you think the test case is unnecessary, I will delete them.

@DaisukeYoda
Copy link
Member

@slyang08
Thanks for your suggention. TestNodeColumns looks solid, but I'd move it to a separate PR and keeps PR213 focused on the check command feature itself. Sound good?

@slyang08
Copy link
Contributor Author

slyang08 commented Nov 7, 2025

Thanks for your suggention. TestNodeColumns looks solid, but I'd move it to a separate PR and keeps PR213 focused on the check command feature itself. Sound good?

Hi @DaisukeYoda,
I would like to confirm once again that what you want in this PR is just about ./pyscn check feature, so when the user uses ./pyscn check --select deps testdata/python/circular_deps_test and got the error, it won't show the error comes from which line and which column, right?
Or keeps the error message showing line and column, but no test case this PR?

@slyang08 slyang08 force-pushed the feature/issue-175-circular-dependency-check branch from b8f9329 to 54ea9bc Compare November 12, 2025 01:00
@DaisukeYoda
Copy link
Member

Yes, I'd like to confirm the former option.

@slyang08 slyang08 force-pushed the feature/issue-175-circular-dependency-check branch from 54ea9bc to f757b81 Compare November 13, 2025 17:06
@slyang08
Copy link
Contributor Author

slyang08 commented Nov 19, 2025

Hi,
I made the code as the first option and showed module1.py:1:1: circular dependency detected: module1 -> module2 -> module1 with Line and Column as 1 and 1.

If you have any concern that please tell me to modify once again.

@DaisukeYoda
Copy link
Member

@slyang08
Sorry for taking so long. This looks good and ready to merge now.

Thanks for sticking with all the review feedback. I really appreciate your contribution!

I'll try to maintain the repo more actively, so please keep contributing if you're interested. Thanks! 🙏

@DaisukeYoda DaisukeYoda self-requested a review November 20, 2025 08:44
@DaisukeYoda DaisukeYoda merged commit 42bb181 into ludo-technologies:main Nov 20, 2025
4 checks passed
Sign up for free to 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.

[FEATURE] Add circular dependency detection to check command

3 participants