From 818ed36181dc215c9c5d79eb37fc28f51722b505 Mon Sep 17 00:00:00 2001 From: Jeffrey Marvin Forones Date: Sat, 28 Oct 2017 13:24:54 +0800 Subject: [PATCH] refactor --- core.py | 117 +------------------------------------------ module_router.py | 116 ++++++++++++++++++++++++++++++++++++++++++ package_extractor.py | 45 +++++++++++++++++ 3 files changed, 163 insertions(+), 115 deletions(-) create mode 100644 module_router.py create mode 100644 package_extractor.py diff --git a/core.py b/core.py index b7a345e..3058fb0 100644 --- a/core.py +++ b/core.py @@ -1,6 +1,4 @@ -import pkgutil -import os -import inspect +from package_extractor import PackageExtractor """ Description:: Initialize the blueprints inside in the root folder @@ -26,115 +24,4 @@ def __init__(self, app, root_path): self.root_path = root_path """ register blueprint to the current path """ - self.add_blueprint(root_path) - - def directory_path(self, path): - - """ get all the list of files and directories """ - for file in os.listdir(path): - - """ prevent __pycache__ directory or any directory that has __ """ - if "__" not in file: - """ get the full path directory """ - dir_file = path + '/' + file - - """ check is the path is a directory - only directories are picked - """ - if os.path.isdir(dir_file): - """ register blueprint on the directory """ - self.add_blueprint(dir_file) - - """ find sub directories on each directory found """ - self.directory_path(path=dir_file) - - @staticmethod - def blueprint_name(name): - """ set index automatically as home page """ - if "index" in name: - name = str(name).replace("index", "") - if "routes" in name: - name = str(name).replace("routes", "") - - """ remove the last . in the string it it ends with a . - for the url structure must follow the flask routing format - it should be /model/method instead of /model/method/ - """ - if name[-1:] == ".": - name = name[:-1] - http_name = str(name).replace(".", "/") - print(http_name) - return http_name - - @staticmethod - def get_http_methods(names): - if isinstance(names, list): - methods = [] - - for name in names: - if "__" not in name: - if name == "index": - methods.append('GET') - elif name == "create": - methods.append('POST') - elif name == "update": - methods.append('PUT') - elif name == "destroy": - methods.append('DELETE') - else: - methods.append('GET') - - return methods - else: - raise TypeError("names must be a list") - - def model_add_router(self, mod): - if hasattr(mod, '__routes__'): - for route in mod.__routes__: - if inspect.isclass(route[2]): - """ If it's a class it needs to extract the methods by function names - magic functions are excluded - """ - route_name, slug, cls = route - for (fn_name, fn_object) in self.get_cls_fn_members(cls): - if inspect.isfunction(fn_object): - mod.__method__.add_url_rule( - rule=slug, - endpoint=fn_name, - view_func=fn_object, - methods=self.get_http_methods([fn_name])) - else: - raise KeyError("Member is not a function.") - - elif inspect.isfunction(route[2]): - route_name, slug, fn, methods = route - - mod.__method__.add_url_rule( - rule=slug, - endpoint=fn.__name__, - view_func=fn, - methods=methods) - - @staticmethod - def get_cls_fn_members(cls): - return [member for member in inspect.getmembers(cls, predicate=inspect.isfunction)] - - def add_blueprint(self, path): - - """ find all packages in the current path """ - for loader, name, is_pkg in pkgutil.walk_packages(path, prefix="", onerror=None): - """ if module found load module and save all attributes in the module found """ - mod = loader.find_module(name).load_module(name) - - """ find the attribute method on each module """ - if hasattr(mod, '__method__'): - self.model_add_router(mod) - root_module = self.root_path.replace(".", "") - url_prefix_name = str(name).replace(root_module, "") - """ register to the blueprint if method attribute found """ - self.__app.register_blueprint(mod.__method__, url_prefix=self.blueprint_name(url_prefix_name)) - - else: - """ prompt not found notification """ - # print('{} has no module attribute method'.format(mod)) - pass + PackageExtractor(application=app, path=root_path) diff --git a/module_router.py b/module_router.py new file mode 100644 index 0000000..bbc53f8 --- /dev/null +++ b/module_router.py @@ -0,0 +1,116 @@ +import inspect + + +class ModuleRouter: + def __init__(self, mod): # module + self._module = mod + if self._is_valid_module(): + self.model_add_router() + + def model_add_router(self): + if hasattr(self._module, '__routes__') and len(self._module.__routes__): + route_type, route_data = self._routing_type(route=self._module.__routes__.pop(0)) + if route_type == 'cls': + """ If it's a class it needs to extract the methods by function names + magic functions are excluded + """ + route_name, slug, cls = route_data + self.class_member_route(route=route_data, members=self.get_cls_fn_members(cls)) + + elif route_type == 'fn': + route_name, slug, fn, methods = route_data + + self._module.__method__.add_url_rule( + rule=slug, + endpoint=fn.__name__, + view_func=fn, + methods=methods) + self.model_add_router() + + def _is_valid_module(self): + return hasattr(self._module, '__routes__') or hasattr(self._module, '__method__') + + @staticmethod + def _routing_type(route): + __type = None + if isinstance(route, tuple): + if len(route) == 3 and inspect.isclass(route[2]): + __type = 'cls' + elif len(route) == 4 and inspect.isfunction(route[2]): + if isinstance(route[3], (list, tuple, set)): + __type = 'fn' + else: + raise TypeError("methods must be a list.") + else: + raise TypeError("Invalid route syntax.") + return __type, route + + @staticmethod + def get_http_methods(names): + if isinstance(names, list): + methods = [] + + for name in names: + if "__" not in name: + if name == "index": + methods.append('GET') + elif name == "create": + methods.append('POST') + elif name == "update": + methods.append('PUT') + elif name == "destroy": + methods.append('DELETE') + else: + methods.append('GET') + + return methods + else: + raise TypeError("names must be a list") + + @staticmethod + def get_cls_fn_members(cls): + return [member for member in inspect.getmembers(cls, predicate=inspect.isfunction)] + + def class_member_route(self, route, members): + if isinstance(members, (list, set)): + if len(members): + (fn_name, fn_object) = members.pop(0) + route_name, slug, cls = route + if inspect.isfunction(fn_object): + self._module.__method__.add_url_rule( + rule=slug, + endpoint=fn_name, + view_func=fn_object, + methods=self.get_http_methods([fn_name])) + else: + raise KeyError("Member is not a function.") + self.class_member_route(route, members) + else: + raise TypeError("members must be a list.") + + def register_route(self, app, name): + app.register_blueprint(self._module.__method__, url_prefix=self.blueprint_name(name)) + + @staticmethod + def blueprint_name(name): + + root_module = name.replace(".", "") + + name = str(name).replace(root_module, "") + """ set index automatically as home page """ + if "index" in name: + name = str(name).replace("index", "") + if "routes" in name: + name = str(name).replace("routes", "") + if "module" in name: + name = str(name).replace("module", "") + + """ remove the last . in the string it it ends with a . + for the url structure must follow the flask routing format + it should be /model/method instead of /model/method/ + """ + if name[-1:] == ".": + name = name[:-1] + http_name = str(name).replace(".", "/") + + return http_name diff --git a/package_extractor.py b/package_extractor.py new file mode 100644 index 0000000..7cf1a3d --- /dev/null +++ b/package_extractor.py @@ -0,0 +1,45 @@ +import inspect +import pkgutil +from module_router import ModuleRouter + + +class PackageExtractor: + + __packages = None + + def __init__(self, application, path): + self.path = path + self.application = application + _packages = self.__inspect_packages(packages=pkgutil.walk_packages(path, prefix="", onerror=None)) + self.extract_packages(packages=_packages) + + @staticmethod + def __inspect_packages(packages): + if inspect.isgenerator(packages): + packages = [package for package in packages] + + if isinstance(packages, (list, set)): + if len(packages): + return packages + else: + raise ValueError("Package does not have an item.") + + def extract_packages(self, packages): + if len(packages): + loader, name, is_pkg = packages.pop(0) + """ if module found load module and save all attributes in the module found """ + mod = loader.find_module(name).load_module(name) + + """ find the attribute method on each module """ + if hasattr(mod, '__method__'): + module_router = ModuleRouter(mod) + + """ register to the blueprint if method attribute found """ + module_router.register_route(app=self.application, name=name) + + else: + """ prompt not found notification """ + # print('{} has no module attribute method'.format(mod)) + pass + self.extract_packages(packages) +