Factory method in python

I am working on the following small project: https://github.com/AndreaCrotti/project-organizer

The short goal is much easier to manage many different projects. One of the useful things is a way to automatically determine the type of project I'm working on, correctly configure some commands.

Right now I am using the match function of the class and the discovery function, which iterates over the various matches. I am sure there may be a better design for this, but he cannot find it.

Any ideas?

class ProjectType(object): build_cmd = "" @classmethod def match(cls, _): return True class PythonProject(ProjectType): build_cmd = "python setup.py develop --user" @classmethod def match(cls, base): return path.isfile(path.join(base, 'setup.py')) class AutoconfProject(ProjectType): #TODO: there should be also a way to configure it build_cmd = "./configure && make -j3" @classmethod def match(cls, base): markers = ('configure.in', 'configure.ac', 'makefile.am') return any(path.isfile(path.join(base, x)) for x in markers) class MakefileOnly(ProjectType): build_cmd = "make" @classmethod def match(cls, base): # if we can count on the order the first check is not useful return (not AutoconfProject.match(base)) and \ (path.isfile(path.join(base, 'Makefile'))) def detect_project_type(path): prj_types = (PythonProject, AutoconfProject, MakefileOnly, ProjectType) for p in prj_types: if p.match(path): return p() 
+4
source share
2 answers

This is the wise use of the factory function as a class method.

One possible improvement is that all classes inherit from one parent class, which would have one cool method that would include all the logic in detect_project_type .

Perhaps something like this will work:

 class ProjectType(object): build_cmd = "" markers = [] @classmethod def make_project(cls, path): prj_types = (PythonProject, AutoconfProject, MakefileOnly, ProjectType) for p in prj_types: markers = p.markers if any(path.isfile(path.join(path, x)) for x in markers): return p() class PythonProject(ProjectType): build_cmd = "python setup.py develop --user" markers = ['setup.py'] class AutoconfProject(ProjectType): #TODO: there should be also a way to configure it build_cmd = "./configure && make -j3" markers = ['configure.in', 'configure.ac', 'makefile.am'] class MakefileOnly(ProjectType): build_cmd = "make" markers = ['Makefile'] 
+4
source

It looks great to me, although I would make two improvements.

1- Use a metaclass to automatically collect all ProjectTypes, rather than manually listing them, which will avoid skipping any type of project by mistake or in the wrong order, for example.

 class ProjectTypeManger(type): klasses = [] def __new__(meta, classname, bases, classDict): klass = type.__new__(meta, classname, bases, classDict) meta.klasses.append(klass) return klass @classmethod def detect_project_type(meta, path): for p in meta.klasses: if p.match(path): return p() class ProjectType(object): __metaclass__ = ProjectTypeManger build_cmd = "" @classmethod def match(cls, _): return None 

The 2- match method should return the object itself, not true / false. Thus, the class can configure the object anyway, it wants + you can call the base class mapping method, for example. MakefileOnly can be inferred from AutoconfProject so that it first checks the base class for any matches, but is not sure if such inheritance makes sense

 class MakefileOnly(AutoconfProject): build_cmd = "make" @classmethod def match(cls, base): ret = super(MakefileOnly, cls).match(base) if ret is not None: return ret if path.isfile(path.join(base, 'Makefile')): return cls() return None 
+2
source

Source: https://habr.com/ru/post/1381210/


All Articles