Update document for the develpers as per current implementation

This commit is contained in:
Ashesh Vashi 2015-10-20 13:00:05 +05:30
parent e27e39a8f3
commit 7f8ebb01d8
6 changed files with 708 additions and 98 deletions

View File

@ -14,6 +14,12 @@ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
# It is possible that, it fails to build this (if not running from the
# development environment).
code_snippet:
@echo "Generating code-snippet.rst for some of the important classes..."
-@python build_code_snippet.py
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@ -36,95 +42,95 @@ help:
clean:
-rm -rf $(BUILDDIR)/*
html:
html: code_snippet
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
dirhtml: code_snippet
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
singlehtml: code_snippet
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
pickle: code_snippet
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
json: code_snippet
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
htmlhelp: code_snippet
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
qthelp: code_snippet
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pgAdminIII.qhcp"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pgAdminIV.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pgAdminIII.qhc"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pgAdminIV.qhc"
devhelp:
devhelp: code_snippet
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/pgAdminIII"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pgAdminIII"
@echo "# mkdir -p $$HOME/.local/share/devhelp/pgAdminIV"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pgAdminIV"
@echo "# devhelp"
epub:
epub: code_snippet
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
latex: code_snippet
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
latexpdf: code_snippet
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
make -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
text: code_snippet
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
man: code_snippet
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
changes:
changes: code_snippet
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
linkcheck: code_snippet
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
doctest: code_snippet
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

View File

@ -0,0 +1,71 @@
import os
import sys
import inspect
root = os.path.realpath(
os.path.dirname(
os.path.realpath(__file__)
) + '{0}..{0}..{0}web'.format(os.sep)
)
if sys.path[0] != root:
sys.path.insert(0, root)
from pgadmin.utils import PgAdminModule
target = open('code-snippet.rst', 'w')
target.truncate()
target.write("Code Snippet\n")
target.write("------------\n\n")
target.write("""
This document contains code for some of the important classes, listed as
below:\n\n""")
for m in [
'PgAdminModule', 'NodeView',
'BaseDriver', 'BaseConnection'
]:
target.write("* {0}_\n".format(m))
def print_code(outstream, name, module, info=None):
l = len(name)
outstream.write("\n\n.. _{0}:\n\n{0}\n".format(name))
idx = 0
while idx < l:
idx += 1
outstream.write("*")
if info:
outstream.write("\n\n{0}".format(info))
outstream.write("\n\n.. code-block:: python\n\n")
for line in inspect.getsourcelines(module)[0]:
if line.strip():
outstream.write(" {0}".format(line))
else:
outstream.write("{0}".format(line))
print_code(
target, "PgAdminModule", PgAdminModule,
"""
PgAdminModule is inherted from Flask.Blueprint module.
This module defines a set of methods, properties and attributes, that every module should implement.
""")
from pgadmin.browser.utils import NodeView
print_code(
target, "NodeView", NodeView,
"""
NodeView class helps exposing basic REST APIs for different operations used by
pgAdmin Browser. The basic idea has been taken from the `Flask's MethodView
<http://flask.pocoo.org/docs/0.10/api/#flask.views.MethodView>`_ class. Because
- we need a lot more operations (not, just CRUD), we can not use it directly.""")
from pgadmin.utils.driver.abstract import BaseDriver, BaseConnection
print_code(target, "BaseDriver", BaseDriver)
print_code(target, "BaseConnection", BaseConnection)

View File

@ -9,8 +9,8 @@ a web application, which is written in C++ using the QT framework.
Runtime
-------
The runtime is essentially a Python webserver and browser in a box. Found in the
**/runtime** directory in the source tree, it is a relatively simple QT
The runtime is essentially a Python webserver and browser in a box. Found in the
**/runtime** directory in the source tree, it is a relatively simple QT
application that is most easily modified using the **QT Creator** application.
Web Application
@ -27,23 +27,23 @@ Configuration
The core application configuration is found in **config.py**. This file includes
all configurable settings for the application, along with descriptions of their
use. It is essential that various settings are configured prior to deployent on
a web server; these can be overriden in **config_local.py** to avoid modifying
a web server; these can be overriden in **config_local.py** to avoid modifying
the main configuration file.
User Settings
*************
When running in desktop mode, pgAdmin has a single, default user account that is
used for the desktop user. When running in server mode, there may be unlimited
used for the desktop user. When running in server mode, there may be unlimited
users who are required to login prior to using the application. pgAdmin utilised
the **Flask-Security** module to manage application security and users, and
the **Flask-Security** module to manage application security and users, and
provides options for self-service password reset and password changes etc.
Whether in desktop or server mode, each user's settings are stored in a SQLite
database which is also used to store the user accounts. This is initially
database which is also used to store the user accounts. This is initially
created using the **setup.py** script which will create the database file and
schema within it, and add the first user account (with administrative
privileges) and a default server group for them. A **settings** table is also
schema within it, and add the first user account (with administrative
privileges) and a default server group for them. A **settings** table is also
used to store user configuration settings in a key-value fashion. Although not
required, setting keys (or names) are typically formatted using forward slashes
to artificially namespace values, much like the pgAdmin 3 settings files on Linux
@ -56,67 +56,131 @@ particularly with regard to desktop vs. server mode.
pgAdmin Core
************
The heart of pgAdmin is the **pgadmin** package. This contains the globally
The heart of pgAdmin is the **pgadmin** package. This contains the globally
available HTML templates used by the Jinja engine, as well as any global static
files such as images, Javascript and CSS files that are used in multiple modules.
The work of the package is handled in it's constructor, **__init__.py**. This
is responsible for setting up logging and authentication, dynamically loading
is responsible for setting up logging and authentication, dynamically loading
other modules, and a few other tasks.
Modules
*******
Units of functionality are added to pgAdmin through the addition of modules. Theses
are Python packages that implement Flask Blueprints, and provide various hook
points for other modules to utilise (primarily the default module - the browser).
Units of functionality are added to pgAdmin through the addition of modules.
Theses are Python object instance of classes, inherits the
PgAdminModule class (a Flask Blueprint implementation), found in
**web/pgadmin/utils.py**. It provide various hook points for other modules
to utilise (primarily the default module - the browser).
To be recognised as a module, a Python package must be created. This must:
1) Be placed within the **web/pgadmin/** directory, and
2) Contain a Python module called **views**, and
3) Contain within the views module, a **blueprint** variable representing the
Flask Blueprint
2) Implements pgadmin.utils.PgAdminModule class
3) An instance variable (generally - named **blueprint**) representing that
particular class in that package.
Each module may define a **template** and **static** directory for the Blueprint
that it implements. To avoid name collisions, templates should be stored under
a directory within the specified template directory, named after the module itself.
For example, the **browser** module stores it's templates in
For example, the **browser** module stores it's templates in
**web/pgadmin/browser/templates/browser/**. This does not apply to static files
which may omit the second module name.
In addition to defining the Blueprint, the **views** module is typically
responsible for defining all the views that will be rendered in response to
client requests. These must include appropriate route and security decorators.
In addition to defining the Blueprint, the **views** module is typically
responsible for defining all the views that will be rendered in response to
client requests, we must provide a REST API url(s) for these views. These must
include appropriate route and security decorators. Take a look at the NodeView
class, which uses the same approach as Flask's MethodView, it can be found in
**web/pgadmin/browser/utils.py**. This specific class is used by browser nodes
for creating REST API url(s) for different operation on them. i.e. list, create,
update, delete, fetch children, get
statistics/reversed SQL/dependencies/dependents list for that node, etc. We can
use the same class for other purpose too. You just need to inherit that class,
and overload the member variables operations, parent_ids, ids, node_type, and
then register it as node view with PgAdminModule instance.
Most pgAdmin modules will also implement a **hooks** Python module. This is
responsible for providing hook points to integrate the module into the rest of
the application - for example, a hook might tell the caller what CSS files need
to be included on the rendered page, or what menu options to include and what
they should do. Hook points need not exist if they are not required. It is the
responsiblity of the caller to ensure they are present before attempting to
utilise them.
Most pgAdmin modules will also implement the **hooks** provided by the
PgAdminModule class. This is responsible for providing hook points to integrate
the module into the rest of the application - for example, a hook might tell
the caller what CSS files need to be included on the rendered page, or what menu
options to include and what they should do. Hook points need not exist if they
are not required. It is the responsiblity of the caller to ensure they are
present before attempting to utilise them.
Hooks currently implemented are:
.. code-block:: python
def register_submodules(app):
"""Register any child module or node blueprints"""
def get_file_menu_items():
def get_edit_menu_items():
def get_tools_menu_items():
def get_management_menu_items():
def get_help_menu_items():
"""Return a (set) of dicts of menu items, with name, priority, URL, target and onclick code."""
def get_scripts():
"""Return a list of script URLs to include in the rendered page header"""
class MyModule(PgAdminModule):
"""
This is class implements the pgadmin.utils.PgAdminModule, and
implements the hooks
"""
...
def get_own_stylesheets(self):
"""
Returns:
list: the stylesheets used by this module, not including any
stylesheet needed by the submodules.
"""
return [url_for('static', 'css/mymodule.css')]
def get_own_javascripts(self):
"""
Returns:
list of dict:
- contains the name (representation for this javascript
module), path (url for it without .js suffix), deps (array of
dependents), exports window object by the javascript module,
and when (would you like to load this javascript), etc
information for this module, not including any script needed
by submodules.
"""
return [
{
'name': 'pgadmin.extension.mymodule',
'path': url_for('static', filename='js/mymodule'),
'exports': None,
'when': 'server'
}
]
def get_own_menuitems(self):
"""
Returns:
dict: the menuitems for this module, not including
any needed from the submodules.
"""
return {
'help_items': [
MenuItem(
name='mnu_mymodule_help',
priority=999,
# We need to create javascript, which registers itself
# as module
module="pgAdmin.MyModule",
callback='about_show',
icon='fa fa-info-circle',
label=gettext('About MyModule'
)
]
}
def get_panels(self):
"""
Returns:
list: a list of panel objects to add implemented in javascript
module
"""
return []
...
blueprint = MyModule('mymodule', __name__, static_url_path='/static')
def get_stylesheets():
"""Return a list of stylesheet URLs to include in the rendered page header"""
pgAdmin Modules may include any additional Python modules that are required to
fulfill their purpose, as required. They may also reference other dynamically
loaded modules, but must use the defined hook points and fail gracefully in the
@ -125,40 +189,24 @@ event that a particular module is not present.
Nodes
*****
Nodes are very similar to modules, but implement individual nodes on the browser
treeview. To be recognised as a module, a Python package must be created. This
must:
Nodes are very similar to modules, it represents an individual node or,
collection object on the browser treeview. To recognised as a node module, a
Python package (along with javascript modules) must be created. This must:
1) Be placed within the **web/pgadmin/browser/** directory, and
2) Contain a Python module called **views**, and
3) Contain within the views module, a **blueprint** variable representing the
Flask Blueprint
The hook points currently defined for nodes are:
2) Implements the BrowserPluginModule, and registers the node view, which
exposes required the REST APIs
3) An instance of the class object
.. code-block:: python
Front End
*********
def register_submodules(app):
"""Register any child node blueprints"""
def get_file_menu_items():
"""Return a (set) of dicts of menu items, with name, priority, URL, target and onclick code."""
def get_context_menu_items():
"""Return a (set) of dicts of content menu items with name, label, priority and JS"""
def get_create_menu_items():
"""Return a (set) of dicts of create menu items, with a Javascript array of
object types on which the option should appear, name, label. priority and
the function name (no parens) to call on click."""
def get_standard_menu_items():
"""Return a (set) of dicts of standard menu items (drop/rename), with
object type, action, priority and the function name (no parens) to call
on click."""
def get_script_snippets():
"""Return the script snippets needed to handle treeview node operations."""
def get_css_snippets():
"""Return the CSS needed to display the treeview node image."""
pgAdmin uses javascript extensively for the front-end implementation. It uses
require.js to allow the lazy loading (or, say load only when required),
bootstrap for UI look and feel, Backbone for data manipulation of a node,
Backform for generating properties/create dialog for selected node. We have
divided each module in small chunks as much as possible. Not all javascript
modules are required to be loaded (i.e. loading a javascript module for
database will make sense only when a server node is loaded competely.) Please
look at the the javascript files node.js, browser.js, menu.js, panel.js, etc for
better understanding of the code.

484
docs/en_US/code-snippet.rst Normal file
View File

@ -0,0 +1,484 @@
Code Snippet
------------
This document contains code for some of the important classes, listed as
below:
* PgAdminModule_
* NodeView_
* BaseDriver_
* BaseConnection_
.. _PgAdminModule:
PgAdminModule
*************
PgAdminModule is inherted from Flask.Blueprint module.
This module defines a set of methods, properties and attributes, that every module should implement.
.. code-block:: python
class PgAdminModule(Blueprint):
"""
Base class for every PgAdmin Module.
This class defines a set of method and attributes that
every module should implement.
"""
def __init__(self, name, import_name, **kwargs):
kwargs.setdefault('url_prefix', '/' + name)
kwargs.setdefault('template_folder', 'templates')
kwargs.setdefault('static_folder', 'static')
self.submodules = []
super(PgAdminModule, self).__init__(name, import_name, **kwargs)
def register(self, app, options, first_registration=False):
"""
Override the default register function to automagically register
sub-modules at once.
"""
if first_registration:
self.submodules = list(app.find_submodules(self.import_name))
super(PgAdminModule, self).register(app, options, first_registration)
for module in self.submodules:
app.register_blueprint(module)
def get_own_stylesheets(self):
"""
Returns:
list: the stylesheets used by this module, not including any
stylesheet needed by the submodules.
"""
return []
def get_own_javascripts(self):
"""
Returns:
list: the javascripts used by this module, not including
any script needed by the submodules.
"""
return []
def get_own_menuitems(self):
"""
Returns:
dict: the menuitems for this module, not including
any needed from the submodules.
"""
return defaultdict(list)
def get_panels(self):
"""
Returns:
list: a list of panel objects to add
"""
return []
@property
def stylesheets(self):
stylesheets = self.get_own_stylesheets()
for module in self.submodules:
stylesheets.extend(module.stylesheets)
return stylesheets
@property
def javascripts(self):
javascripts = self.get_own_javascripts()
for module in self.submodules:
javascripts.extend(module.javascripts)
return javascripts
@property
def menu_items(self):
menu_items = self.get_own_menuitems()
for module in self.submodules:
for key, value in module.menu_items.items():
menu_items[key].extend(value)
menu_items = {key: sorted(values, key=attrgetter('priority'))
for key, values in menu_items.items()}
return menu_items
.. _NodeView:
NodeView
********
NodeView class helps exposing basic REST APIs for different operations used by
pgAdmin Browser. The basic idea has been taken from the `Flask's MethodView
<http://flask.pocoo.org/docs/0.10/api/#flask.views.MethodView>`_ class. Because
- we need a lot more operations (not, just CRUD), we can not use it directly.
.. code-block:: python
class NodeView(with_metaclass(MethodViewType, View)):
"""
A PostgreSQL Object has so many operaions/functions apart from CRUD
(Create, Read, Update, Delete):
i.e.
- Reversed Engineered SQL
- Modified Query for parameter while editing object attributes
i.e. ALTER TABLE ...
- Statistics of the objects
- List of dependents
- List of dependencies
- Listing of the children object types for the certain node
It will used by the browser tree to get the children nodes
This class can be inherited to achieve the diffrent routes for each of the
object types/collections.
OPERATION | URL | Method
---------------+------------------------+--------
List | /obj/[Parent URL]/ | GET
Properties | /obj/[Parent URL]/id | GET
Create | /obj/[Parent URL]/ | POST
Delete | /obj/[Parent URL]/id | DELETE
Update | /obj/[Parent URL]/id | PUT
SQL (Reversed | /sql/[Parent URL]/id | GET
Engineering) |
SQL (Modified | /sql/[Parent URL]/id | POST
Properties) |
Statistics | /stats/[Parent URL]/id | GET
Dependencies | /deps/[Parent URL]/id | GET
Dependents | /deps/[Parent URL]/id | POST
Children Nodes | /nodes/[Parent URL]/id | GET
NOTE:
Parent URL can be seen as the path to identify the particular node.
i.e.
In order to identify the TABLE object, we need server -> database -> schema
information.
"""
operations = dict({
'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'}
],
'nodes': [{'get': 'nodes'}],
'sql': [{'get': 'sql', 'post': 'modified_sql'}],
'stats': [{'get': 'statistics'}],
'deps': [{'get': 'dependencies', 'post': 'dependents'}],
'module.js': [{}, {}, {'get': 'module_js'}]
})
@classmethod
def generate_ops(cls):
cmds = []
for op in cls.operations:
idx = 0
for ops in cls.operations[op]:
meths = []
for meth in ops:
meths.append(meth.upper())
if len(meths) > 0:
cmds.append({
'cmd': op, 'req': (idx == 0),
'with_id': (idx != 2), 'methods': meths
})
idx += 1
return cmds
# Inherited class needs to modify these parameters
node_type = None
# This must be an array object with attributes (type and id)
parent_ids = []
# This must be an array object with attributes (type and id)
ids = []
@classmethod
def get_node_urls(cls):
assert cls.node_type is not None, \
"Please set the node_type for this class ({0})".format(
str(cls.__class__.__name__))
common_url = '/'
for p in cls.parent_ids:
common_url += '<{0}:{1}>/'.format(str(p['type']), str(p['id']))
id_url = None
for p in cls.ids:
id_url = '{0}<{1}:{2}>'.format(common_url if not id_url else id_url,
p['type'], p['id'])
return id_url, common_url
def __init__(self, **kwargs):
self.cmd = kwargs['cmd']
# Check the existance of all the required arguments from parent_ids
# and return combination of has parent arguments, and has id arguments
def check_args(self, **kwargs):
has_id = has_args = True
for p in self.parent_ids:
if p['id'] not in kwargs:
has_args = False
break
for p in self.ids:
if p['id'] not in kwargs:
has_id = False
break
return has_args, has_id and has_args
def dispatch_request(self, *args, **kwargs):
meth = flask.request.method.lower()
if meth == 'head':
meth = 'get'
assert self.cmd in self.operations, \
"Unimplemented Command ({0}) for {1}".format(
self.cmd,
str(self.__class__.__name__)
)
has_args, has_id = self.check_args(**kwargs)
assert (self.cmd in self.operations and
(has_id and len(self.operations[self.cmd]) > 0 and
meth in self.operations[self.cmd][0]) or
(not has_id and len(self.operations[self.cmd]) > 1 and
meth in self.operations[self.cmd][1]) or
(len(self.operations[self.cmd]) > 2 and
meth in self.operations[self.cmd][2])), \
"Unimplemented method ({0}) for command ({1}), which {2} an id".format(
meth, self.cmd,
'requires' if has_id else 'does not require'
)
meth = self.operations[self.cmd][0][meth] if has_id else \
self.operations[self.cmd][1][meth] if has_args and \
meth in self.operations[self.cmd][1] else \
self.operations[self.cmd][2][meth]
method = getattr(self, meth, None)
if method is None:
return make_json_response(
status=406,
success=0,
errormsg=gettext(
"Unimplemented method ({0}) for this url ({1})".format(
meth, flask.request.path)
)
)
return method(*args, **kwargs)
@classmethod
def register_node_view(cls, blueprint):
cls.blueprint = blueprint
id_url, url = cls.get_node_urls()
commands = cls.generate_ops()
for c in commands:
if c['with_id']:
blueprint.add_url_rule(
'/{0}{1}'.format(
c['cmd'], id_url if c['req'] else url
),
view_func=cls.as_view(
'{0}{1}'.format(
c['cmd'], '_id' if c['req'] else ''
),
cmd=c['cmd']
),
methods=c['methods']
)
else:
blueprint.add_url_rule(
'/{0}'.format(c['cmd']),
view_func=cls.as_view(
'{0}'.format(c['cmd']), cmd=c['cmd']
),
methods=c['methods']
)
def module_js(self, **kwargs):
"""
This property defines (if javascript) exists for this node.
Override this property for your own logic.
"""
return flask.make_response(
flask.render_template(
"{0}/{0}.js".format(self.node_type)
),
200, {'Content-Type': 'application/x-javascript'}
)
def nodes(self, *args, **kwargs):
"""Build a list of treeview nodes from the child nodes."""
nodes = []
for module in self.blueprint.submodules:
nodes.extend(module.get_nodes(*args, **kwargs))
return make_json_response(data=nodes)
.. _BaseDriver:
BaseDriver
**********
.. code-block:: python
class BaseDriver(object):
"""
class BaseDriver(object):
This is a base class for different server types.
Inherit this class to implement different type of database driver
implementation.
(For PostgreSQL/Postgres Plus Advanced Server, we will be using psycopg2)
Abstract Properties:
-------- ----------
* Version (string):
Current version string for the database server
Abstract Methods:
-------- -------
* get_connection(*args, **kwargs)
- It should return a Connection class object, which may/may not be
connected to the database server.
* release_connection(*args, **kwargs)
- Implement the connection release logic
* gc()
- Implement this function to release the connections assigned in the
session, which has not been pinged from more than the idle timeout
configuration.
"""
__metaclass__ = DriverRegistry
@abstractproperty
def Version(cls):
pass
@abstractmethod
def get_connection(self, *args, **kwargs):
pass
@abstractmethod
def release_connection(self, *args, **kwargs):
pass
@abstractmethod
def gc(self):
pass
.. _BaseConnection:
BaseConnection
**************
.. code-block:: python
class BaseConnection(object):
"""
class BaseConnection(object)
It is a base class for database connection. A different connection
drive must implement this to expose abstract methods for this server.
General idea is to create a wrapper around the actaul driver
implementation. It will be instantiated by the driver factory
basically. And, they should not be instantiated directly.
Abstract Methods:
-------- -------
* connect(**kwargs)
- Define this method to connect the server using that particular driver
implementation.
* execute_scalar(query, params)
- Implement this method to execute the given query and returns single
datum result.
* execute_2darray(query, params)
- Implement this method to execute the given query and returns the result
as a 2 dimentional array.
* execute_dict(query, params)
- Implement this method to execute the given query and returns the result
as an array of dict (column name -> value) format.
* connected()
- Implement this method to get the status of the connection. It should
return True for connected, otherwise False
* reset()
- Implement this method to reconnect the database server (if possible)
* transaction_status()
- Implement this method to get the transaction status for this
connection. Range of return values different for each driver type.
* ping()
- Implement this method to ping the server. There are times, a connection
has been lost, but - the connection driver does not know about it. This
can be helpful to figure out the actual reason for query failure.
* _release()
- Implement this method to release the connection object. This should not
be directly called using the connection object itself.
NOTE: Please use BaseDriver.release_connection(...) for releasing the
connection object for better memory management, and connection pool
management.
"""
__metaclass__ = ABCMeta
@abstractmethod
def connect(self, **kwargs):
pass
@abstractmethod
def execute_scalar(self, query, params=None):
pass
@abstractmethod
def execute_2darray(self, query, params=None):
pass
@abstractmethod
def execute_dict(self, query, params=None):
pass
@abstractmethod
def connected(self):
pass
@abstractmethod
def reset(self):
pass
@abstractmethod
def transaction_status(self):
pass
@abstractmethod
def ping(self):
pass
@abstractmethod
def _release(self):
pass

View File

@ -91,7 +91,7 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
html_theme = 'classic'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the

View File

@ -74,6 +74,7 @@ learn how pgAdmin works, and how to develop improvements and new features.
coding-standards
code-overview
code-snippet
submitting-patches
translations
@ -94,4 +95,4 @@ pgAdmin is released under the
liberal Open Source licence similar to BSD or MIT, and approved by the Open
Source Initiative. The copyright for the project source code, website and
documentation is attributed to the
`pgAdmin Development Team <http://www.pgadmin.org/development/team.php>`_.
`pgAdmin Development Team <http://www.pgadmin.org/development/team.php>`_.