summaryrefslogtreecommitdiff
path: root/grc/python/extract_docs.py
diff options
context:
space:
mode:
Diffstat (limited to 'grc/python/extract_docs.py')
-rw-r--r--grc/python/extract_docs.py296
1 files changed, 0 insertions, 296 deletions
diff --git a/grc/python/extract_docs.py b/grc/python/extract_docs.py
deleted file mode 100644
index 7c149ce593..0000000000
--- a/grc/python/extract_docs.py
+++ /dev/null
@@ -1,296 +0,0 @@
-"""
-Copyright 2008-2011 Free Software Foundation, Inc.
-This file is part of GNU Radio
-
-GNU Radio Companion is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-GNU Radio Companion is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
-"""
-
-import sys
-import re
-import subprocess
-import threading
-import json
-import Queue
-import random
-import itertools
-
-
-###############################################################################
-# The docstring extraction
-###############################################################################
-
-def docstring_guess_from_key(key):
- """Extract the documentation from the python __doc__ strings
-
- By guessing module and constructor names from key
-
- Args:
- key: the block key
-
- Returns:
- a dict (block_name --> doc string)
- """
- doc_strings = dict()
-
- in_tree = [key.partition('_')[::2] + (
- lambda package: getattr(__import__('gnuradio.' + package), package),
- )]
-
- key_parts = key.split('_')
- oot = [
- ('_'.join(key_parts[:i]), '_'.join(key_parts[i:]), __import__)
- for i in range(1, len(key_parts))
- ]
-
- for module_name, init_name, importer in itertools.chain(in_tree, oot):
- if not module_name or not init_name:
- continue
- try:
- module = importer(module_name)
- break
- except ImportError:
- continue
- else:
- return doc_strings
-
- pattern = re.compile(
- '^' + init_name.replace('_', '_*').replace('x', r'\w') + r'\w*$'
- )
- for match in filter(pattern.match, dir(module)):
- try:
- doc_strings[match] = getattr(module, match).__doc__
- except AttributeError:
- continue
-
- return doc_strings
-
-
-def docstring_from_make(key, imports, make):
- """Extract the documentation from the python __doc__ strings
-
- By importing it and checking a truncated make
-
- Args:
- key: the block key
- imports: a list of import statements (string) to execute
- make: block constructor template
-
- Returns:
- a list of tuples (block_name, doc string)
- """
-
- try:
- blk_cls = make.partition('(')[0].strip()
- if '$' in blk_cls:
- raise ValueError('Not an identifier')
-
- ns = dict()
- for _import in imports:
- exec(_import.strip(), ns)
- blk = eval(blk_cls, ns)
-
- doc_strings = {key: blk.__doc__}
-
- except (ImportError, AttributeError, SyntaxError, ValueError):
- doc_strings = docstring_guess_from_key(key)
-
- return doc_strings
-
-
-###############################################################################
-# Manage docstring extraction in separate process
-###############################################################################
-
-class SubprocessLoader(object):
- """Start and manage docstring extraction process
-
- Manages subprocess and handles RPC.
- """
- BOOTSTRAP = "import runpy; runpy.run_path({!r}, run_name='__worker__')"
- AUTH_CODE = random.random() # sort out unwanted output of worker process
- RESTART = 5 # number of worker restarts before giving up
- DONE = object() # sentinel value to signal end-of-queue
-
- def __init__(self, callback_query_result, callback_finished=None):
- self.callback_query_result = callback_query_result
- self.callback_finished = callback_finished or (lambda: None)
-
- self._queue = Queue.Queue()
- self._thread = None
- self._worker = None
- self._shutdown = threading.Event()
- self._last_cmd = None
-
- def start(self):
- """Start the worker process handler thread"""
- if self._thread is not None:
- return
- self._shutdown.clear()
- thread = self._thread = threading.Thread(target=self.run_worker)
- thread.daemon = True
- thread.start()
-
- def run_worker(self):
- """Read docstring back from worker stdout and execute callback."""
- for _ in range(self.RESTART):
- if self._shutdown.is_set():
- break
- try:
- self._worker = subprocess.Popen(
- args=(sys.executable, '-uc', self.BOOTSTRAP.format(__file__)),
- stdin=subprocess.PIPE, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE
- )
- self._handle_worker()
-
- except (OSError, IOError):
- msg = "Warning: restarting the docstring loader"
- cmd, args = self._last_cmd
- if cmd == 'query':
- msg += " (crashed while loading {0!r})".format(args[0])
- print >> sys.stderr, msg
- continue # restart
- else:
- break # normal termination, return
- finally:
- self._worker.terminate()
- else:
- print >> sys.stderr, "Warning: docstring loader crashed too often"
- self._thread = None
- self._worker = None
- self.callback_finished()
-
- def _handle_worker(self):
- """Send commands and responses back from worker."""
- assert '1' == self._worker.stdout.read(1)
- for cmd, args in iter(self._queue.get, self.DONE):
- self._last_cmd = cmd, args
- self._send(cmd, args)
- cmd, args = self._receive()
- self._handle_response(cmd, args)
-
- def _send(self, cmd, args):
- """send a command to worker's stdin"""
- fd = self._worker.stdin
- json.dump((self.AUTH_CODE, cmd, args), fd)
- fd.write('\n'.encode())
-
- def _receive(self):
- """receive response from worker's stdout"""
- for line in iter(self._worker.stdout.readline, ''):
- try:
- key, cmd, args = json.loads(line, encoding='utf-8')
- if key != self.AUTH_CODE:
- raise ValueError('Got wrong auth code')
- return cmd, args
- except ValueError:
- continue # ignore invalid output from worker
- else:
- raise IOError("Can't read worker response")
-
- def _handle_response(self, cmd, args):
- """Handle response from worker, call the callback"""
- if cmd == 'result':
- key, docs = args
- self.callback_query_result(key, docs)
- elif cmd == 'error':
- print args
- else:
- print >> sys.stderr, "Unknown response:", cmd, args
-
- def query(self, key, imports=None, make=None):
- """request docstring extraction for a certain key"""
- if self._thread is None:
- self.start()
- if imports and make:
- self._queue.put(('query', (key, imports, make)))
- else:
- self._queue.put(('query_key_only', (key,)))
-
- def finish(self):
- """signal end of requests"""
- self._queue.put(self.DONE)
-
- def wait(self):
- """Wait for the handler thread to die"""
- if self._thread:
- self._thread.join()
-
- def terminate(self):
- """Terminate the worker and wait"""
- self._shutdown.set()
- try:
- self._worker.terminate()
- self.wait()
- except (OSError, AttributeError):
- pass
-
-
-###############################################################################
-# Main worker entry point
-###############################################################################
-
-def worker_main():
- """Main entry point for the docstring extraction process.
-
- Manages RPC with main process through.
- Runs a docstring extraction for each key it read on stdin.
- """
- def send(cmd, args):
- json.dump((code, cmd, args), sys.stdout)
- sys.stdout.write('\n'.encode())
-
- sys.stdout.write('1')
- for line in iter(sys.stdin.readline, ''):
- code, cmd, args = json.loads(line, encoding='utf-8')
- try:
- if cmd == 'query':
- key, imports, make = args
- send('result', (key, docstring_from_make(key, imports, make)))
- elif cmd == 'query_key_only':
- key, = args
- send('result', (key, docstring_guess_from_key(key)))
- elif cmd == 'exit':
- break
- except Exception as e:
- send('error', repr(e))
-
-
-if __name__ == '__worker__':
- worker_main()
-
-elif __name__ == '__main__':
- def callback(key, docs):
- print key
- for match, doc in docs.iteritems():
- print '-->', match
- print doc.strip()
- print
- print
-
- r = SubprocessLoader(callback)
-
- # r.query('analog_feedforward_agc_cc')
- # r.query('uhd_source')
- r.query('expr_utils_graph')
- r.query('blocks_add_cc')
- r.query('blocks_add_cc', ['import gnuradio.blocks'], 'gnuradio.blocks.add_cc(')
- # r.query('analog_feedforward_agc_cc')
- # r.query('uhd_source')
- # r.query('uhd_source')
- # r.query('analog_feedforward_agc_cc')
- r.finish()
- # r.terminate()
- r.wait()