From 6180396f0b3a9c39ccb4c38f60fb89df842783ea Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Fri, 18 Jun 2010 10:40:13 +0000 Subject: Updated files to match PEP 257 git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@5951 ce84e21b-d406-0410-9b95-82705330c041 --- src/lib/Server/Core.py | 26 ++++---- src/lib/Server/FileMonitor.py | 44 +++++++------- src/lib/Server/Plugin.py | 135 +++++++++++++++++++++--------------------- src/lib/Server/__init__.py | 2 +- 4 files changed, 104 insertions(+), 103 deletions(-) (limited to 'src') diff --git a/src/lib/Server/Core.py b/src/lib/Server/Core.py index f139ef99b..84e3f9882 100644 --- a/src/lib/Server/Core.py +++ b/src/lib/Server/Core.py @@ -1,4 +1,4 @@ -'''Bcfg2.Server.Core provides the runtime support for bcfg2 modules''' +"""Bcfg2.Server.Core provides the runtime support for Bcfg2 modules.""" __revision__ = '$Revision$' import atexit @@ -17,7 +17,7 @@ import Bcfg2.Server.Plugins.Metadata logger = logging.getLogger('Bcfg2.Server.Core') def critical_error(operation): - '''Log and err, traceback and return an xmlrpc fault to client''' + """Log and err, traceback and return an xmlrpc fault to client.""" logger.error(operation, exc_info=1) raise xmlrpclib.Fault(7, "Critical unexpected failure: %s" % (operation)) @@ -28,11 +28,11 @@ except: pass class CoreInitError(Exception): - '''This error is raised when the core cannot be initialized''' + """This error is raised when the core cannot be initialized.""" pass class Core(Component): - '''The Core object is the container for all Bcfg2 Server logic, and modules''' + """The Core object is the container for all Bcfg2 Server logic and modules.""" name = 'bcfg2-server' implementation = 'bcfg2-server' @@ -175,7 +175,7 @@ class Core(Component): % (plugin.name), exc_info=1) def GetStructures(self, metadata): - '''Get all structures for client specified by metadata''' + """Get all structures for client specified by metadata.""" structures = reduce(lambda x, y:x+y, [struct.BuildStructures(metadata) for struct \ in self.structures], []) @@ -187,7 +187,7 @@ class Core(Component): return structures def BindStructure(self, structure, metadata): - '''Bind a complete structure''' + """Bind a complete structure.""" for entry in structure.getchildren(): if entry.tag.startswith("Bound"): entry.tag = entry.tag[5:] @@ -204,7 +204,7 @@ class Core(Component): % (entry.tag, entry.get('name')), exc_info=1) def Bind(self, entry, metadata): - '''Bind an entry using the appropriate generator''' + """Bind an entry using the appropriate generator.""" if 'altsrc' in entry.attrib: oldname = entry.get('name') entry.set('name', entry.get('altsrc')) @@ -239,7 +239,7 @@ class Core(Component): raise PluginExecutionError, (entry.tag, entry.get('name')) def BuildConfiguration(self, client): - '''Build Configuration for client''' + """Build configuration for client.""" start = time.time() config = lxml.etree.Element("Configuration", version='2.0', \ revision=self.revision) @@ -324,7 +324,7 @@ class Core(Component): @exposed def GetProbes(self, address): - '''Fetch probes for a particular client''' + """Fetch probes for a particular client.""" resp = lxml.etree.Element('probes') try: name = self.metadata.resolve_client(address) @@ -349,7 +349,7 @@ class Core(Component): @exposed def RecvProbeData(self, address, probedata): - '''Receive probe data from clients''' + """Receive probe data from clients.""" try: name = self.metadata.resolve_client(address) meta = self.build_metadata(name) @@ -383,7 +383,7 @@ class Core(Component): @exposed def AssertProfile(self, address, profile): - '''Set profile for a client''' + """Set profile for a client.""" try: client = self.metadata.resolve_client(address) self.metadata.set_profile(client, profile, address) @@ -396,7 +396,7 @@ class Core(Component): @exposed def GetConfig(self, address, checksum=False): - '''Build config for a client''' + """Build config for a client.""" try: client = self.metadata.resolve_client(address) config = self.BuildConfiguration(client) @@ -408,7 +408,7 @@ class Core(Component): @exposed def RecvStats(self, address, stats): - '''Act on statistics upload''' + """Act on statistics upload""" sdata = lxml.etree.XML(stats) client = self.metadata.resolve_client(address) self.process_statistics(client, sdata) diff --git a/src/lib/Server/FileMonitor.py b/src/lib/Server/FileMonitor.py index 9538cf428..6fab0c328 100644 --- a/src/lib/Server/FileMonitor.py +++ b/src/lib/Server/FileMonitor.py @@ -6,7 +6,7 @@ from time import sleep, time logger = logging.getLogger('Bcfg2.Server.FileMonitor') def ShouldIgnore(event): - '''Test if the event should be suppresed''' + """Test if the event should be suppresed.""" # FIXME should move event suppression out of the core if event.filename.split('/')[-1] == '.svn': return True @@ -23,12 +23,12 @@ class Event(object): self.action = code def code2str(self): - '''return static code for event''' + """return static code for event""" return self.action available = {} class FileMonitor(object): - '''File Monitor baseclass''' + """File Monitor baseclass.""" def __init__(self, debug=False): object.__init__(self) self.debug = debug @@ -89,7 +89,7 @@ class FileMonitor(object): class FamFam(object): - '''The fam object is a set of callbacks for file alteration events (FAM support)''' + """The fam object is a set of callbacks for file alteration events (FAM support).""" def __init__(self): object.__init__(self) @@ -99,7 +99,7 @@ class FamFam(object): self.debug = False def fileno(self): - '''return fam file handle number''' + """return fam file handle number""" return self.fm.fileno() def handle_event_set(self, _): @@ -112,7 +112,7 @@ class FamFam(object): now = time() def AddMonitor(self, path, obj): - '''add a monitor to path, installing a callback to obj.HandleEvent''' + """Add a monitor to path, installing a callback to obj.HandleEvent.""" mode = os.stat(path)[stat.ST_MODE] if stat.S_ISDIR(mode): handle = self.fm.monitorDirectory(path, None) @@ -124,7 +124,7 @@ class FamFam(object): return handle.requestID() def Service(self, interval=0.50): - '''Handle all fam work''' + """Handle all fam work.""" count = 0 collapsed = 0 rawevents = [] @@ -164,10 +164,10 @@ class FamFam(object): class Fam(FileMonitor): - ''' + """ The fam object is a set of callbacks for - file alteration events (FAM support) - ''' + file alteration events (FAM support). + """ def __init__(self, debug=False): FileMonitor.__init__(self, debug) @@ -177,7 +177,7 @@ class Fam(FileMonitor): return self.fm.fileno() def AddMonitor(self, path, obj): - '''add a monitor to path, installing a callback to obj.HandleEvent''' + """Add a monitor to path, installing a callback to obj.HandleEvent.""" mode = os.stat(path)[stat.ST_MODE] if stat.S_ISDIR(mode): handle = self.fm.monitorDirectory(path, None) @@ -194,10 +194,10 @@ class Fam(FileMonitor): return self.fm.nextEvent() class Pseudo(FileMonitor): - ''' + """ The fam object is a set of callbacks for - file alteration events (static monitor support) - ''' + file alteration events (static monitor support). + """ def __init__(self, debug=False): FileMonitor.__init__(self, debug=False) @@ -210,7 +210,7 @@ class Pseudo(FileMonitor): return self.pending_events.pop() def AddMonitor(self, path, obj): - '''add a monitor to path, installing a callback to obj.HandleEvent''' + """add a monitor to path, installing a callback to obj.HandleEvent""" handleID = len(self.handles.keys()) mode = os.stat(path)[stat.ST_MODE] handle = Event(handleID, path, 'exists') @@ -232,10 +232,10 @@ try: GAMChanged, GAMDeleted, GAMMoved class GaminEvent(Event): - ''' + """ This class provides an event analogous to - python-fam events based on gamin sources - ''' + python-fam events based on gamin sources. + """ def __init__(self, request_id, filename, code): Event.__init__(self, request_id, filename, code) action_map = {GAMCreated: 'created', GAMExists: 'exists', @@ -245,10 +245,10 @@ try: self.action = action_map[code] class Gamin(FileMonitor): - ''' + """ The fam object is a set of callbacks for file alteration events (Gamin support) - ''' + """ def __init__(self, debug=False): FileMonitor.__init__(self, debug) self.mon = WatchMonitor() @@ -259,11 +259,11 @@ try: return self.mon.get_fd() def queue(self, path, action, request_id): - '''queue up the event for later handling''' + """queue up the event for later handling""" self.events.append(GaminEvent(request_id, path, action)) def AddMonitor(self, path, obj): - '''add a monitor to path, installing a callback to obj.HandleEvent''' + """Add a monitor to path, installing a callback to obj.HandleEvent.""" handle = self.counter self.counter += 1 mode = os.stat(path)[stat.ST_MODE] diff --git a/src/lib/Server/Plugin.py b/src/lib/Server/Plugin.py index 7b4bbbf24..765d908dc 100644 --- a/src/lib/Server/Plugin.py +++ b/src/lib/Server/Plugin.py @@ -1,4 +1,4 @@ -'''This module provides the baseclass for Bcfg2 Server Plugins''' +"""This module provides the baseclass for Bcfg2 Server Plugins.""" __revision__ = '$Revision$' import copy @@ -34,15 +34,15 @@ info_regex = re.compile( \ 'paranoid:(\s)*(?P\S+)|mtime:(\s)*(?P\w+)$') class PluginInitError(Exception): - '''Error raised in cases of Plugin initialization errors''' + """Error raised in cases of Plugin initialization errors.""" pass class PluginExecutionError(Exception): - '''Error raised in case of Plugin execution errors''' + """Error raised in case of Plugin execution errors.""" pass class Plugin(object): - '''This is the base class for all Bcfg2 Server plugins. + """This is the base class for all Bcfg2 Server plugins. Several attributes must be defined in the subclass: name : the name of the plugin __version__ : a version string @@ -52,7 +52,7 @@ class Plugin(object): - Structure creation (overloading BuildStructures) - Configuration entry binding (overloading HandlesEntry, or loads the Entries table) - Data collection (overloading GetProbes/ReceiveData) - ''' + """ name = 'Plugin' __version__ = '$Id$' __author__ = 'bcfg-dev@mcs.anl.gov' @@ -86,31 +86,31 @@ class Plugin(object): self.running = False class Generator(object): - '''Generator plugins contribute to literal client configurations''' + """Generator plugins contribute to literal client configurations.""" def HandlesEntry(self, entry, metadata): - '''This is the slow path method for routing configuration binding requests''' + """This is the slow path method for routing configuration binding requests.""" return False def HandleEntry(self, entry, metadata): - '''This is the slow-path handler for configuration entry binding''' + """This is the slow-path handler for configuration entry binding.""" raise PluginExecutionError class Structure(object): - '''Structure Plugins contribute to abstract client configurations''' + """Structure Plugins contribute to abstract client configurations.""" def BuildStructures(self, metadata): - '''return a list of abstract goal structures for client''' + """Return a list of abstract goal structures for client.""" raise PluginExecutionError class Metadata(object): - '''Signal metadata capabilities for this plugin''' + """Signal metadata capabilities for this plugin""" def add_client(self, client_name, attribs): - '''add client''' + """Add client.""" pass def remove_client(self, client_name): - '''remove client''' + """Remove client.""" pass def viz(self, hosts, bundles, key, colors): - '''create viz str for viz admin mode''' + """Create viz str for viz admin mode.""" pass def get_initial_metadata(self, client_name): @@ -120,33 +120,33 @@ class Metadata(object): raise PluginExecutionError class Connector(object): - '''Connector Plugins augment client metadata instances''' + """Connector Plugins augment client metadata instances.""" def get_additional_groups(self, metadata): - '''determine additional groups for metadata''' + """Determine additional groups for metadata.""" return list() def get_additional_data(self, metadata): - '''determine additional data for metadata inst''' + """Determine additional data for metadata inst.""" return dict() class Probing(object): - '''Signal probe capability for this plugin''' + """Signal probe capability for this plugin""" def GetProbes(self, _): - '''Return a set of probes for execution on client''' + """Return a set of probes for execution on client.""" return [] def ReceiveData(self, _, dummy): - '''Receive probe results pertaining to client''' + """Receive probe results pertaining to client.""" pass class Statistics(object): - '''Signal statistics handling capability''' + """Signal statistics handling capability.""" def process_statistics(self, client, xdata): pass class ThreadedStatistics(Statistics, threading.Thread): - '''Threaded statistics handling capability''' + """Threaded statistics handling capability.""" def __init__(self, core, datastore): Statistics.__init__(self) threading.Thread.__init__(self) @@ -158,7 +158,7 @@ class ThreadedStatistics(Statistics, self.start() def save(self): - ''' Save any pending data to a file''' + """ Save any pending data to a file.""" pending_data = [] try: while not self.work_queue.empty(): @@ -179,7 +179,7 @@ class ThreadedStatistics(Statistics, self.logger.warning("Failed to save pending data") def load(self): - ''' Load any pending data to a file''' + """ Load any pending data to a file.""" if not os.path.exists(self.pending_file): return True pending_data = [] @@ -247,7 +247,7 @@ class ThreadedStatistics(Statistics, warned = True def handle_statistics(self, metadata, data): - '''Handle stats here''' + """Handle stats here.""" pass class PullSource(object): @@ -262,12 +262,12 @@ class PullTarget(object): raise PluginExecutionError def AcceptPullData(self, specific, new_entry, verbose): - '''This is the null per-plugin implementation - of bcfg2-admin pull''' + """This is the null per-plugin implementation + of bcfg2-admin pull""" raise PluginExecutionError class Decision(object): - '''Signal decision handling capability''' + """Signal decision handling capability.""" def GetDecisions(self, metadata, mode): return [] @@ -275,17 +275,17 @@ class ValidationError(Exception): pass class StructureValidator(object): - '''Validate/modify goal structures''' + """Validate/modify goal structures.""" def validate_structures(self, metadata, structures): raise ValidationError, "not implemented" class GoalValidator(object): - '''Validate/modify configuration goals''' + """Validate/modify configuration goals.""" def validate_goals(self, metadata, goals): raise ValidationError, "not implemented" class Version(object): - '''Interact with various version control systems''' + """Interact with various version control systems.""" def get_revision(self): return [] def commit_data(self): @@ -294,10 +294,11 @@ class Version(object): # the rest of the file contains classes for coherent file caching class FileBacked(object): - '''This object caches file data in memory. + """This object caches file data in memory. HandleEvent is called whenever fam registers an event. Index can parse the data into member data as required. - This object is meant to be used as a part of DirectoryBacked.''' + This object is meant to be used as a part of DirectoryBacked. + """ def __init__(self, name): object.__init__(self) @@ -305,7 +306,7 @@ class FileBacked(object): self.name = name def HandleEvent(self, event=None): - '''Read file upon update''' + """Read file upon update.""" if event and event.code2str() not in ['exists', 'changed', 'created']: return try: @@ -315,11 +316,11 @@ class FileBacked(object): logger.error("Failed to read file %s" % (self.name)) def Index(self): - '''Update local data structures based on current file state''' + """Update local data structures based on current file state""" pass class DirectoryBacked(object): - '''This object is a coherent cache for a filesystem hierarchy of files.''' + """This object is a coherent cache for a filesystem hierarchy of files.""" __child__ = FileBacked patterns = re.compile('.*') @@ -338,7 +339,7 @@ class DirectoryBacked(object): return self.entries.iteritems() def AddEntry(self, name): - '''Add new entry to data structures upon file creation''' + """Add new entry to data structures upon file creation.""" if name == '': logger.info("got add for empty name") elif name in self.entries: @@ -355,7 +356,7 @@ class DirectoryBacked(object): self.entries[name].HandleEvent() def HandleEvent(self, event): - '''Propagate fam events to underlying objects''' + """Propagate fam events to underlying objects.""" action = event.code2str() if event.filename == '': logger.info("Got event for blank filename") @@ -379,7 +380,7 @@ class DirectoryBacked(object): event.filename) class XMLFileBacked(FileBacked): - '''This object is a coherent cache for an XML file to be used as a part of DirectoryBacked.''' + """This object is a coherent cache for an XML file to be used as a part of DirectoryBacked.""" __identifier__ = 'name' def __init__(self, filename): @@ -388,7 +389,7 @@ class XMLFileBacked(FileBacked): FileBacked.__init__(self, filename) def Index(self): - '''Build local data structures''' + """Build local data structures""" try: xdata = XML(self.data) except XMLSyntaxError: @@ -401,19 +402,19 @@ class XMLFileBacked(FileBacked): return iter(self.entries) class SingleXMLFileBacked(XMLFileBacked): - '''This object is a coherent cache for an independent XML File.''' + """This object is a coherent cache for an independent XML File.""" def __init__(self, filename, fam): XMLFileBacked.__init__(self, filename) fam.AddMonitor(filename, self) class StructFile(XMLFileBacked): - '''This file contains a set of structure file formatting logic''' + """This file contains a set of structure file formatting logic.""" def __init__(self, name): XMLFileBacked.__init__(self, name) self.fragments = {} def Index(self): - '''Build internal data structures''' + """Build internal data structures.""" try: xdata = lxml.etree.XML(self.data) except lxml.etree.XMLSyntaxError: @@ -436,7 +437,7 @@ class StructFile(XMLFileBacked): work[newpred] = group.getchildren() def Match(self, metadata): - '''Return matching fragments of independent''' + """Return matching fragments of independent.""" matching = [frag for (pred, frag) in self.fragments.iteritems() if pred(metadata)] if matching: return reduce(lambda x, y:x+y, matching) @@ -444,7 +445,7 @@ class StructFile(XMLFileBacked): return [] class INode: - '''LNodes provide lists of things available at a particular group intersection''' + """LNodes provide lists of things available at a particular group intersection.""" raw = {'Client':"lambda x:'%s' == x.hostname and predicate(x)", 'Group':"lambda x:'%s' in x.groups and predicate(x)"} nraw = {'Client':"lambda x:'%s' != x.hostname and predicate(x)", @@ -488,7 +489,7 @@ class INode: idict[item.tag] = [item.get('name')] def Match(self, metadata, data): - '''Return a dictionary of package mappings''' + """Return a dictionary of package mappings.""" if self.predicate(metadata): for key in self.contents: try: @@ -500,7 +501,7 @@ class INode: child.Match(metadata, data) class XMLSrc(XMLFileBacked): - '''XMLSrc files contain a LNode hierarchy that returns matching entries''' + """XMLSrc files contain a LNode hierarchy that returns matching entries.""" __node__ = INode __cacheobj__ = dict @@ -513,7 +514,7 @@ class XMLSrc(XMLFileBacked): self.noprio = noprio def HandleEvent(self, _=None): - '''Read file upon update''' + """Read file upon update.""" try: data = file(self.name).read() except IOError: @@ -535,7 +536,7 @@ class XMLSrc(XMLFileBacked): del xdata, data def Cache(self, metadata): - '''Build a package dict for a given host''' + """Build a package dict for a given host.""" if self.cache == None or self.cache[0] != metadata: cache = (metadata, self.__cacheobj__()) if self.pnode == None: @@ -546,11 +547,11 @@ class XMLSrc(XMLFileBacked): self.cache = cache class XMLDirectoryBacked(DirectoryBacked): - '''Directorybacked for *.xml''' + """Directorybacked for *.xml.""" patterns = re.compile('.*\.xml') class PrioDir(Plugin, Generator, XMLDirectoryBacked): - '''This is a generator that handles package assignments''' + """This is a generator that handles package assignments.""" name = 'PrioDir' __child__ = XMLSrc @@ -564,7 +565,7 @@ class PrioDir(Plugin, Generator, XMLDirectoryBacked): raise PluginInitError def HandleEvent(self, event): - '''Handle events and update dispatch table''' + """Handle events and update dispatch table.""" XMLDirectoryBacked.HandleEvent(self, event) self.Entries = {} for src in self.entries.values(): @@ -576,7 +577,7 @@ class PrioDir(Plugin, Generator, XMLDirectoryBacked): self.Entries[itype] = {child: self.BindEntry} def BindEntry(self, entry, metadata): - '''Check package lists of package entries''' + """Check package lists of package entries.""" [src.Cache(metadata) for src in self.entries.values()] name = entry.get('name') if not src.cache: @@ -612,7 +613,7 @@ class PrioDir(Plugin, Generator, XMLDirectoryBacked): # new unified EntrySet backend class SpecificityError(Exception): - '''Thrown in case of filename parse failure''' + """Thrown in case of filename parse failure.""" pass class Specificity: @@ -630,7 +631,7 @@ class Specificity: self.group in metadata.groups def __cmp__(self, other): - '''sort most to least specific''' + """Sort most to least specific.""" if self.all: return 1 if self.group: @@ -643,7 +644,7 @@ class Specificity: return -1 def more_specific(self, other): - '''test if self is more specific than other''' + """Test if self is more specific than other.""" if self.all: True elif self.group: @@ -667,7 +668,7 @@ class SpecificData(object): logger.error("Failed to read file %s" % self.name) class EntrySet: - '''Entry sets deal with the host- and group-specific entries''' + """Entry sets deal with the host- and group-specific entries.""" ignore = re.compile("^(\.#.*|.*~|\\..*\\.(sw[px]))$") def __init__(self, basename, path, entry_type, encoding): self.path = path @@ -685,7 +686,7 @@ class EntrySet: if item.specific.matches(metadata)] def handle_event(self, event): - '''Handle FAM events for the TemplateSet''' + """Handle FAM events for the TemplateSet.""" action = event.code2str() if event.filename in ['info', 'info.xml', ':info']: @@ -706,7 +707,7 @@ class EntrySet: del self.entries[event.filename] def entry_init(self, event): - '''handle template and info file creation''' + """Handle template and info file creation.""" if event.filename in self.entries: logger.warn("Got duplicate add for %s" % event.filename) else: @@ -722,7 +723,7 @@ class EntrySet: self.entries[event.filename].handle_event(event) def specificity_from_filename(self, fname): - '''construct a specificity instance from a filename and regex''' + """Construct a specificity instance from a filename and regex.""" data = self.specific.match(fname) if not data: raise SpecificityError(fname) @@ -739,7 +740,7 @@ class EntrySet: return Specificity(**kwargs) def update_metadata(self, event): - '''process info and info.xml files for the templates''' + """Process info and info.xml files for the templates.""" fpath = "%s/%s" % (self.path, event.filename) if event.filename == 'info.xml': if not self.infoxml: @@ -761,14 +762,14 @@ class EntrySet: (self.metadata['perms']) def reset_metadata(self, event): - '''reset metadata to defaults if info or info.xml removed''' + """Reset metadata to defaults if info or info.xml removed.""" if event.filename == 'info.xml': self.infoxml = None elif event.filename == 'info': self.metadata = default_file_metadata.copy() def group_sortfunc(self, x, y): - '''sort groups by their priority''' + """sort groups by their priority""" return cmp(x.specific.prio, y.specific.prio) def bind_info_to_entry(self, entry, metadata): @@ -786,7 +787,7 @@ class EntrySet: for (key, value) in mdata['Info'][None].iteritems()] def bind_entry(self, entry, metadata): - '''Return the appropriate interpreted template from the set of available templates''' + """Return the appropriate interpreted template from the set of available templates.""" self.bind_info_to_entry(entry, metadata) matching = self.get_matching(metadata) @@ -806,7 +807,7 @@ class EntrySet: raise PluginExecutionError class GroupSpool(Plugin, Generator): - '''Unified interface for handling group-specific data (e.g. .G## files)''' + """Unified interface for handling group-specific data (e.g. .G## files).""" name = 'GroupSpool' __version__ = '$Id$' __author__ = 'bcfg-dev@mcs.anl.gov' @@ -826,7 +827,7 @@ class GroupSpool(Plugin, Generator): self.encoding = core.encoding def HandleEvent(self, event): - '''Unified FAM event handler for DirShadow''' + """Unified FAM event handler for DirShadow.""" action = event.code2str() if event.filename[0] == '/': return @@ -862,7 +863,7 @@ class GroupSpool(Plugin, Generator): self.entries[ident].handle_event(event) def AddDirectoryMonitor(self, relative): - '''Add new directory to FAM structures''' + """Add new directory to FAM structures.""" if not relative.endswith('/'): relative += '/' name = self.data + relative diff --git a/src/lib/Server/__init__.py b/src/lib/Server/__init__.py index 931345168..25f397565 100644 --- a/src/lib/Server/__init__.py +++ b/src/lib/Server/__init__.py @@ -1,5 +1,5 @@ # $Id$ -'''This is the set of modules for Bcfg2.Server''' +"""This is the set of modules for Bcfg2.Server.""" __revision__ = '$Revision$' __all__ = ["Admin", "Core", "FileMonitor", "Plugin", "Plugins", -- cgit v1.2.3-1-g7c22