Skip to main content
Glama
python-parser.ts5.2 kB
import * as path from 'path'; import { BaseLanguageParser } from './base/BaseLanguageParser.js'; import { EntityFactory } from './base/EntityFactory.js'; import { RelationshipBuilder } from './base/RelationshipBuilder.js'; import { PythonContentExtractor } from './extractors/python/PythonContentExtractor.js'; import { PythonClassParser } from './entity-parsers/python/PythonClassParser.js'; import { PythonFunctionParser } from './entity-parsers/python/PythonFunctionParser.js'; import { PythonAnnotationExtractor } from './extractors/python/PythonAnnotationExtractor.js'; import { PythonMethodCallExtractor } from './extractors/python/PythonMethodCallExtractor.js'; import { ParsedEntity, ParsedRelationship, ParseError } from '../types.js'; export class PythonParser extends BaseLanguageParser { private contentExtractor = new PythonContentExtractor(); private classParser = new PythonClassParser(); private functionParser = new PythonFunctionParser(); private annotationExtractor = new PythonAnnotationExtractor(); private methodCallExtractor = new PythonMethodCallExtractor(); canParse(filePath: string): boolean { const ext = path.extname(filePath).toLowerCase(); return ext === '.py'; } async parseFile(filePath: string, content: string, projectId: string): Promise<{ entities: ParsedEntity[]; relationships: ParsedRelationship[]; errors: ParseError[]; }> { this.setCurrentProject(projectId); const entities: ParsedEntity[] = []; const relationships: ParsedRelationship[] = []; const errors: ParseError[] = []; try { // Extract basic content structure const extractionResult = this.contentExtractor.extractContent(content, filePath); const moduleName = extractionResult.moduleName || this.getModuleFromPath(filePath); const moduleId = moduleName; // Create module entity if (moduleName !== '__main__') { const moduleEntity = EntityFactory.createModule( moduleId, moduleName, moduleName, filePath, `Python module: ${moduleName}` ); this.addEntity(entities, moduleEntity); } // Parse different entity types using specialized parsers this.classParser.parseClasses( content, filePath, moduleName, entities, relationships, (entity) => this.addEntity(entities, entity), (rel) => this.addRelationship(relationships, rel) ); this.functionParser.parseFunctions( content, filePath, moduleName, entities, relationships, (entity) => this.addEntity(entities, entity), (rel) => this.addRelationship(relationships, rel) ); // Parse enums and module-level attributes this.parseEnums(content, filePath, moduleName, entities, relationships); this.parseModuleAttributes(content, filePath, moduleName, entities, relationships); } catch (error) { this.addError(errors, { message: `Failed to parse Python file: ${error instanceof Error ? error.message : 'Unknown error'}`, line: 1, file_path: filePath }); } return { entities, relationships, errors }; } private parseEnums( content: string, filePath: string, moduleName: string, entities: ParsedEntity[], relationships: ParsedRelationship[] ): void { const extractionResult = this.contentExtractor.extractContent(content, filePath); for (const parsedEnum of extractionResult.enums) { const enumId = `${moduleName}.${parsedEnum.name}`; const qualifiedName = `${moduleName}.${parsedEnum.name}`; const enumEntity = EntityFactory.createEnum( enumId, parsedEnum.name, qualifiedName, filePath, parsedEnum.startLine, parsedEnum.endLine, parsedEnum.modifiers ); this.addEntity(entities, enumEntity); this.addRelationship(relationships, RelationshipBuilder.createBelongsTo(enumId, moduleName, filePath)); } } private parseModuleAttributes( content: string, filePath: string, moduleName: string, entities: ParsedEntity[], relationships: ParsedRelationship[] ): void { const extractionResult = this.contentExtractor.extractContent(content, filePath); for (const parsedField of extractionResult.fields) { const fieldId = `${moduleName}.${parsedField.name}`; const qualifiedName = `${moduleName}.${parsedField.name}`; const fieldEntity = EntityFactory.createField( fieldId, parsedField.name, qualifiedName, filePath, parsedField.startLine, parsedField.endLine, parsedField.modifiers ); this.addEntity(entities, fieldEntity); this.addRelationship(relationships, RelationshipBuilder.createBelongsTo(fieldId, moduleName, filePath)); } } private getModuleFromPath(filePath: string): string { const normalized = path.normalize(filePath); const parsed = path.parse(normalized); if (parsed.name === '__init__') { // For __init__.py files, use the directory name return path.basename(parsed.dir); } return parsed.name; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/JonnoC/CodeRAG'

If you have feedback or need assistance with the MCP directory API, please join our Discord server