提取python项目中的类关系

代码对对python项目中的父子类关系进行提取。当然目前只做到了简单的提取工作,具体的分析并没有做。由于python中支持多继承,因此当有非常多的类以后,这个图不知道怎么画比较合适,等以后有时间想出了好的解决方案再来实施。下面是具体的python代码

#!/bin/python3

import re
import os

class InfoCollector(object):

	def __init__(self):
		self.match_table = self._build_match_table()

		#class_relation store the known class relation
		self.class_relation = []

		#module_table used to map the short module name with full name
		self.module_table = {}

		self.classs = []

	def _build_match_table(self):
		''' lines match in the keys order '''
		keys = ['class', 'import_as', 'import', 'from_import_as', 'from_import']

		match_table = []
		for key in keys:
			regex = self.__getattribute__('_PATTERN_STR_' + key.upper())
			proc = self.__getattribute__('_proc_' + key + '_match')

			match_table.append((key, regex, proc, re.compile(regex)))

		return match_table

	_PATTERN_STR_CLASS = r"^class (.*)\((.*)\):$"

	def _proc_class_match(self, match):
		child_class = match.groups()[0].strip()
		parents_class = match.groups()[1].strip()

		print("child_class:%s parent_class:%s" % (child_class, parents_class))

		parents = parents_class.split(',')
		for parent in parents:
			parent = parent.strip()

			if '.' in parent:
				path, sp, klass = parent.rpartition('.')
				abs_path = self.module_table.get(path, path)
				parent_class = ':'.join([abs_path, klass])
			else:
				if parent in self.classs:
					parent_class = ':' + parent
					print(parent_class)
				else:
					parent_class = parent

			self.classs.append(child_class)
			self.class_relation.append((child_class, parent_class))


	_PATTERN_STR_IMPORT = r"^import (.*)"

	def _proc_import_match(self, match):
		module = match.groups()[0].strip()

		self.module_table[module] = module

		print("module name: %s" % module)

	_PATTERN_STR_IMPORT_AS = r"^import (.*) as (.*)"

	def _proc_import_as_match(self, match):
		module = match.groups()[0]
		module = module.strip()

		alias = match.groups()[1]
		alias = alias.strip()

		self.module_table[alias] = module

		print("module name: %s alias: %s" % (module, alias))

	_PATTERN_STR_FROM_IMPORT = r"^from (.*) import (.*)"

	def _proc_from_import_match(self, match):
		path = match.groups()[0]
		path = path.strip()

		module = match.groups()[1]
		module.strip()

		self.module_table[module] = '.'.join([path, module])

		print("path:%s module: %s" % (path, module))

	_PATTERN_STR_FROM_IMPORT_AS = r"^from (.*) import (.*) as (.*)"

	def _proc_from_import_as_match(self, match):
		path = match.groups()[0]
		path = path.strip()

		module = match.groups()[1]
		module = module.strip()

		alias = match.groups()[2]
		alias = alias.strip()

		self.module_table[alias] = '.'.join([path, module])
		print("path:%s module: %s alias: %s" % (path, module, alias))

	def update_with_single_line(self, line):
		for key, regex, proc, pattern in self.match_table:
			match = re.search(pattern, line)
			if match:
				proc(match)
				return
		return

	def update_with_full_file(self, file_name):
		self.reset()
		with open(file_name) as in_file:
			for line in in_file:
				self.update_with_single_line(line)

	def reset(self):
		self.module_table = {}
		self.class_relation = []
		self.classs = []

	def present_relations(self):
		print(self.class_relation)

class classFinder(object):

	def __init__(self, collector, dir_name):
		self._collector = collector
		self._dir = dir_name
		self.relations = []

	def update_with_file(self, full_file_name):
		module_name = full_file_name[len(self._dir):]
		module_name = module_name.replace(os.path.sep, '.')
		module_name = module_name.strip('.')

		self._collector.reset()
		with open(full_file_name) as in_file:
			for line in in_file:
				self._collector.update_with_single_line(line)

		for child, parent in self._collector.class_relation:
			if parent.startswith(':'):
				parent = module_name + parent

			self.relations.append((':'.join([module_name, child]), parent))

		self._collector.reset()

	def run(self):
		for path, dirs, files in os.walk(self._dir):
			files = [x for x in files if x.endswith('.py')]
			for _file in files:
				full_file_name = os.path.join(path, _file)
				self.update_with_file(full_file_name)

	def output_to_file(self, file_name):
		with open(file_name, 'w') as output_file:
			for pair in self.relations:
				output_file.write(str(pair) + '\n')


if __name__ == '__main__':
	DIR= 'abspath/to/cinder'

	collector = InfoCollector()

	finder = classFinder(collector, DIR)

	finder.run()

	finder.output_to_file('class_of_cinder')

该代码还有很多需要完善的地方,当前只是把代码的大体结构给完成了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值