EnthoughtBase-3.1.0/0000755000175100001440000000000011520337551015236 5ustar ischnellusers00000000000000EnthoughtBase-3.1.0/setup_data.py0000644000175100001440000000013511520102573017732 0ustar ischnellusers00000000000000INFO = { 'name': 'EnthoughtBase', 'version': '3.1.0', 'install_requires' : [], } EnthoughtBase-3.1.0/extras.map0000644000175100001440000000036211517627321017247 0ustar ischnellusers00000000000000[agent] enthought.logger.agent = * [distribution] enthought.util.distribution = * [envisage] enthought.logger.plugin = * enthought.logger.widget = * [traits] enthought.util.traits = * [ui] enthought.util.ui = * enthought.util.wx = * EnthoughtBase-3.1.0/TODO.txt0000644000175100001440000000106611517627321016552 0ustar ischnellusers00000000000000* REMOVE ALL DEPENDENCIES THIS PACKAGE HAS ON OTHER ETS PROJECTS! * Refactor util/equivalence.py to remove the dependency on Traits, or else move the module out of this project. * Separate the logger plugin (basically everything from enthought.logger.plugin on down) from the core logger utility methods / classes this package contains. This will remove some dependencies in our extras. * Refactor util/traits/editor/parameter_choice_editor.py to be toolkit independent -- it is currently hardwired for wx. Or move it out of this project. EnthoughtBase-3.1.0/LICENSE.txt0000644000175100001440000000312011517627321017060 0ustar ischnellusers00000000000000This software is OSI Certified Open Source Software. OSI Certified is a certification mark of the Open Source Initiative. Copyright (c) 2006, Enthought, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Enthought, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. EnthoughtBase-3.1.0/PKG-INFO0000644000175100001440000000374111520337551016340 0ustar ischnellusers00000000000000Metadata-Version: 1.0 Name: EnthoughtBase Version: 3.1.0 Summary: Core packages for the Enthought Tool Suite. Home-page: http://code.enthought.com/projects/enthought_base.php Author: ETS Developers Author-email: enthought-dev@enthought.com License: BSD Download-URL: http://www.enthought.com/repo/ETS/EnthoughtBase-3.1.0.tar.gz Description: The EnthoughtBase project includes a few core packages that are used by many other projects in the Enthought Tool Suite: - **enthought.etsconfig**: Supports configuring settings that need to be shared across multiple projects or programs on the same system. Most significant of these is the GUI toolkit to be used. You can also configure locations for writing application data and user data, and the name of the company responsible for the software (which is used in the application and user data paths on some systems). - **enthought.logger**: Provides convenience functions for creating logging handlers. - **enthought.util**: Provides miscellaneous utility functions. Prerequisites ------------- If you want to build EnthoughtBase from source, you must first install `setuptools `_. Platform: Windows Platform: Linux Platform: Mac OS-X Platform: Unix Platform: Solaris Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Science/Research Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: MacOS Classifier: Operating System :: Microsoft :: Windows Classifier: Operating System :: OS Independent Classifier: Operating System :: POSIX Classifier: Operating System :: Unix Classifier: Programming Language :: Python Classifier: Topic :: Scientific/Engineering Classifier: Topic :: Software Development Classifier: Topic :: Software Development :: Libraries EnthoughtBase-3.1.0/enthought/0000755000175100001440000000000011520337551017243 5ustar ischnellusers00000000000000EnthoughtBase-3.1.0/enthought/logger/0000755000175100001440000000000011520337551020522 5ustar ischnellusers00000000000000EnthoughtBase-3.1.0/enthought/logger/util.py0000644000175100001440000000740211517627321022057 0ustar ischnellusers00000000000000""" Utility functions. fixme: I don't like random collections of utility functions! Where should this go? """ # Standard library imports. import os from os.path import basename, dirname, isdir, splitdrive, splitext from zipfile import is_zipfile, ZipFile def get_module_name(filename): """ Get the fully qualified module name for a filename. For example, if the filename is /enthought/envisage/core/core_plugin_definition.py this method would return enthought.envisage.core.core_plugin_definition """ if os.path.exists(filename): # Get the name of the module minus the '.py' module, ext = os.path.splitext(os.path.basename(filename)) # Start with the actual module name. module_path = [module] # If the directory is a Python package then add it to the module path. #return self.is_folder and '__init__.py' in os.listdir(self.path) parent = dirname(filename) while isdir(parent) and '__init__.py' in os.listdir(parent): bname = basename(parent) module_path.insert(0, splitext(bname)[0]) parent = dirname(parent) module_name = '.'.join(module_path) # If the file does not exist then it might be a zip file path. else: module_name = get_module_name_from_zip(filename) return module_name # fixme: WIP def get_module_name_from_zip(filename): # first, find the zip file in the path filepath = filename zippath = None while not is_zipfile(filepath) and \ splitdrive(filepath)[1] != '\\' \ and splitdrive(filepath)[1] != '/': filepath, tail = os.path.split(filepath) if zippath is not None: zippath = tail + '/' + zippath else: zippath = tail if not is_zipfile(filepath): return None # if the split left a preceding slash on the zippath then remove # it if zippath.startswith('\\') or zippath.startswith('/'): zippath = zippath[1:] # replace any backwards slashes with forward slashes zippath = zippath.replace('\\', '/') # Get the name of the module minus the '.py' module, ext = splitext(basename(zippath)) # Start with the actual module name. module_path = [module] # to get the module name, we walk through the zippath until we # find a parent directory that does NOT have a __init__.py file z = ZipFile(filepath) parentpath = dirname(zippath) while path_exists_in_zip(z, parentpath + '/__init__.py'): module_path.insert(0, basename(parentpath)) parentpath = dirname(parentpath) z.close() return '.'.join(module_path) # fixme: WIP def path_exists_in_zip(zfile, path): try: zfile.getinfo(path) exists = True except: exists = False return exists # fixme: WIP def is_zip_path(path): """ Returns True if the path refers to a zip file. """ filepath = path while not is_zipfile(filepath) and \ splitdrive(filepath)[1] != '\\' \ and splitdrive(filepath)[1] != '/': filepath = dirname(filepath) return is_zipfile(filepath) # fixme: WIP def get_zip_path(filename): """ Returns the path to the zip file contained in the filename. fixme: An example here would help. """ filepath = filename zippath = None while not is_zipfile(filepath) and \ splitdrive(filepath)[1] != '\\' \ and splitdrive(filepath)[1] != '/': filepath, tail = os.path.split(filepath) if zippath is not None: zippath = tail + '/' + zippath else: zippath = tail return zippath #### EOF ###################################################################### EnthoughtBase-3.1.0/enthought/logger/plugin/0000755000175100001440000000000011520337551022020 5ustar ischnellusers00000000000000EnthoughtBase-3.1.0/enthought/logger/plugin/logger_preferences.py0000644000175100001440000000146711517627321026245 0ustar ischnellusers00000000000000import logging from enthought.preferences.api import PreferencesHelper from enthought.traits.api import Bool, Str, Trait class LoggerPreferences(PreferencesHelper): """ The persistent service exposing the Logger plugin's API. """ #### Preferences ########################################################### # The log levels level = Trait('Info', {'Debug' : logging.DEBUG, 'Info' : logging.INFO, 'Warning' : logging.WARNING, 'Error' : logging.ERROR, 'Critical' : logging.CRITICAL, }, is_str = True, ) enable_agent = Bool(False) smtp_server = Str() to_address = Str() from_address = Str() # The path to the preferences node that contains the preferences. preferences_path = Str('enthought.logger') EnthoughtBase-3.1.0/enthought/logger/plugin/preferences.ini0000644000175100001440000000015211517627321025023 0ustar ischnellusers00000000000000[enthought.logger] level = 'Info' enable_agent = False smtp_server = '' to_address = '' from_address = '' EnthoughtBase-3.1.0/enthought/logger/plugin/logger_service.py0000644000175100001440000001166711517627321025407 0ustar ischnellusers00000000000000# Standard library imports from cStringIO import StringIO import logging import os import zipfile # Enthought library imports from enthought.pyface.workbench.api import View as WorkbenchView from enthought.traits.api import Any, Callable, HasTraits, Instance, List, \ Property, Undefined, on_trait_change root_logger = logging.getLogger() logger = logging.getLogger(__name__) class LoggerService(HasTraits): """ The persistent service exposing the Logger plugin's API. """ # The Envisage application. application = Any() # The logging Handler we use. handler = Any() # Our associated LoggerPreferences. preferences = Any() # The view we use. plugin_view = Instance(WorkbenchView) # Contributions from other plugins. mail_files = Property(List(Callable)) def save_preferences(self): """ Save the preferences. """ self.preferences.preferences.save() def whole_log_text(self): """ Return all of the logged data as formatted text. """ lines = [ self.handler.format(rec) for rec in self.handler.get() ] # Ensure that we end with a newline. lines.append('') text = '\n'.join(lines) return text def create_email_message(self, fromaddr, toaddrs, ccaddrs, subject, priority, include_userdata=False, stack_trace="", comments="", include_environment=True): """ Format a bug report email from the log files. """ from email.mime.application import MIMEApplication from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText message = MIMEMultipart() message['Subject'] = "%s [priority=%s]" % (subject, priority) message['To'] = ', '.join(toaddrs) message['Cc'] = ', '.join(ccaddrs) message['From'] = fromaddr message.preamble = 'You will not see this in a MIME-aware mail ' \ 'reader.\n' message.epilogue = ' ' # To guarantee the message ends with a newline # First section is simple ASCII data ... m = [] m.append("Bug Report") m.append("==============================") m.append("") if len(comments) > 0: m.append("Comments:") m.append("========") m.append(comments) m.append("") if len(stack_trace) > 0: m.append("Stack Trace:") m.append("===========") m.append(stack_trace) m.append("") msg = MIMEText('\n'.join(m)) message.attach(msg) # Include the log file ... logtext = self.whole_log_text() msg = MIMEText(logtext) msg.add_header('Content-Disposition', 'attachment', filename='logfile.txt') message.attach(msg) # Include the environment variables ... # FIXME: ask the user, maybe? if include_environment: # Transmit the user's environment settings as well. Main purpose is # to work out the user name to help with following up on bug reports # and in future we should probably send less data. entries = [] for key, value in sorted(os.environ.items()): entries.append('%30s : %s\n' % (key, value)) msg = MIMEText(''.join(entries)) msg.add_header('Content-Disposition', 'attachment', filename='environment.txt') message.attach(msg) if include_userdata and len(self.mail_files) != 0: f = StringIO() zf = zipfile.ZipFile(f, 'w') for mf in self.mail_files: mf(zf) zf.close() msg = MIMEApplication(f.getvalue()) msg.add_header('Content-Disposition', 'attachment', filename='userdata.zip') message.attach(msg) return message def send_bug_report(self, smtp_server, fromaddr, toaddrs, ccaddrs, message): """ Send a bug report email. """ try: import smtplib logger.debug("Connecting to: %s" % smtp_server) server = smtplib.SMTP(host=smtp_server) logger.debug("Connected: %s" % server) #server.set_debuglevel(1) server.sendmail(fromaddr, toaddrs + ccaddrs, message.as_string()) server.quit() except Exception, e: logger.exception("Problem sending error report") #### Traits stuff ######################################################### def _get_mail_files(self): return self.application.get_extensions( 'enthought.logger.plugin.mail_files') @on_trait_change('preferences.level_') def _level_changed(self, new): if (new is not None and new is not Undefined and self.handler is not None): root_logger.setLevel(self.preferences.level_) self.handler.setLevel(self.preferences.level_) EnthoughtBase-3.1.0/enthought/logger/plugin/logger_plugin.py0000644000175100001440000000742311517627321025240 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ """ Logger plugin. """ # Standard library imports. import logging # Enthought library imports. from enthought.envisage.api import ExtensionPoint, Plugin from enthought.logger.log_queue_handler import LogQueueHandler from enthought.traits.api import Callable, List # Local imports. from logger_preferences import LoggerPreferences from logger_service import LoggerService ID = 'enthought.logger' ILOGGER = ID + '.plugin.logger_service.LoggerService' class LoggerPlugin(Plugin): """ Logger plugin. """ id = ID name = 'Logger plugin' #### Extension points for this plugin ###################################### MAIL_FILES = 'enthought.logger.plugin.mail_files' mail_files = ExtensionPoint( List(Callable), id=MAIL_FILES, desc=""" This extension point allows you to contribute functions which will be called to add project files to the zip file that the user mails back with bug reports from the Quality Agent. The function will be passed a zipfile.ZipFile object. """ ) #### Contributions to extension points made by this plugin ################# PREFERENCES = 'enthought.envisage.preferences' PREFERENCES_PAGES = 'enthought.envisage.ui.workbench.preferences_pages' VIEWS = 'enthought.envisage.ui.workbench.views' preferences = List(contributes_to=PREFERENCES) preferences_pages = List(contributes_to=PREFERENCES_PAGES) views = List(contributes_to=VIEWS) def _preferences_default(self): return ['pkgfile://%s/plugin/preferences.ini' % ID] def _preferences_pages_default(self): from enthought.logger.plugin.view.logger_preferences_page import \ LoggerPreferencesPage return [LoggerPreferencesPage] def _views_default(self): return [self._logger_view_factory] #### Plugin interface ###################################################### def start(self): """ Starts the plugin. """ preferences = LoggerPreferences() service = LoggerService(application=self.application, preferences=preferences) formatter = logging.Formatter('%(levelname)s|%(asctime)s|%(message)s') handler = LogQueueHandler() handler.setLevel(preferences.level_) handler.setFormatter(formatter) root_logger = logging.getLogger() root_logger.addHandler(handler) root_logger.setLevel(preferences.level_) service.handler = handler self.application.register_service(ILOGGER, service) def stop(self): """ Stops the plugin. """ service = self.application.get_service(ILOGGER) service.save_preferences() #### LoggerPlugin private interface ######################################## def _logger_view_factory(self, **traits): from enthought.logger.plugin.view.logger_view import LoggerView service = self.application.get_service(ILOGGER) view = LoggerView(service=service, **traits) # Record the created view on the service. service.plugin_view = view return view #### EOF ###################################################################### EnthoughtBase-3.1.0/enthought/logger/plugin/__init__.py0000644000175100001440000000000011517627321024122 0ustar ischnellusers00000000000000EnthoughtBase-3.1.0/enthought/logger/plugin/view/0000755000175100001440000000000011520337551022772 5ustar ischnellusers00000000000000EnthoughtBase-3.1.0/enthought/logger/plugin/view/images/0000755000175100001440000000000011520337551024237 5ustar ischnellusers00000000000000EnthoughtBase-3.1.0/enthought/logger/plugin/view/images/error.png0000644000175100001440000000701511517627321026104 0ustar ischnellusers00000000000000PNG  IHDRa pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-gAMA|Q cHRMz%u0`:o_F(IDATxdoe3|8Cڤ%W vD(%"iH ]T qaY`"I h')I#&l iikgڙv:̼3\ЦƳ7䞣D>@Z(v˧ O65jOdxj *kh%` eĉlזht  KK0o௯qmZqhX/OJ{x|j7o2J^d]"ӔWWnm%1<̲1d!4?9zD~mm`hH6ɽ~ _'Oʽc>9XW7c\_R!~ѽ{yu`Ȏt^JKd'&ȋPؠjgJīU=4D)#qؖ<.^dY6~V&jJzyR]k|hR.s| N ?"+EU cm Kco/o|MXlǡ;$%ץ^4 ~թThaO5Ǐ)NLc_/#C!fYq|X{TdXe'ucc9,B_gٽFڰW2!%"uH2{*gI:|{b~D3T*(,H$>4F1jk)R <*  ss뮛OB MhR"BEJgf?;Neġx H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-gAMA|Q cHRMz%u0`:o_FIDATxdOuysw7NdfKn"jV1eQ1)Y̢ Vm35TXCWgRrs|>}y/l-t]ٳŌc*e~«P Cu~fJ";!%<UnCkBӎ:cW Xed l, {rgMALF̓q}xPػl2ox`sg&zE/bq Qy EW; C=k|w~o+eK ʙRէãw:*`%6l L<؏˿U+SEHc" ÏWM/ ڲB+9HqîS{kJߩ߇/!obz{Mx3МDJJӓ V,GnooB*rE]AU#vzfr1 03O'< s)bf8>Ѐ/R4m Ea$B ENp+611mi˱3XPP)Ie ^.(q,u)K O5˃`dR`*I_W+5&6Ĕpi>S&m[PVV6>MYvkQRWIENDB`EnthoughtBase-3.1.0/enthought/logger/plugin/view/images/warning.png0000644000175100001440000000676711517627321026435 0ustar ischnellusers00000000000000PNG  IHDRa pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-gAMA|Q cHRMz%u0`:o_FIDATxlKh\uLn&I2 yƄ8ؚ`*āBEAЕ bhA+.FJ4h3Iit^q1)n9?QUņƖQ=#O;EXχT=VW+޺4j *``d>hD!n[ll Ǯŕڬ87`6iCΩܻ܄j]lz?* ^1+pcWwVHݣn kcz1Sg)=}~S}'**j\?BJ*ۺN?K<稝C610"8L4dOX,QHc/?^u{ ƾ0$-E\Tk.Yu3rFưoA ym}[Gc d;V @N.'3ߜxgw>z ֮69+a qҝSafq1IdBqDRF]ZUh\H _Lc%/]#ji@TPX1 HݪT.5:IENDB`EnthoughtBase-3.1.0/enthought/logger/plugin/view/images/crit_error.png0000644000175100001440000000156711517627321027133 0ustar ischnellusers00000000000000PNG  IHDRabKGD pHYs  tIME&E+IDAT8mKh\eǘԤ6L  Tj(DMW" 7-T6*DBA\( A([)jҎNB%s9wRw}wy\<R.ȏnFG}uBզh5hFL_>MA`EBl[z;ZU16wEA)u4' b!V7vk_71~Scl k GVL4A/\8Jiӵu"Z綂 1>㝳tnIiR)R=C\BDVT,sZ.nT+9oz';gSL*hWx1Dd6p+|8>YJ&#]=S&%nXPܹw׻ Xbeuj PbpdVAFIENDB`EnthoughtBase-3.1.0/enthought/logger/plugin/view/images/image_LICENSE.txt0000644000175100001440000000113111517627321027223 0ustar ischnellusers00000000000000The icons are mostly derived work from other icons. As such they are licensed accordingly to the original license: Crystal Project: LGPL license as described in image_LICENSE_CP.txt Unless stated in this file, icons are work of enthought, and are released under BSD-like license. Files and orginal authors: ---------------------------------------------------------------- about.png Crystal Project crit_error.png Crystal Project debug.png Crystal Project error.png Crystal Project warning.png Crystal Project EnthoughtBase-3.1.0/enthought/logger/plugin/view/images/info.png0000644000175100001440000000706011517627321025706 0ustar ischnellusers00000000000000PNG  IHDRa pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-gAMA|Q cHRMz%u0`:o_FKIDATxdOe;c A1 1BXMg= jԛăkL* RPk -t0·<ɓF&0{甴͡4ɮ< ]BJn~r}wM z'BZBYD,*MhAQQ7 x2I2K f #------------------------------------------------------------------------------ import logging from enthought.preferences.ui.api import PreferencesPage from enthought.traits.api import Bool, Trait, Str from enthought.traits.ui.api import EnumEditor, Group, Item, View class LoggerPreferencesPage(PreferencesPage): """ A preference page for the logger plugin. """ #### 'PreferencesPage' interface ########################################## # The page's category (e.g. 'General/Appearance'). The empty string means # that this is a top-level page. category = '' # The page's help identifier (optional). If a help Id *is* provided then # there will be a 'Help' button shown on the preference page. help_id = '' # The page name (this is what is shown in the preferences dialog. name = 'Logger' # The path to the preferences node that contains the preferences. preferences_path = 'enthought.logger' #### Preferences ########################################################### # The log levels level = Trait('Info', {'Debug' : logging.DEBUG, 'Info' : logging.INFO, 'Warning' : logging.WARNING, 'Error' : logging.ERROR, 'Critical' : logging.CRITICAL, }, is_str = True, ) enable_agent = Bool(False) smtp_server = Str to_address = Str from_address = Str # The view used to change the plugin preferences traits_view = View( Group( Group( Item( name='level', editor=EnumEditor( values={ 'Debug' : '1:Debug', 'Info' : '2:Info', 'Warning' : '3:Warning', 'Error' : '4:Error' , 'Critical' : '5:Critical', }, ), style='simple', ), label='Logger Settings', show_border=True, ), Group(Item(name='10')), Group( Group( Group(Item(name='enable_agent', label='Enable quality agent'), show_left=False), Group(Item(name='smtp_server', label='SMTP server'), Item(name='from_address'), Item(name='to_address'), enabled_when='enable_agent==True')), label='Quality Agent Settings', show_border=True, ), ), ) #### EOF ###################################################################### EnthoughtBase-3.1.0/enthought/logger/plugin/view/logger_view.py0000644000175100001440000001560011517627321025662 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ # Standard library imports from datetime import datetime import logging # Enthought library imports. from enthought.pyface.api import ImageResource, clipboard from enthought.pyface.workbench.api import TraitsUIView from enthought.traits.api import Button, Instance, List, Property, Str, \ cached_property, on_trait_change from enthought.traits.ui.api import View, Group, Item, CodeEditor, \ TabularEditor, spring from enthought.traits.ui.tabular_adapter import TabularAdapter # Local imports from enthought.logger.agent.quality_agent_view import QualityAgentView from enthought.logger.plugin import view from enthought.logger.plugin.logger_service import LoggerService # Constants _IMAGE_MAP = { logging.DEBUG: ImageResource('debug'), logging.INFO: ImageResource('info'), logging.WARNING: ImageResource('warning'), logging.ERROR: ImageResource('error'), logging.CRITICAL: ImageResource('crit_error') } class LogRecordAdapter(TabularAdapter): """ A TabularEditor adapter for logging.LogRecord objects. """ columns = [ ('Level', 'level'), ('Date', 'date'), ('Time', 'time'), ('Message', 'message') ] column_widths = [ 80, 100, 120, -1 ] level_image = Property level_text = Property(Str) date_text = Property(Str) time_text = Property(Str) message_text = Property(Str) def get_width(self, object, trait, column): return self.column_widths[column] def _get_level_image(self): return _IMAGE_MAP[self.item.levelno] def _get_level_text(self): return self.item.levelname.capitalize() def _get_date_text(self): dt = datetime.fromtimestamp(self.item.created) return dt.date().isoformat() def _get_time_text(self): dt = datetime.fromtimestamp(self.item.created) return dt.time().isoformat() def _get_message_text(self): # Just display the first line of multiline messages, like stacktraces. msg = self.item.getMessage() msgs = msg.strip().split('\n') if len(msgs) > 1: suffix = '... [double click for details]' else: suffix = '' abbrev_msg = msgs[0] + suffix return abbrev_msg class LoggerView(TraitsUIView): """ The Workbench View showing the list of log items. """ id = Str('enthought.logger.plugin.view.logger_view.LoggerView') name = Str('Logger') service = Instance(LoggerService) log_records = List(Instance(logging.LogRecord)) formatted_records = Property(Str, depends_on='log_records') activated = Instance(logging.LogRecord) activated_text = Property(Str, depends_on='activated') reset_button = Button("Reset Logs") show_button = Button("Complete Text Log") copy_button = Button("Copy Log to Clipboard") code_editor = CodeEditor(lexer='null', show_line_numbers=False) log_records_editor = TabularEditor(adapter=LogRecordAdapter(), editable=False, activated='activated') trait_view = View(Group(Item('log_records', editor=log_records_editor), Group(Item('reset_button'), spring, Item('show_button'), Item('copy_button'), orientation='horizontal', show_labels=False), show_labels=False)) ########################################################################### # LogQueueHandler view interface ########################################################################### def update(self, force=False): """ Update 'log_records' if our handler has new records or 'force' is set. """ service = self.service if service.handler.has_new_records() or force: self.log_records = [ rec for rec in service.handler.get() if rec.levelno >= service.preferences.level_ ] ########################################################################### # Private interface ########################################################################### @on_trait_change('service.preferences.level_') def _update_log_records(self): self.service.handler._view = self self.update(force=True) def _reset_button_fired(self): self.service.handler.reset() self.log_records = [] def _show_button_fired(self): self.edit_traits(view=View(Item('formatted_records', editor=self.code_editor, style='readonly', show_label=False), width=800, height=600, resizable=True, buttons=[ 'OK' ], title='Complete Text Log')) def _copy_button_fired(self): clipboard.text_data = self.formatted_records @cached_property def _get_formatted_records(self): return '\n'.join([ self.service.handler.formatter.format(record) for record in self.log_records ]) def _activated_changed(self): if self.activated is None: return msg = self.activated.getMessage() if self.service.preferences.enable_agent: dialog = QualityAgentView(msg=msg, service=self.service) dialog.open() else: self.edit_traits(view=View(Item('activated_text', editor=self.code_editor, style='readonly', show_label=False), width=800, height=600, resizable=True, buttons=[ 'OK' ], title='Log Message Detail')) @cached_property def _get_activated_text(self): if self.activated is None: return '' else: return self.activated.getMessage() #### EOF ###################################################################### EnthoughtBase-3.1.0/enthought/logger/plugin/view/__init__.py0000644000175100001440000000000011517627321025074 0ustar ischnellusers00000000000000EnthoughtBase-3.1.0/enthought/logger/log_queue_handler.py0000644000175100001440000000460011517627321024561 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ # Standard library imports. from logging import Handler # Enthought library imports. from enthought.util.ring_buffer import RingBuffer class LogQueueHandler(Handler): """ Buffers up the log messages so that we can display them later. This is important on startup when log messages are generated before the ui has started. By putting them in this queue we can display them once the ui is ready. """ # The view where updates will go _view = None def __init__(self, size=1000): Handler.__init__(self) # only buffer 1000 log records self.size = size self.ring = RingBuffer(self.size) self.dirty = False return def emit(self, record): """ Actually this is more like an enqueue than an emit().""" self.ring.append(record) if self._view is not None: try: self._view.update() except Exception, e: pass self.dirty = True return def get(self): self.dirty = False try: result = self.ring.get() except Exception, msg: # we did our best and it won't cause too much damage # to just return a bogus message result = [] return result def has_new_records(self): return self.dirty def reset(self): # start over with a new empty buffer self.ring = RingBuffer(self.size) if self._view is not None: try: self._view.update() except Exception, e: pass self.dirty = True return ## EOF ################################################################## EnthoughtBase-3.1.0/enthought/logger/logger.py0000644000175100001440000000545711517627321022371 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ """ Convenience functions for creating logging handlers etc. """ # Standard library imports. import logging from logging.handlers import RotatingFileHandler # Enthought library imports. from enthought.util.api import deprecated # Local imports. from log_queue_handler import LogQueueHandler # The default logging level. LEVEL = logging.DEBUG # The default formatter. FORMATTER = logging.Formatter('%(levelname)s|%(asctime)s|%(message)s') class LogFileHandler(RotatingFileHandler): """ The default log file handler. """ def __init__(self, path, maxBytes=1000000, backupCount=3, level=None, formatter=None): RotatingFileHandler.__init__( self, path, maxBytes=maxBytes, backupCount=3 ) if level is None: level = LEVEL if formatter is None: formatter = FORMATTER # Set our default formatter and log level. self.setFormatter(formatter) self.setLevel(level) @deprecated('use "LogFileHandler"') def create_log_file_handler(path, maxBytes=1000000, backupCount=3, level=None, formatter=None): """ Creates a log file handler. This is just a convenience function to make it easy to create the same kind of handlers across applications. It sets the handler's formatter to the default formatter, and its logging level to the default logging level. """ if level is None: level = LEVEL if formatter is None: formatter = FORMATTER handler = RotatingFileHandler( path, maxBytes=maxBytes, backupCount=backupCount ) handler.setFormatter(formatter) handler.setLevel(level) return handler def add_log_queue_handler(logger, level=None, formatter=None): """ Adds a queueing log handler to a logger. """ if level is None: level = LEVEL if formatter is None: formatter = FORMATTER # Add the handler to the root logger. log_queue_handler = LogQueueHandler() log_queue_handler.setLevel(level) log_queue_handler.setFormatter(formatter) logger.addHandler(log_queue_handler) return log_queue_handler #### EOF ###################################################################### EnthoughtBase-3.1.0/enthought/logger/filtering_handler.py0000644000175100001440000001411511517627321024561 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ """ A log handler that allows filtering of messages by origin. """ # Standard library imports. import logging, inspect, os # Local imports. # # fixme: This module was just copied over from 'enthought.envisage.core' (so # that we don't rely on Envisage here!). Where should this module go? from util import get_module_name class FilteringHandler(logging.Handler): """ A log handler that allows filtering of messages by origin. Example ------- :: from enthought.logger.api import DebugHandler, logger handler = FilteringHandler( include = { 'enthought.envisage.core' : True }, exclude = { 'enthought.envisage.core.application' : False } ) logger.addHandler(handler) Notes ----- The boolean value specified for each name in the include and exclude dictionaries indicates whether or not the include or exclude should pertain to any sub-packages and modules. The above example includes all log messages from anything contained in, or under the 'enthought.envisage.core' package, EXCEPT for any log messages from the 'enthought.envisage.core.application' module. """ ########################################################################### # 'object' interface. ########################################################################### def __init__(self, include=None, exclude=None): """ Creates a new handler. """ # Base class constructor. logging.Handler.__init__(self) # Packages or modules to include. self.include = include is not None and include or {} # Packages or modules to exclude. self.exclude = exclude is not None and exclude or {} return ########################################################################### # 'Handler' interface. ########################################################################### def emit(self, record): """ Emits a log record. """ # Get the name of the module that the logger was called from. module_name = self._get_module_name() if len(self.include) == 0 or self._include(module_name): if len(self.exclude) == 0 or not self._exclude(module_name): self.filtered_emit(record) return ########################################################################### # 'Handler' interface. ########################################################################### def filtered_emit(self, record): """ Emits a log record if it has not been filtered. """ print record.getMessage() return ########################################################################### # Private interface. ########################################################################### def _get_module_name(self): """ Returns the module that the logger was actually called from. """ # fixem: Ahem.... what can I say... this gets us to the actual caller! frame = inspect.currentframe() frame = frame.f_back.f_back.f_back.f_back.f_back.f_back.f_back # This returns a tuple containing the last 5 elements of the frame # record which are:- # # - the filename # - the line number # - the function name # - the list of lines of context from the source code # - the index of the current line within that list filename, lineno, funcname, source, index = inspect.getframeinfo(frame) # The plugin definition's location is the directory containing the # module that it is defined in. self.location = os.path.dirname(filename) # We can't use 'inspect.getmodulename' here as it gets confused because # of our import hook in Envisage 8^( # # e.g. for the core plugin definition:- # # using inspect -> 'core_plugin_definition' # using ours -> 'enthought.envisage.core.core_plugin_definition' return get_module_name(filename) def _include(self, module_name): """ Is the module name in the include set? """ for item, include_children in self.include.items(): if item == module_name: include = True break elif include_children and self._is_child_of(item, module_name): include = True break else: include = False return include def _exclude(self, module_name): """ Is the module name in the exclude set? """ for item, exclude_children in self.exclude.items(): if item == module_name: exclude = True break elif exclude_children and self._is_child_of(item, module_name): exclude = True break else: exclude = False return exclude def _is_child_of(self, x, y): """ Is 'y' a child symbol of 'x'? e.g. 'foo.bar.baz' (y) is a child of 'foo.bar' (x) """ if y.startswith(x): x_atoms = x.split('.') y_atoms = y.split('.') is_child_of = y_atoms[:len(x_atoms)] == x_atoms else: is_child_of = False return is_child_of #### EOF ###################################################################### EnthoughtBase-3.1.0/enthought/logger/api.py0000644000175100001440000000035211517627321021650 0ustar ischnellusers00000000000000from logger import add_log_queue_handler, create_log_file_handler from logger import FORMATTER, LEVEL, LogFileHandler from log_point import log_point from filtering_handler import FilteringHandler from null_handler import NullHandler EnthoughtBase-3.1.0/enthought/logger/custom_excepthook.py0000644000175100001440000000255711517627321024653 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ # Standard library imports. import logging from traceback import format_exception """ To catch exceptions with our own code this code needs to be added sys.excepthook = custom_excepthook """ def custom_excepthook(type, value, traceback): """ Pass on the exception to the logging system. """ msg = 'Custom - Traceback (most recent call last):\n' list = format_exception(type, value, traceback) msg = "".join(list) # Try to find the module that the exception actually came from. name = getattr(traceback.tb_frame, 'f_globals', {}).get('__name__', __name__) logger = logging.getLogger(name) logger.error(msg) return ## EOF ################################################################## EnthoughtBase-3.1.0/enthought/logger/agent/0000755000175100001440000000000011520337551021620 5ustar ischnellusers00000000000000EnthoughtBase-3.1.0/enthought/logger/agent/quality_agent_mailer.py0000644000175100001440000000766611517627320026412 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ # Standard library imports. import logging import os # Enthought library imports. from enthought.util.home_directory import get_home_directory # Setup a logger for this module. logger = logging.getLogger(__name__) def create_email_message(fromaddr, toaddrs, ccaddrs, subject, priority, include_project=False, stack_trace="", comments=""): # format a message suitable to be sent to the Roundup bug tracker from email.MIMEMultipart import MIMEMultipart from email.MIMEText import MIMEText from email.MIMEBase import MIMEBase message = MIMEMultipart() message['Subject'] = "%s [priority=%s]" % (subject, priority) message['To'] = ', '.join(toaddrs) message['Cc'] = ', '.join(ccaddrs) message['From'] = fromaddr message.preamble = 'You will not see this in a MIME-aware mail reader.\n' message.epilogue = ' ' # To guarantee the message ends with a newline # First section is simple ASCII data ... m = [] m.append("Bug Report") m.append("==============================") m.append("") if len(comments) > 0: m.append("Comments:") m.append("========") m.append(comments) m.append("") if len(stack_trace) > 0: m.append("Stack Trace:") m.append("===========") m.append(stack_trace) m.append("") msg = MIMEText('\n'.join(m)) message.attach(msg) # Include the log file ... if True: try: log = os.path.join(get_home_directory(), 'envisage.log') f = open(log, 'r') entries = f.readlines() f.close() ctype = 'application/octet-stream' maintype, subtype = ctype.split('/', 1) msg = MIMEBase(maintype, subtype) msg = MIMEText(''.join(entries)) msg.add_header('Content-Disposition', 'attachment', filename='logfile.txt') message.attach(msg) except: logger.exception('Failed to include log file with message') # Include the environment variables ... if True: """ Transmit the user's environment settings as well. Main purpose is to work out the user name to help with following up on bug reports and in future we should probably send less data. """ try: entries = [] for key, value in os.environ.iteritems(): entries.append('%30s : %s\n' % (key, value)) ctype = 'application/octet-stream' maintype, subtype = ctype.split('/', 1) msg = MIMEBase(maintype, subtype) msg = MIMEText(''.join(entries)) msg.add_header('Content-Disposition', 'attachment', filename='environment.txt') message.attach(msg) except: logger.exception('Failed to include environment variables with message') # FIXME: no project plugins exist for Envisage 3, yet, and this isn't the right # way to do it, either. See the docstring of attachments.py. # # Attach the project if requested ... # if include_project: # from attachments import Attachments # try: # attachments = Attachments(message) # attachments.package_any_relevant_files() # except: # logger.exception('Failed to include workspace files with message') return message EnthoughtBase-3.1.0/enthought/logger/agent/__init__.py0000644000175100001440000000004211517627320023727 0ustar ischnellusers00000000000000""" lib.enthought.logger.agent """EnthoughtBase-3.1.0/enthought/logger/agent/attachments.py0000644000175100001440000000542311517627320024513 0ustar ischnellusers00000000000000""" Attach relevant project files. FIXME: there are no public project plugins for Envisage 3, yet. In any case, this stuff should not be hard-coded, but extensible via extension points. The code remains here because we can reuse the zip utility code in that extensible rewrite. """ import logging import os.path from email import Encoders from email.MIMEBase import MIMEBase from enthought.traits.api import Any, HasTraits logger = logging.getLogger(__name__) class Attachments(HasTraits): application = Any() message = Any() def __init__(self, message, **traits): traits = traits.copy() traits['message'] = message super(Attachments, self).__init__(**traits) # FIXME: all of the package_*() methods refer to deprecated project plugins. def package_workspace(self): if self.application is None: pass workspace = self.application.get_service('enthought.envisage.project.IWorkspace') if workspace is not None: dir = workspace.path self._attach_directory(dir) return def package_single_project(self): if self.application is None: pass single_project = self.application.get_service('enthought.envisage.single_project.ModelService') if single_project is not None: dir = single_project.location self._attach_directory(dir) def package_any_relevant_files(self): self.package_workspace() self.package_single_project() return def _attach_directory(self, dir): relpath = os.path.basename(dir) import zipfile from cStringIO import StringIO ctype = 'application/octet-stream' maintype, subtype = ctype.split('/', 1) msg = MIMEBase(maintype, subtype) file_object = StringIO() zip = zipfile.ZipFile(file_object, 'w') _append_to_zip_archive(zip, dir, relpath) zip.close() msg.set_payload(file_object.getvalue()) Encoders.encode_base64(msg) # Encode the payload using Base64 msg.add_header('Content-Disposition', 'attachment', filename='project.zip') self.message.attach(msg) file_object.close() def _append_to_zip_archive(zip, dir, relpath): """ Add all files in and below directory dir into zip archive""" for filename in os.listdir(dir): path = os.path.join(dir, filename) if os.path.isfile(path): name = os.path.join(relpath, filename) zip.write(path, name) logger.debug('adding %s to error report' % path) else: if filename != ".svn": # skip svn files if any subdir = os.path.join(dir, filename) _append_to_zip_archive(zip, subdir, os.path.join(relpath, filename)) return EnthoughtBase-3.1.0/enthought/logger/agent/quality_agent_view.py0000644000175100001440000002775011517627320026107 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ # Standard library imports. import logging # Enthought library imports. from enthought.pyface.api import Dialog from enthought.traits.api import Any, Str, Tuple # Setup a logger for this module. logger = logging.getLogger(__name__) priority_levels = ['Low', 'Medium', 'High', 'Critical'] class QualityAgentView(Dialog): size = Tuple((700, 900)) title = Str('Quality Agent') # The associated LoggerService. service = Any() msg = Str('') subject = Str('Untitled Error Report') to_address = Str() cc_address = Str('') from_address = Str() smtp_server = Str() priority = Str(priority_levels[2]) comments = Str('None') include_userdata = Any ########################################################################### # Protected 'Dialog' interface. ########################################################################### # fixme: Ideally, this should be passed in; this topic ID belongs to the # Enlib help project/plug-in. help_id = 'enlib|HID_Quality_Agent_Dlg' def _create_dialog_area(self, parent): """ Creates the main content of the dialog. """ import wx parent.SetSizeHints(minW=300, minH=575) # Add the main panel sizer = wx.BoxSizer(wx.VERTICAL) panel = wx.Panel(parent, -1) panel.SetSizer(sizer) panel.SetAutoLayout(True) # Add a descriptive label at the top ... label = wx.StaticText(panel, -1, "Send a comment or bug report ...") sizer.Add(label, 0, wx.ALL, border=5) # Add the stack trace view ... error_panel = self._create_error_panel(panel) sizer.Add(error_panel, 1, wx.ALL|wx.EXPAND|wx.CLIP_CHILDREN, border=5) # Update the layout: sizer.Fit(panel) # Add the error report view ... report_panel = self._create_report_panel(panel) sizer.Add(report_panel, 2, wx.ALL|wx.EXPAND|wx.CLIP_CHILDREN, border=5) # Update the layout: sizer.Fit(panel) return panel def _create_buttons(self, parent): """ Creates the buttons. """ import wx sizer = wx.BoxSizer(wx.HORIZONTAL) # 'Send' button. send = wx.Button(parent, wx.ID_OK, "Send") wx.EVT_BUTTON(parent, wx.ID_OK, self._on_send) sizer.Add(send) send.SetDefault() # 'Cancel' button. cancel = wx.Button(parent, wx.ID_CANCEL, "Cancel") wx.EVT_BUTTON(parent, wx.ID_CANCEL, self._wx_on_cancel) sizer.Add(cancel, 0, wx.LEFT, 10) # 'Help' button. if len(self.help_id) > 0: help = wx.Button(parent, wx.ID_HELP, "Help") wx.EVT_BUTTON(parent, wx.ID_HELP, self._wx_on_help) sizer.Add(help, 0, wx.LEFT, 10) return sizer def _on_help(self, event): """Called when the 'Help' button is pressed. """ hp = self.service.application.get_service('enthought.help.IHelp') hp.library.show_topic(self.help_id) return ### Utility methods ####################################################### def _create_error_panel(self, parent): import wx box = wx.StaticBox(parent, -1, "Message:") sizer = wx.StaticBoxSizer(box, wx.VERTICAL) # Print the stack trace label2 = wx.StaticText(parent, -1,"The following information will be included in the report:") sizer.Add(label2, 0, wx.LEFT|wx.TOP|wx.BOTTOM|wx.CLIP_CHILDREN, border=5) details = wx.TextCtrl(parent, -1, self.msg, size=(-1,75), style=wx.TE_MULTILINE | wx.TE_READONLY | wx.HSCROLL | wx.VSCROLL | wx.TE_RICH2 | wx.CLIP_CHILDREN) details.SetSizeHints(minW=-1, minH=75) # Set the font to not be proportional font = wx.Font(12, wx.MODERN, wx.NORMAL, wx.NORMAL) details.SetStyle(0, len(self.msg), wx.TextAttr(font=font)) sizer.Add(details, 1, wx.EXPAND|wx.ALL|wx.CLIP_CHILDREN, 5) return sizer def _create_report_panel(self, parent): import wx box = wx.StaticBox(parent, -1, "Report Information:") sizer = wx.StaticBoxSizer(box, wx.VERTICAL) # Add email info ... sizer.Add(self._create_email_info(parent), 0, wx.ALL|wx.EXPAND, 5) # Add priority combo: sizer.Add(self._create_priority_combo(parent), 0, wx.ALL|wx.RIGHT, 5) # Extra comments from the user: label3 = wx.StaticText(parent, -1, "Additional Comments:") sizer.Add(label3, 0, wx.LEFT|wx.TOP|wx.BOTTOM|wx.CLIP_CHILDREN, 5) comments_field = wx.TextCtrl(parent, -1, self.comments, size=(-1,75), style=wx.TE_MULTILINE | wx.TE_RICH2 | wx.CLIP_CHILDREN) comments_field.SetSizeHints(minW=-1, minH=75) font = wx.Font(12, wx.MODERN, wx.NORMAL, wx.NORMAL) comments_field.SetStyle(0, len(self.comments), wx.TextAttr(font=font)) sizer.Add(comments_field, 1, wx.ALL|wx.EXPAND|wx.CLIP_CHILDREN, 5) wx.EVT_TEXT(parent, comments_field.GetId(), self._on_comments) # Include the project combobox? if len(self.service.mail_files) > 0: sizer.Add(self._create_project_upload(parent), 0, wx.ALL, border=5) return sizer def _create_email_info(self, parent): import wx # Layout setup .. sizer = wx.FlexGridSizer(5,2,10,10) sizer.AddGrowableCol(1) title_label = wx.StaticText(parent, -1, "Subject:") sizer.Add(title_label , 0, wx.ALL|wx.ALIGN_RIGHT) title_field = wx.TextCtrl(parent, -1, self.subject, wx.Point(-1,-1)) sizer.Add(title_field, 1, wx.EXPAND|wx.ALL|wx.ALIGN_RIGHT|wx.CLIP_CHILDREN) wx.EVT_TEXT(parent, title_field.GetId(), self._on_subject) to_label = wx.StaticText(parent, -1, "To:") sizer.Add(to_label , 0, wx.ALL|wx.ALIGN_RIGHT) to_field = wx.TextCtrl(parent, -1, self.to_address) sizer.Add(to_field, 1, wx.EXPAND|wx.ALL|wx.ALIGN_RIGHT|wx.CLIP_CHILDREN) wx.EVT_TEXT(parent, to_field.GetId(), self._on_to) cc_label = wx.StaticText(parent, -1, "Cc:") sizer.Add(cc_label, 0, wx.ALL|wx.ALIGN_RIGHT) cc_field = wx.TextCtrl(parent, -1, "") sizer.Add(cc_field, 1, wx.EXPAND|wx.ALL|wx.ALIGN_RIGHT|wx.CLIP_CHILDREN) wx.EVT_TEXT(parent, cc_field.GetId(), self._on_cc) from_label = wx.StaticText(parent, -1, "From:") sizer.Add(from_label, 0, wx.ALL|wx.ALIGN_RIGHT) from_field = wx.TextCtrl(parent, -1, self.from_address) sizer.Add(from_field, 1, wx.EXPAND|wx.ALL|wx.ALIGN_RIGHT|wx.CLIP_CHILDREN) wx.EVT_TEXT(parent, from_field.GetId(), self._on_from) smtp_label = wx.StaticText(parent, -1, "SMTP Server:") sizer.Add(smtp_label, 0, wx.ALL|wx.ALIGN_RIGHT) smtp_server_field = wx.TextCtrl(parent, -1, self.smtp_server) sizer.Add(smtp_server_field, 1, wx.EXPAND|wx.ALL|wx.ALIGN_RIGHT|wx.CLIP_CHILDREN) wx.EVT_TEXT(parent, smtp_server_field.GetId(), self._on_smtp_server) return sizer def _create_priority_combo(self, parent): import wx sizer = wx.BoxSizer(wx.HORIZONTAL) label = wx.StaticText(parent, -1, "How critical is this issue?") sizer.Add(label, 0, wx.ALL, border=0) cb = wx.ComboBox(parent, -1, self.priority, wx.Point(90, 50), wx.Size(95, -1), priority_levels, wx.CB_READONLY) sizer.Add(cb, 1, wx.EXPAND|wx.LEFT|wx.CLIP_CHILDREN, border=10) wx.EVT_COMBOBOX(parent, cb.GetId(), self._on_priority) return sizer def _create_project_upload(self, parent): import wx id = wx.NewId() cb = wx.CheckBox(parent, id, "Include Workspace Files (will increase email size) ", wx.Point(65, 80), wx.Size(-1, 20), wx.NO_BORDER) wx.EVT_CHECKBOX(parent, id, self._on_project) return cb ## UI Listeners ########################################################### def _on_subject(self, event): self.subject = event.GetEventObject().GetValue() def _on_to(self, event): self.to_address = event.GetEventObject().GetValue() def _on_cc(self, event): self.cc_address = event.GetEventObject().GetValue() def _on_from(self, event): self.from_address = event.GetEventObject().GetValue() def _on_smtp_server(self, event): self.smtp_server = event.GetEventObject().GetValue() def _on_priority(self, event): self.priority = event.GetEventObject().GetStringSelection() def _on_comments(self, event): self.comments = event.GetEventObject().GetValue() def _on_project(self, event): self.include_userdata = event.Checked() cb = event.GetEventObject() if event.Checked(): cb.SetLabel("Include Workspace Files (approx. %.2f MBytes)" % self._compute_project_size()) else: cb.SetLabel("Include Workspace Files (will increase email size)") return def _on_send(self, event): import wx # Disable the Send button while we go through the possibly # time-consuming email-sending process. button = event.GetEventObject() button.Enable(0) fromaddr, toaddrs, ccaddrs = self._create_email_addresses() message = self._create_email(fromaddr, toaddrs, ccaddrs) self.service.send_bug_report(self.smtp_server, fromaddr, toaddrs, ccaddrs, message) # save the user's preferences self.service.preferences.smtp_server = self.smtp_server self.service.preferences.to_address = self.to_address self.service.preferences.from_address = self.from_address # finally we close the dialog self._wx_on_ok(event) return ## Private ################################################################ def _create_email_addresses(self): # utility function map addresses from ui into the standard format # FIXME: We should use standard To: header parsing instead of this ad # hoc whitespace-only approach. fromaddr = self.from_address if "" == fromaddr.strip(): fromaddr = "anonymous" toaddrs = self.to_address.split() ccaddrs = self.cc_address.split() return fromaddr, toaddrs, ccaddrs def _compute_project_size(self): # determine size of email in MBytes fromaddr, toaddrs, ccaddrs = self._create_email_addresses() message = self._create_email(fromaddr, toaddrs, ccaddrs) return len(message.as_string()) / (2.0**20) def _create_email(self, fromaddr, toaddrs, ccaddrs): return self.service.create_email_message( fromaddr, toaddrs, ccaddrs, self.subject, self.priority, self.include_userdata, self.msg, self.comments, ) def _to_address_default(self): return self.service.preferences.to_address def _from_address_default(self): return self.service.preferences.from_address def _smtp_server_default(self): return self.service.preferences.smtp_server ####### EOF ############################################################# EnthoughtBase-3.1.0/enthought/logger/__init__.py0000644000175100001440000000050611517627321022637 0ustar ischnellusers00000000000000#----------------------------------------------------------------------------- # # Copyright (c) 2005 by Enthought, Inc. # All rights reserved. # #----------------------------------------------------------------------------- """ Convenience functions for creating logging handlers. Part of the EnthoughtBase project. """EnthoughtBase-3.1.0/enthought/logger/log_point.py0000644000175100001440000000315111517627321023071 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ """ Prints a stack trace every time it is called but does not halt execution of the application. Copied from Uche Ogbuji's blog """ # Standard library imports. import inspect from cStringIO import StringIO def log_point(msg='\n'): stack = inspect.stack() # get rid of logPoint's part of the stack: stack = stack[1:] stack.reverse() output = StringIO() if msg: output.write(str(msg) + '\n') for stackLine in stack: frame, filename, line, funcname, lines, unknown = stackLine if filename.endswith('/unittest.py'): # unittest.py code is a boring part of the traceback continue if filename.startswith('./'): filename = filename[2:] output.write('%s:%s in %s:\n' % (filename, line, funcname)) if lines: output.write(' %s\n' % ''.join(lines)[:-1]) s = output.getvalue() return s ## EOF ################################################################## EnthoughtBase-3.1.0/enthought/logger/null_handler.py0000644000175100001440000000263211517627321023551 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ """ A null log handler. """ # Standard library imports. import logging class NullHandler(logging.Handler): """ A null log handler. This is a quick hack so that we can start to refactor the 'logger' module since it used to add actual handlers at module load time. Now we only add this handler so that people using just the ETS library and not one of our applications won't see the warning about 'no handlers'. """ ########################################################################### # 'Handler' interface. ########################################################################### def emit(self, record): """ Emits a log record. """ pass #### EOF ###################################################################### EnthoughtBase-3.1.0/enthought/etsconfig/0000755000175100001440000000000011520337551021224 5ustar ischnellusers00000000000000EnthoughtBase-3.1.0/enthought/etsconfig/tests/0000755000175100001440000000000011520337551022366 5ustar ischnellusers00000000000000EnthoughtBase-3.1.0/enthought/etsconfig/tests/etsconfig_test_case.py0000644000175100001440000001221411517627321026756 0ustar ischnellusers00000000000000""" Tests the 'ETSConfig' configuration object. """ # Standard library imports. import os, time, unittest # Enthought library imports. from enthought.etsconfig.api import ETSConfig class ETSConfigTestCase(unittest.TestCase): """ Tests the 'ETSConfig' configuration object. """ ########################################################################### # 'TestCase' interface. ########################################################################### #### public methods ####################################################### def setUp(self): """ Prepares the test fixture before each test method is called. """ return def tearDown(self): """ Called immediately after each test method has been called. """ return ########################################################################### # 'ETSConfigTestCase' interface. ########################################################################### #### public methods ####################################################### def test_application_data(self): """ application data """ dirname = ETSConfig.application_data self.assertEqual(os.path.exists(dirname), True) self.assertEqual(os.path.isdir(dirname), True) return def test_set_application_data(self): """ set application data """ old = ETSConfig.application_data ETSConfig.application_data = 'foo' self.assertEqual('foo', ETSConfig.application_data) ETSConfig.application_data = old self.assertEqual(old, ETSConfig.application_data) return def test_application_data_is_idempotent(self): """ application data is idempotent """ # Just do the previous test again! self.test_application_data() return def test_write_to_application_data_directory(self): """ write to application data directory """ ETSConfig.company = 'Blah' dirname = ETSConfig.application_data path = os.path.join(dirname, 'dummy.txt') data = str(time.time()) f = file(path, 'w') f.write(data) f.close() self.assertEqual(os.path.exists(path), True) f = file(path) result = f.read() f.close() os.remove(path) self.assertEqual(data, result) return def test_default_company(self): """ default company """ self.assertEqual(ETSConfig.company, 'Enthought') return def test_set_company(self): """ set company """ old = ETSConfig.company ETSConfig.company = 'foo' self.assertEqual('foo', ETSConfig.company) ETSConfig.company = old self.assertEqual(old, ETSConfig.company) return def _test_default_application_home(self): """ application home """ # This test is only valid when run with the 'main' at the end of this # file: "python app_dat_locator_test_case.py", in which case the # app_name will be the directory this file is in ('tests'). app_home = ETSConfig.application_home (dirname, app_name) = os.path.split(app_home) self.assertEqual(dirname, ETSConfig.application_data) self.assertEqual(app_name, 'tests') def test_user_data(self): """ user data """ dirname = ETSConfig.user_data self.assertEqual(os.path.exists(dirname), True) self.assertEqual(os.path.isdir(dirname), True) return def test_set_user_data(self): """ set user data """ old = ETSConfig.user_data ETSConfig.user_data = 'foo' self.assertEqual('foo', ETSConfig.user_data) ETSConfig.user_data = old self.assertEqual(old, ETSConfig.user_data) return def test_user_data_is_idempotent(self): """ user data is idempotent """ # Just do the previous test again! self.test_user_data() return def test_write_to_user_data_directory(self): """ write to user data directory """ ETSConfig.company = 'Blah' dirname = ETSConfig.user_data path = os.path.join(dirname, 'dummy.txt') data = str(time.time()) f = file(path, 'w') f.write(data) f.close() self.assertEqual(os.path.exists(path), True) f = file(path) result = f.read() f.close() os.remove(path) self.assertEqual(data, result) return # For running as an individual set of tests. if __name__ == '__main__': # Add the non-default test of application_home...non-default because it must # be run using this module as a script to be valid. suite = unittest.TestLoader().loadTestsFromTestCase(ETSConfigTestCase) suite.addTest(ETSConfigTestCase('_test_default_application_home')) unittest.TextTestRunner(verbosity=2).run(suite) #### EOF ###################################################################### EnthoughtBase-3.1.0/enthought/etsconfig/api.py0000644000175100001440000000004011517627321022344 0ustar ischnellusers00000000000000from etsconfig import ETSConfig EnthoughtBase-3.1.0/enthought/etsconfig/etsconfig.py0000644000175100001440000003537311517627321023575 0ustar ischnellusers00000000000000""" Enthought Tool Suite configuration information. """ # Standard library imports. import sys import os from os import path class ETSConfig(object): """ Enthought Tool Suite configuration information. This class should not use ANY other package in the tool suite so that it will always work no matter which other packages are present. """ ########################################################################### # 'object' interface. ########################################################################### #### operator methods ##################################################### def __init__(self): """ Constructor. Note that this constructor can only ever be called from within this module, since we don't expose the class. """ # Shadow attributes for properties. self._application_data = None self._application_home = None self._company = None self._toolkit = None self._kiva_backend = None self._user_data = None return ########################################################################### # 'ETSConfig' interface. ########################################################################### #### properties ########################################################### def get_application_data(self, create=False): """ Return the application data directory path. **Parameters** create: create the corresponding directory or not **Notes** This is a directory that applications and packages can safely write non-user accessible data to i.e. configuration information, preferences etc. Do not put anything in here that the user might want to navigate to e.g. projects, user data files etc. The actual location differs between operating systems. """ if self._application_data is None: self._application_data = \ self._initialize_application_data(create=create) return self._application_data def _get_application_data(self): """ Property getter, see get_application_data's docstring. """ return self.get_application_data(create=True) def _set_application_data(self, application_data): """ Property setter. """ self._application_data = application_data return def get_application_home(self, create=False): """ Return the application home directory path. **Parameters** create: create the corresponding directory or not **Notes** This is a directory named after the current, running application that imported this module that applications and packages can safely write non-user accessible data to i.e. configuration information, preferences etc. It is a sub-directory of self.application_data, named after the directory that contains the "main" python script that started the process. For example, if application foo is started with a script named "run.py" in a directory named "foo", then the application home would be: /foo, regardless of if it was launched with "python /run.py" or "cd ; python run.py" This is useful for library modules used in apps that need to store state, preferences, etc. for the specific app only, and not for all apps which use that library module. If the library module uses ETSConfig.application_home, they can store prefs for the app all in one place and do not need to know the details of where each app might reside. Do not put anything in here that the user might want to navigate to e.g. projects, user home files etc. The actual location differs between operating systems. """ if self._application_home is None: self._application_home = path.join( self.get_application_data(create=create), self._get_application_dirname()) return self._application_home application_data = property(_get_application_data, _set_application_data) def _get_application_home(self): """ Property getter, see get_application_home's docstring. """ return self.get_application_home(create=True) def _set_application_home(self, application_home): """ Property setter. """ self._application_home = application_home return application_home = property(_get_application_home, _set_application_home) def _get_company(self): """ Property getter. """ if self._company is None: self._company = self._initialize_company() return self._company def _set_company(self, company): """ Property setter for the company name. """ self._company = company return company = property(_get_company, _set_company) def _get_toolkit(self): """ Property getter for the GUI toolkit. The value returned is, in order of preference: the value set by the application; the value passed on the command line using the '-toolkit' option; the value specified by the 'ETS_TOOLKIT' environment variable; otherwise the empty string. """ if self._toolkit is None: self._toolkit = self._initialize_toolkit() return self._toolkit.split('.')[0] def _set_toolkit(self, toolkit): """ Property setter for the GUI toolkit. The toolkit can be set more than once, but only if it is the same one each time. An application that is written for a particular toolkit can explicitly set it before any other module that gets the value is imported. """ if self._toolkit and self._toolkit != toolkit: raise ValueError, "cannot set toolkit to %s because it has "\ "already been set to %s" % (toolkit, self._toolkit) self._toolkit = toolkit return toolkit = property(_get_toolkit, _set_toolkit) def _get_enable_toolkit(self): """ Deprecated: This property is no longer used. Property getter for the Enable backend. The value returned is, in order of preference: the value set by the application; the value passed on the command line using the '-toolkit' option; the value specified by the 'ENABLE_TOOLKIT' environment variable; otherwise the empty string. """ from warnings import warn warn('Use of the enable_toolkit attribute is deprecated.') return self.toolkit def _set_enable_toolkit(self, toolkit): """ Deprecated. Property setter for the Enable toolkit. The toolkit can be set more than once, but only if it is the same one each time. An application that is written for a particular toolkit can explicitly set it before any other module that gets the value is imported. """ from warnings import warn warn('Use of the enable_toolkit attribute is deprecated.') return enable_toolkit = property(_get_enable_toolkit, _set_enable_toolkit) def _get_kiva_backend(self): """ Property getter for the Kiva backend. The value returned is dependent on the value of the toolkit property. If toolkit specifies a kiva backend using the extended syntax: [.] then the value of the property will be whatever was specified. Otherwise the value will be a reasonable default for the given enable backend. """ if self._toolkit is None: raise AttributeError, "The kiva_backend attribute is dependent on toolkit, which has not been set." if self._kiva_backend is None: try: self._kiva_backend = self._toolkit.split('.')[1] except IndexError: # Pick a reasonable default based on the toolkit if self.toolkit == "wx": self._kiva_backend = "quartz" if sys.platform == "darwin" else "image" elif self.toolkit == "qt4": self._kiva_backend = "image" elif self.toolkit == "pyglet": self._kiva_backend = "gl" else: self._kiva_backend = "image" return self._kiva_backend kiva_backend = property(_get_kiva_backend) def _get_user_data(self): """ Property getter. This is a directory that users can safely write user accessible data to i.e. user-defined functions, edited functions, etc. The actual location differs between operating systems. """ if self._user_data is None: self._user_data = self._initialize_user_data() return self._user_data def _set_user_data(self, user_data): """ Property setter. """ self._user_data = user_data return user_data = property(_get_user_data, _set_user_data) #### private methods ##################################################### # fixme: In future, these methods could allow the properties to be set # via the (as yet non-existent) preference/configuration mechanism. This # would allow configuration via (in order of precedence):- # # - a configuration file # - environment variables # - the command line def _get_application_dirname(self): """ Return the name of the directory (not a path) that the "main" Python script which started this process resides in, or "" if it could not be determined or is not appropriate. For example, if the script that started the current process was named "run.py" in a directory named "foo", and was launched with "python run.py", the name "foo" would be returned (this assumes the directory name is the name of the app, which seems to be as good of an assumption as any). """ dirname = "" main_mod = sys.modules.get('__main__', None) if main_mod is not None: if hasattr(main_mod, '__file__'): main_mod_file = path.abspath(main_mod.__file__) dirname = path.basename(path.dirname(main_mod_file)) return dirname def _initialize_application_data(self, create=True): """ Initializes the (default) application data directory. """ if sys.platform == 'win32': environment_variable = 'APPDATA' directory_name = self.company else: environment_variable = 'HOME' directory_name = '.' + self.company.lower() # Lookup the environment variable. parent_directory = os.environ.get(environment_variable, None) if parent_directory is None or parent_directory == '/root': import tempfile from warnings import warn parent_directory = tempfile.gettempdir() user = os.environ.get('USER', None) if user is not None: directory_name += "_%s" % user warn('Environment variable "%s" not set, setting home directory to %s' % \ (environment_variable, parent_directory)) application_data = os.path.join(parent_directory, directory_name) if create: # If a file already exists with this name then make sure that it is # a directory! if os.path.exists(application_data): if not os.path.isdir(application_data): raise ValueError('File "%s" already exists' % application_data) # Otherwise, create the directory. else: os.makedirs(application_data) return application_data def _initialize_company(self): """ Initializes the (default) company. """ return 'Enthought' def _initialize_toolkit(self): """ Initializes the toolkit. """ # We handle the command line option even though it doesn't have the # highest precedence because we always want to remove it from the # command line. if '-toolkit' in sys.argv: opt_idx = sys.argv.index('-toolkit') try: opt_toolkit = sys.argv[opt_idx + 1] except IndexError: raise ValueError, "the -toolkit command line argument must be followed by a toolkit name" # Remove the option. del sys.argv[opt_idx:opt_idx + 1] else: opt_toolkit = None if self._toolkit is not None: toolkit = self._toolkit elif opt_toolkit is not None: toolkit = opt_toolkit else: toolkit = os.environ.get('ETS_TOOLKIT', '') return toolkit def _initialize_user_data(self): """ Initializes the (default) user data directory. """ # We check what the os.path.expanduser returns parent_directory = os.path.expanduser('~') directory_name = self.company if sys.platform == 'win32': # Check if the usr_dir is C:\\John Doe\\Documents and Settings. # If yes, then we should modify the usr_dir to be 'My Documents'. # If no, then the user must have modified the os.environ # variables and the directory chosen is a desirable one. desired_dir = os.path.join(parent_directory, 'My Documents') if os.path.exists(desired_dir): parent_directory = desired_dir else: directory_name = directory_name.lower() # The final directory. usr_dir = os.path.join(parent_directory, directory_name) # If a file already exists with this name then make sure that it is # a directory! if os.path.exists(usr_dir): if not os.path.isdir(usr_dir): raise ValueError('File "%s" already exists' % usr_dir) # Otherwise, create the directory. else: os.makedirs(usr_dir) return usr_dir # We very purposefully only have one object and do not export the class. We # could have just made everything class methods, but that always seems a bit # gorpy, especially with properties etc. ETSConfig = ETSConfig() #### EOF ###################################################################### EnthoughtBase-3.1.0/enthought/etsconfig/__init__.py0000644000175100001440000000053311517627321023341 0ustar ischnellusers00000000000000#----------------------------------------------------------------------------- # # Copyright (c) 2007 by Enthought, Inc. # All rights reserved. # #----------------------------------------------------------------------------- """ Supports sharing settings across projects or programs on the same system. Part of the EnthoughtBase project. """EnthoughtBase-3.1.0/enthought/qt/0000755000175100001440000000000011520337551017667 5ustar ischnellusers00000000000000EnthoughtBase-3.1.0/enthought/qt/QtCore.py0000644000175100001440000000064011520333407021432 0ustar ischnellusers00000000000000import os qt_api = os.environ.get('QT_API', 'pyqt') if qt_api == 'pyqt': from PyQt4.QtCore import * def QVariant(obj=None): import PyQt4.QtCore return PyQt4.QtCore.QVariant(obj) from PyQt4.QtCore import pyqtSignal as Signal from PyQt4.Qt import QCoreApplication from PyQt4.Qt import Qt else: from PySide.QtCore import * def QVariant(obj=None): return obj EnthoughtBase-3.1.0/enthought/qt/QtGui.py0000644000175100001440000000030611520333407021265 0ustar ischnellusers00000000000000import os qt_api = os.environ.get('QT_API', 'pyqt') if qt_api == 'pyqt': from PyQt4.Qt import QKeySequence, QTextCursor from PyQt4.QtGui import * else: from PySide.QtGui import * EnthoughtBase-3.1.0/enthought/qt/QtSvg.py0000644000175100001440000000022311520333407021276 0ustar ischnellusers00000000000000import os qt_api = os.environ.get('QT_API', 'pyqt') if qt_api == 'pyqt': from PyQt4.QtSvg import * else: from PySide.QtSvg import * EnthoughtBase-3.1.0/enthought/qt/__init__.py0000644000175100001440000000125111520325553021776 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2010, Enthought Inc # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # # Author: Enthought Inc # Description: Qt API selector. Can be used to switch between pyQt and PySide #------------------------------------------------------------------------------ import os from enthought.etsconfig.api import ETSConfig qt_api = os.environ.get('QT_API', 'pyqt') if ETSConfig.toolkit == 'qt4': if qt_api == 'pyqt': import sip sip.setapi('QString', 2) else: print "---- using PySide ----"EnthoughtBase-3.1.0/enthought/qt/QtOpenGL.py0000644000175100001440000000023111520333407021662 0ustar ischnellusers00000000000000import os qt_api = os.environ.get('QT_API', 'pyqt') if qt_api == 'pyqt': from PyQt4.QtOpenGL import * else: from PySide.QtOpenGL import * EnthoughtBase-3.1.0/enthought/qt/QtWebKit.py0000644000175100001440000000023111520333407021723 0ustar ischnellusers00000000000000import os qt_api = os.environ.get('QT_API', 'pyqt') if qt_api == 'pyqt': from PyQt4.QtWebKit import * else: from PySide.QtWebKit import * EnthoughtBase-3.1.0/enthought/util/0000755000175100001440000000000011520337551020220 5ustar ischnellusers00000000000000EnthoughtBase-3.1.0/enthought/util/ring_buffer.py0000644000175100001440000000315611517627321023072 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ """ Copied from Python Cookbook. """ class RingBuffer: def __init__(self,size_max): self.max = size_max self.data = [] def append(self,x): """append an element at the end of the buffer""" self.data.append(x) if len(self.data) == self.max: self.cur = 0 self.__class__ = RingBufferFull def get(self): """ return a list of elements from the oldest to the newest""" return self.data class RingBufferFull: def __init__(self,n): raise Exception("you should use RingBuffer") def append(self,x): self.data[self.cur]=x self.cur=(self.cur+1) % self.max def get(self): return self.data[self.cur:]+self.data[:self.cur] # sample of use """x=RingBuffer(5) x.append(1); x.append(2); x.append(3); x.append(4) print x.__class__,x.get() x.append(5) print x.__class__,x.get() x.append(6) print x.data,x.get() x.append(7); x.append(8); x.append(9); x.append(10) print x.data,x.get()""" EnthoughtBase-3.1.0/enthought/util/dp.py0000644000175100001440000000535211517627321021205 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ from numpy import arange, sqrt, argmax, zeros, nonzero, take, absolute def decimate(x, y, tolerance): """ Returns decimated x and y arrays. This is Douglas and Peucker's algorithm rewritten to use Numeric arrays. Tolerance is usually determined by determining the size that a single pixel represents in the units of x and y. Compression ratios for large seismic and well data sets can be significant. """ # Todo - we could improve the aesthetics by scaling (normalizing) the x and # y arrays. eg in a well the curve varies by +/- 1 and the depths by 0,10000 # This affects the accuracy of the representation in sloping regions. keep = zeros(len(x)) _decimate(x, y, keep, 0, len(x) - 1, tolerance) ids = nonzero(keep) return take(x,ids), take(y, ids) def _decimate(x, y, keep, si, ei, tolerance): keep[si] = 1 keep[ei] = 1 # check if the two data points are adjacent if ei < (si + 2): return # now find the perp distance to each point x0 = x[si+1:ei] y0 = y[si+1:ei] xei_minux_xsi = x[ei] - x[si] yei_minux_ysi = y[ei] - y[si] top = absolute( xei_minux_xsi * (y[si] - y0) - (x[si] - x0) * yei_minux_ysi ) # The algorithm currently does an expensive sqrt operation which is not # strictly necessary except that it makes the tolerance correspond to a real # world quantity. bot = sqrt( xei_minux_xsi*xei_minux_xsi + yei_minux_ysi*yei_minux_ysi) dist = top / bot # find the point that is furthest from line between points si and ei index = argmax(dist) if dist[index] > tolerance: abs_index = index + (si + 1) keep[abs_index] = 1 _decimate(x, y, keep, si, abs_index, tolerance) _decimate(x, y, keep, abs_index, ei, tolerance) return if __name__ == "__main__": from numpy.random import random x = arange(0,4,0.1) y = zeros(len(x)) y = random(len(x)) tolerance = .1 print tolerance nx,ny = decimate(x, y, tolerance) print 'before ', len(x) print 'after ', len(nx) EnthoughtBase-3.1.0/enthought/util/home_directory.py0000644000175100001440000000263211517627321023614 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, 2006 by Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ import os def get_home_directory(): """ Determine the user's home directory.""" # 'HOME' should work on most Unixes, and 'USERPROFILE' works on at # least Windows XP ;^) # # FIXME: Is this really better than the following?? # path = os.path.expanduser('~') # The above seems to work on both Windows and Unixes though the docs # indicate it might not work as well on Macs. for name in ['HOME', 'USERPROFILE']: if os.environ.has_key(name): # Make sure that the path ends with a path seperator. path = os.environ[name] if path[-1] != os.path.sep: path += os.path.sep break # If all else fails, the current directory will do. else: path = '' return pathEnthoughtBase-3.1.0/enthought/util/random_state.py0000644000175100001440000000574011517627321023263 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ """ The two classes here help keep up with the current "state" of the random number generators in scipy.stats and random. They can be used to save the current state of the random number generators to be used in the future to ensure identical results between calls. The RandomStateManager works as a stack with save_state, set_state and restore_state methods that allow you to keep a stack of states available. A common usage is as follows: >>> # save the current state in a variable named "old_state" >>> old_state = RandomState() Perform some stochastic calculation... >>> # Now if you want to have stochastic_calculation() return identical >>> # results without disrupting other calculations that use random values >>> # do the following: >>> rsm = RandomStateManager() >>> rsm.save_state() >>> rsm.set_state(old_state) Perform some stochastic calculation... >>> rsm.restore_state() Note that these routines currently only support the state of random and scipy.stats. If you use other random number generators, their states will not be managed correctly. """ import random from numpy.random import get_state as get_seed from numpy.random import set_state as set_seed class RandomState: def __init__(self): self.update() def update(self): self.stats_seed = get_seed() self.random_state = random.getstate() class RandomStateManager: # todo - does it make any sense to use a stack structure? # we currently store the seeds elsewhere anyway so the stack only # ever has one element in it. # def __init__(self): self.state_stack = [] def save_state(self): current_state = RandomState() self.state_stack.append(current_state) def set_state(self, random_state): seed = random_state.stats_seed set_seed(seed) state = random_state.random_state random.setstate(state) def restore_state(self): try: previous_state = self.state_stack.pop(-1) self.set_state(previous_state) except: raise IndexError("trying to call restore_state without matching" " call to save_state") if __name__ == '__main__': import doctest doctest.testmod() EnthoughtBase-3.1.0/enthought/util/synchronized.py0000644000175100001440000000145411517627321023320 0ustar ischnellusers00000000000000""" A decorator for making methods thread-safe via an object-scope lock. """ def synchronized(lock_attribute='_lk'): """ A factory for decorators for making methods thread-safe. """ def decorator(fn): """ A decorator for making methods thread-safe. """ def wrapper(self, *args, **kw): """ The method/function wrapper. """ lock = getattr(self, lock_attribute) try: lock.acquire() result = fn(self, *args, **kw) finally: lock.release() return result wrapper.__doc__ = fn.__doc__ wrapper.__name__ = fn.__name__ return wrapper return decorator #### EOF ###################################################################### EnthoughtBase-3.1.0/enthought/util/clean_strings.py0000644000175100001440000000521611517627321023434 0ustar ischnellusers00000000000000#----------------------------------------------------------------------------- # # Copyright (c) 2006 by Enthought, Inc. # All rights reserved. # #----------------------------------------------------------------------------- """ Provides functions that munge strings to avoid characters that would be problematic in certain situations. """ # Standard library imports. import copy import datetime import keyword import re def clean_filename(name): """ Munge a string to avoid characters that might be problematic as a filename in some filesystems. """ # The only acceptable characters are alphanumeric (in the current locale) # plus a period and dash. wordparts = re.split('[^\w\.\-]+', name) # Filter out empty strings at the beginning or end of the list. wordparts = filter(None, wordparts) # Make sure this is an ASCII-encoded string, not a Unicode string. filename = '_'.join(wordparts).encode('ascii') return filename def clean_timestamp(dt=None, microseconds=False): """ Return a timestamp that has been cleansed of characters that might cause problems in filenames, namely colons. If no datetime object is provided, then uses the current time. Description ----------- The timestamp is in ISO-8601 format with the following exceptions: * Colons ':' are replaced by underscores '_'. * Microseconds are not displayed if the 'microseconds' parameter is False. Parameters ---------- dt : None or datetime.datetime object If None, then the current time is used. microseconds : bool Display microseconds or not. Returns ------- A string timestamp. """ if dt is None: dt = datetime.datetime.now() else: # Operate on a copy. dt = copy.copy(dt) if not microseconds: # The microseconds are largely uninformative but annoying. dt = dt.replace(microsecond=0) stamp = dt.isoformat().replace(':', '_') return stamp def python_name(name): """ Attempt to make a valid Python identifier out of a name. """ if len(name) > 0: # Replace spaces with underscores. name = name.replace(' ', '_').lower() # If the name is a Python keyword then prefix it with an # underscore. if keyword.iskeyword(name): name = '_' + name # If the name starts with a digit then prefix it with an # underscore. if name[0].isdigit(): name = '_' + name return name ### EOF ###################################################################### EnthoughtBase-3.1.0/enthought/util/guisupport.py0000644000175100001440000001400311520325553023010 0ustar ischnellusers00000000000000""" Support for creating GUI apps and starting event loops. IPython's GUI integration allows interative plotting and GUI usage in IPython session. IPython has two different types of GUI integration: 1. The terminal based IPython supports GUI event loops through Python's PyOS_InputHook. PyOS_InputHook is a hook that Python calls periodically whenever raw_input is waiting for a user to type code. We implement GUI support in the terminal by setting PyOS_InputHook to a function that iterates the event loop for a short while. It is important to note that in this situation, the real GUI event loop is NOT run in the normal manner, so you can't use the normal means to detect that it is running. 2. In the two process IPython kernel/frontend, the GUI event loop is run in the kernel. In this case, the event loop is run in the normal manner by calling the function or method of the GUI toolkit that starts the event loop. In addition to starting the GUI event loops in one of these two ways, IPython will *always* create an appropriate GUI application object when GUi integration is enabled. If you want your GUI apps to run in IPython you need to do two things: 1. Test to see if there is already an existing main application object. If there is, you should use it. If there is not an existing application object you should create one. 2. Test to see if the GUI event loop is running. If it is, you should not start it. If the event loop is not running you may start it. This module contains functions for each toolkit that perform these things in a consistent manner. Because of how PyOS_InputHook runs the event loop you cannot detect if the event loop is running using the traditional calls (such as ``wx.GetApp.IsMainLoopRunning()`` in wxPython). If PyOS_InputHook is set These methods will return a false negative. That is, they will say the event loop is not running, when is actually is. To work around this limitation we proposed the following informal protocol: * Whenever someone starts the event loop, they *must* set the ``_in_event_loop`` attribute of the main application object to ``True``. This should be done regardless of how the event loop is actually run. * Whenever someone stops the event loop, they *must* set the ``_in_event_loop`` attribute of the main application object to ``False``. * If you want to see if the event loop is running, you *must* use ``hasattr`` to see if ``_in_event_loop`` attribute has been set. If it is set, you *must* use its value. If it has not been set, you can query the toolkit in the normal manner. * If you want GUI support and no one else has created an application or started the event loop you *must* do this. We don't want projects to attempt to defer these things to someone else if they themselves need it. The functions below implement this logic for each GUI toolkit. If you need to create custom application subclasses, you will likely have to modify this code for your own purposes. This code can be copied into your own project so you don't have to depend on IPython. """ #----------------------------------------------------------------------------- # Copyright (C) 2008-2010 The IPython Development Team # # Distributed under the terms of the BSD License. The full license is in # the file COPYING, distributed as part of this software. #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- # Imports #----------------------------------------------------------------------------- # Prevent name conflict with local wx package. from __future__ import absolute_import #----------------------------------------------------------------------------- # wx #----------------------------------------------------------------------------- def get_app_wx(*args, **kwargs): """Create a new wx app or return an exiting one.""" import wx app = wx.GetApp() if app is None: if not kwargs.has_key('redirect'): kwargs['redirect'] = False app = wx.PySimpleApp(*args, **kwargs) return app def is_event_loop_running_wx(app=None): """Is the wx event loop running.""" if app is None: app = get_app_wx() if hasattr(app, '_in_event_loop'): return app._in_event_loop else: return app.IsMainLoopRunning() def start_event_loop_wx(app=None): """Start the wx event loop in a consistent manner.""" if app is None: app = get_app_wx() if not is_event_loop_running_wx(app): app._in_event_loop = True app.MainLoop() app._in_event_loop = False else: app._in_event_loop = True #----------------------------------------------------------------------------- # qt4 #----------------------------------------------------------------------------- def get_app_qt4(*args, **kwargs): """Create a new qt4 app or return an existing one.""" from enthought.qt import QtGui app = QtGui.QApplication.instance() if app is None: if not args: args = ([''],) app = QtGui.QApplication(*args, **kwargs) return app def is_event_loop_running_qt4(app=None): """Is the qt4 event loop running.""" if app is None: app = get_app_qt4(['']) if hasattr(app, '_in_event_loop'): return app._in_event_loop else: # Does qt4 provide a other way to detect this? return False def start_event_loop_qt4(app=None): """Start the qt4 event loop in a consistent manner.""" if app is None: app = get_app_qt4(['']) if not is_event_loop_running_qt4(app): app._in_event_loop = True app.exec_() app._in_event_loop = False else: app._in_event_loop = True #----------------------------------------------------------------------------- # Tk #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- # gtk #----------------------------------------------------------------------------- EnthoughtBase-3.1.0/enthought/util/resource.py0000644000175100001440000001660711517627321022436 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: Enthought, Inc. # Description: #------------------------------------------------------------------------------ """ Utility functions for managing and finding resources (ie. images/files etc). get_path : Returns the absolute path of a class or instance create_unique_name : Creates a name with a given prefix that is not in a given list of existing names. The separator between the prefix and the rest of the name can also be specified (default is a '_') find_resource: Given a setuptools project specification string ('MyProject>=2.1') and a partial path leading from the projects base directory to the desired resource, will return either an opened file object or, if specified, a full path to the resource. """ # Standard library imports. import inspect, os, sys from distutils.sysconfig import get_python_lib def get_path(path): """ Returns an absolute path for the specified path. 'path' can be a string, class or instance. """ if type(path) is not str: # Is this a class or an instance? if inspect.isclass(path): klass = path else: klass = path.__class__ # Get the name of the module that the class was loaded from. module_name = klass.__module__ # Look the module up. module = sys.modules[module_name] if module_name == '__main__': dirs = [os.path.dirname(sys.argv[0]), os.getcwd()] for d in dirs: if os.path.exists(d): path = d break else: # Get the path to the module. path = os.path.dirname(module.__file__) return path def create_unique_name(prefix, names, separator='_'): """ Creates a name starting with 'prefix' that is not in 'names'. """ i = 1 name = prefix while name in names: name = prefix + separator + str(i) i += 1 return name def find_resource(project, resource_path, alt_path=None, return_path=False): """ Returns a file object or file path pointing to the desired resource. Parameters ---------- project : string The name of the project to look for the resource in. Can be the name or a requirement string. Ex: 'MyProject', 'MyProject>1.0', 'MyProject==1.1' resource_path : string The path to the file from inside the package. If the file desired is MyProject/data/image.jpg, resource_path would be 'data/image.jpg'. alt_path : string The path to the resource relative to the location of the application's top-level script (the one with __main__). If this function is called in code/scripts/myscript.py and the resource is code/data/image.jpg, the alt_path would be '../data/image.jpg'. This path is only used if the resource cannot be found using setuptools. return_path : bool Determines whether the function should return a file object or a full path to the resource. Returns ------- file : file object or file path A file object containing the resource. If return_path is True, 'file' will be the full path to the resource. If the file is not found or cannot be opened, None is returned. Description ----------- This function will find a desired resource file and return an opened file object. The main method of finding the resource uses the pkg_resources resource_stream method, which searches your working set for the installed project specified and appends the resource_path given to the project path, leading it to the file. If setuptools is not installed or it cannot find/open the resource, find_resource will use the sys.path[0] to find the resource if alt_path is defined. """ try: # Get the image using the pkg_resources resource_stream module, which # will find the file by getting the Chaco install path and appending the # image path. This method works in all cases as long as setuptools is # installed. If setuptools isn't installed, the backup sys.path[0] # method is used. from pkg_resources import resource_stream, working_set, Requirement # Get a requirement for the project requirement = Requirement.parse(project) if return_path: dist = working_set.find(requirement) full_path = os.path.join(dist.location, resource_path) # If the path exists, return it if os.path.exists(full_path): return full_path else: raise else: return resource_stream(requirement, resource_path) except: # Setuptools was either not installed, or it failed to find the file. # First check to see if the package was installed using egginst by # looking for the file at: site-packages\\resouce_path full_path = os.path.join(get_python_lib(), resource_path) if os.path.exists(full_path): if return_path: return full_path else: return open(full_path, 'rb') # Get the image using sys.path[0], which is the directory that the # running script lives in. The path to the file is then constructed by # navigating from the script's location. This method only works if this # script is called directly from the command line using # 'python %SOMEPATH%/