""" Module responsible of automated docs generation """ import logging import importlib import re import os from django.apps import AppConfig from django.conf import settings from sphinxcontrib.napoleon import Config, NumpyDocstring APPS_DOC = ['GMS', 'AI', 'MG'] RST_PATH = 'docs/autodoc' def parser_numpy_style(doc, config): """ Parse numpy style docstring to rst style format Parameters ---------- doc: str Numpy style docstring config: Config Configuration for Napoleon Returns ------- success: str Docstring in rst format """ docstring_lines = doc.split('\n') pattern = re.compile('^ {4}') docstring_lines = [pattern.sub('', line) for line in docstring_lines] rest_docstring = NumpyDocstring(docstring_lines, config).lines() rest_docstring_fixed = '\n'.join([' ' + line for line in rest_docstring]) return rest_docstring_fixed def process_family(app_id, config, files): """ Function to process a whole family of services (GMS, AI, MG) Parameters ---------- app_id: str Family ID, (GMS, AI, MG) config: Config Napoleon configuration files: dict Dict containing the string that will be written in the files. One entry per family. Returns ------- success: None The docs will be generated in the string inside variable files. """ calls_module_string = '.'.join(app_id) + '.' + 'calls' calls_module = importlib.import_module(calls_module_string) # Subsection documentation subsection_subsectiondoc = importlib.import_module('.'.join(app_id)).__doc__ subsection_string = """\n{}\n{}\n{}\n""".format('-' * len(app_id[1]), app_id[1], '-' * len(app_id[1])) if subsection_subsectiondoc: subsection_string = """\n{}\n{}\n{}\n""".format('-' * len(app_id[1]), app_id[1], '-' * len(app_id[1])) rest_docstring_fixed = parser_numpy_style(subsection_subsectiondoc, config) subsection_string += rest_docstring_fixed files[app_id[0]] += subsection_string + '\n' # Service documentation # # DEPRECATION WARNING: # TODO: CHANGE all calls init and views modules # In order to eliminate the wildcard import of calls packages inside all # application, the calls_module.__all__ will be replaced by calls_module.CALLS # # TEMPORAL FIX UNTIL CHANGE ALL PACKAGES: try: services_list = calls_module.__all__ except AttributeError: services_list = calls_module.CALLS # # ENDING TEMPORAL FIX ############################################3 for service in [serv for serv in services_list if serv not in ["C_Post_Pozos_PG", 'C_Generic_PostTable_PG']]: path_string = '/'.join(app_id) + '/' + service function_string = """.. py:function:: {} \n""".format(path_string) service_module = importlib.import_module(calls_module_string + '.' + service) # Getting service docstring try: post_doc = service_module.post.__doc__ except AttributeError: # # TEMPORAL FIX UNTIL CHANGE ALL PACKAGES: post_doc = service_module.__dict__['POST_REQUEST'] if 'POST_REQUEST' in \ service_module \ .__dict__ \ .keys() else '' # # ENDING TEMPORAL FIX ############################################# if not post_doc: continue rest_docstring_fixed = parser_numpy_style(post_doc, config) function_string += rest_docstring_fixed files[app_id[0]] += function_string + '\n' class DocsConfig(AppConfig): """ Class to manage Docs app. """ name = 'docs' def ready(self): """ Method executed after docs app is ready. Returns ------- success: None """ # Generate docs when Django server is started logging.info('Generating services documentation') # Setting up napoleon to change between numpy style to rest style config = Config(napoleon_use_param=True, napoleon_use_rtype=True) # Initializing docs files = {'GMS': """\nGMS\n===\n""", 'AI': """\nAI\n===\n""", 'MG': """\nMG\n===\n"""} # Generate docs for sections for app in settings.INSTALLED_APPS: app_id = app.split('.') if app_id[0] in APPS_DOC: process_family(app_id, config, files) # Writing rst files for app in APPS_DOC: with open(os.path.join(RST_PATH, '{}.rst'.format(app)), 'w') as doc_file: doc_file.write(files[app]) # Making html actual_path = os.path.abspath('') os.chdir(RST_PATH) os.system('make html') os.chdir(actual_path) logging.info('Services documentation generated') # Set some changes in html logging.info('Setting up docs to serve') build_path = 'docs/autodoc/_build/html' for _, _, filenames in os.walk(build_path): for file in filenames: if file.split('.')[1] == 'html': string = open('{}/{}'.format(build_path, file),'r').read() string = string.replace('_static/', '/static/docs/') open('{}/{}'.format(build_path, file), 'w').write(string) break # Copy to static os.system('cp -r {} {}'.format(os.path.join(build_path, '_static', '*'), os.path.join('docs/static/docs')))