@@ -684,6 +684,72 @@ describe("detectTechnologies (monorepo)", () => {
684684 } ) ;
685685} ) ;
686686
687+ // ── Python detection ─────────────────────────────────────────
688+
689+ describe ( "detectTechnologies (Python)" , ( ) => {
690+ const tmp = useTmpDir ( ) ;
691+
692+ it ( "detects Python from requirements.txt" , ( ) => {
693+ writeFile ( tmp . path , "requirements.txt" , "flask==3.0.0" ) ;
694+ const { detected } = detectTechnologies ( tmp . path ) ;
695+ ok ( detected . some ( ( t ) => t . id === "python" ) ) ;
696+ } ) ;
697+
698+ it ( "detects Python from pyproject.toml" , ( ) => {
699+ writeFile ( tmp . path , "pyproject.toml" , "[project]\nname = 'myapp'" ) ;
700+ const { detected } = detectTechnologies ( tmp . path ) ;
701+ ok ( detected . some ( ( t ) => t . id === "python" ) ) ;
702+ } ) ;
703+
704+ it ( "detects Python from setup.py" , ( ) => {
705+ writeFile ( tmp . path , "setup.py" , "from setuptools import setup" ) ;
706+ const { detected } = detectTechnologies ( tmp . path ) ;
707+ ok ( detected . some ( ( t ) => t . id === "python" ) ) ;
708+ } ) ;
709+
710+ it ( "detects Python from Pipfile" , ( ) => {
711+ writeFile ( tmp . path , "Pipfile" , "[packages]\nflask = '*'" ) ;
712+ const { detected } = detectTechnologies ( tmp . path ) ;
713+ ok ( detected . some ( ( t ) => t . id === "python" ) ) ;
714+ } ) ;
715+
716+ it ( "detects Python from manage.py (Django)" , ( ) => {
717+ writeFile ( tmp . path , "manage.py" , "#!/usr/bin/env python" ) ;
718+ const { detected } = detectTechnologies ( tmp . path ) ;
719+ ok ( detected . some ( ( t ) => t . id === "python" ) ) ;
720+ } ) ;
721+
722+ it ( "does NOT detect web frontend for Python project with .html templates" , ( ) => {
723+ writeFile ( tmp . path , "requirements.txt" , "flask==3.0.0" ) ;
724+ writeFile ( tmp . path , "templates/index.html" , "<html><body>Hello</body></html>" ) ;
725+ const { isFrontend } = detectTechnologies ( tmp . path ) ;
726+ strictEqual ( isFrontend , false ) ;
727+ } ) ;
728+
729+ it ( "does NOT detect web frontend for Django project with templates" , ( ) => {
730+ writeFile ( tmp . path , "manage.py" , "#!/usr/bin/env python" ) ;
731+ writeFile ( tmp . path , "templates/base.html" , "{% block content %}{% endblock %}" ) ;
732+ writeFile ( tmp . path , "static/style.css" , "body { margin: 0 }" ) ;
733+ const { isFrontend } = detectTechnologies ( tmp . path ) ;
734+ strictEqual ( isFrontend , false ) ;
735+ } ) ;
736+
737+ it ( "detects frontend when both Python and frontend framework are present" , ( ) => {
738+ writeFile ( tmp . path , "requirements.txt" , "flask==3.0.0" ) ;
739+ writePackageJson ( tmp . path , { dependencies : { react : "^19" } } ) ;
740+ const { isFrontend } = detectTechnologies ( tmp . path ) ;
741+ strictEqual ( isFrontend , true ) ;
742+ } ) ;
743+
744+ it ( "returns correct skills (empty) for Python detection" , ( ) => {
745+ writeFile ( tmp . path , "requirements.txt" , "flask==3.0.0" ) ;
746+ const { detected } = detectTechnologies ( tmp . path ) ;
747+ const python = detected . find ( ( t ) => t . id === "python" ) ;
748+ ok ( python ) ;
749+ deepStrictEqual ( python . skills , [ ] ) ;
750+ } ) ;
751+ } ) ;
752+
687753// ── detectCombos ──────────────────────────────────────────────
688754
689755describe ( "detectCombos" , ( ) => {
0 commit comments