easydev-0.9.35/ 0000775 0001750 0001750 00000000000 13131155451 014645 5 ustar cokelaer cokelaer 0000000 0000000 easydev-0.9.35/setup.cfg 0000664 0001750 0001750 00000000567 13131155451 016476 0 ustar cokelaer cokelaer 0000000 0000000 [sdist]
[egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0
[global]
[build_sphinx]
source_dir = doc/source
build_dir = doc/build
all_files = 1
[nosetests]
tests = test
with-coverage = 1
cover-package = easydev
verbosity = 2
logging-level = ERROR
attr = !skip,!notravis
[upload_docs]
upload_dir = doc/build/html/
[tool:pytest]
addopts = --durations=10 --verbose
easydev-0.9.35/MANIFEST.in 0000664 0001750 0001750 00000000151 13047372061 016404 0 ustar cokelaer cokelaer 0000000 0000000 include COPYING
include README.rst
recursive-include easydev/share *
include easydev/share/copybutton.js
easydev-0.9.35/PKG-INFO 0000664 0001750 0001750 00000005470 13131155451 015750 0 ustar cokelaer cokelaer 0000000 0000000 Metadata-Version: 1.1
Name: easydev
Version: 0.9.35
Summary: Common utilities to ease the development of Python packages
Home-page: ['http://packages.python.org/easydev/']
Author: Thomas Cokelaer
Author-email: cokelaer@ebi.ac.uk
License: new BSD
Download-URL: ['http://pypi.python.org/pypi/easydev']
Description: easydev
##########
.. image:: https://badge.fury.io/py/easydev.svg
:target: https://pypi.python.org/pypi/easydev
.. image:: https://secure.travis-ci.org/cokelaer/easydev.png
:target: http://travis-ci.org/cokelaer/easydev
.. image:: https://coveralls.io/repos/cokelaer/easydev/badge.svg?branch=master
:target: https://coveralls.io/r/cokelaer/easydev?branch=master
.. image:: https://landscape.io/github/cokelaer/easydev/master/landscape.png
:target: https://landscape.io/github/cokelaer/easydev/master
:documentation: http://easydev-python.readthedocs.io/en/latest/
:contributions: Please join https://github.com/cokelaer/easydev
:source: Please use https://github.com/cokelaer/easydev
:issues: Please use https://github.com/cokelaer/easydev/issues
:Python version supported: 2.6, 2.7, 3.3, 3.4, 3.5, 3.6
The `easydev `_ package
provides miscellaneous functions that are repeatidly used during
the development of Python packages. The goal is to help developers on
speeding up their own dev. It has been used also as an incubator for other
packages (e.g., http://pypi.python.org/pypi/colormap) and is stable.
.. warning:: I'm not pretending to provide universal and bug-free tools. The
tools provided may also change. However, **easydev** is used
in a few other packages such as
`bioservices `_,
`sequana `_ or
`GDSCTools `_ to give a few
examples.
Keywords: package,multisetup,logging,config,decorators,multigit,progressbar
Platform: Linux
Platform: Unix
Platform: MacOsX
Platform: Windows
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Topic :: Software Development :: Libraries :: Python Modules
easydev-0.9.35/setup.py 0000664 0001750 0001750 00000006566 13130515454 016376 0 ustar cokelaer cokelaer 0000000 0000000 # -*- coding: utf-8 -*-
__revision__ = "$Id$"
import sys
import os
from setuptools import setup, find_packages
import glob
_MAJOR = 0
_MINOR = 9
_MICRO = 35
version = '%d.%d.%d' % (_MAJOR, _MINOR, _MICRO)
release = '%d.%d' % (_MAJOR, _MINOR)
metainfo = {
'authors': {'Cokelaer':('Thomas Cokelaer','cokelaer@ebi.ac.uk')},
'version': version,
'license' : 'new BSD',
'download_url' : ['http://pypi.python.org/pypi/easydev'],
'url' : ["http://packages.python.org/easydev/"],
'description':'Common utilities to ease the development of Python packages' ,
'platforms' : ['Linux', 'Unix', 'MacOsX', 'Windows'],
'keywords' : ["package", "multisetup", "logging", "config", "decorators",
"multigit", "progressbar"],
'classifiers' : [
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'Intended Audience :: Science/Research',
'License :: OSI Approved',
'Operating System :: OS Independent',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Topic :: Software Development :: Libraries :: Python Modules'
]
}
setup(
name = 'easydev',
version = version,
maintainer = metainfo['authors']['Cokelaer'][0],
maintainer_email = metainfo['authors']['Cokelaer'][1],
author = metainfo['authors']['Cokelaer'][0],
author_email = metainfo['authors']['Cokelaer'][1],
long_description = open("README.rst").read(),
keywords = metainfo['keywords'],
description = metainfo['description'],
license = metainfo['license'],
platforms = metainfo['platforms'],
url = metainfo['url'],
download_url = metainfo['download_url'],
classifiers = metainfo['classifiers'],
# package installation
packages = ['easydev', "easydev.share" ],
# using pip, files inside ./easydev/share that are non Python will be
# included as well. For a distribution (using setup sdist), the MANIFEST
# must be updated accordingly
include_package_data = True,
package_data = {"easydev.share": [
"themes/standard/*html",
"themes/standard/static/*",
"themes/cno/*html",
"themes/cno/static/*",
"copybutton.js"]},
install_requires = ['colorama', 'pexpect'],
extras_require = {
'profiler': ["line_profiler_test"]
},
# somehow, the google_head.html is found in themes/standard and themese/cno
# directories thanks to the contents of datafiles variable but the ones from
# themes/standard directory are not copied inside the distribution ?
# using the MANIFEST.in solve the issue. However, data_files=datafiles is
# still required for python setup.py install or pip install to copy the
# share directory in the proper place. sure there will be a neat solution
# one day
zip_safe = False,
entry_points = {
'console_scripts': [
'easydev_buildPackage=easydev.package:buildPackage',
'browse=easydev.browser:main',
]
},
)
easydev-0.9.35/test/ 0000775 0001750 0001750 00000000000 13131155451 015624 5 ustar cokelaer cokelaer 0000000 0000000 easydev-0.9.35/test/test_cnolab_sphinx.py 0000664 0001750 0001750 00000000352 13052627511 022067 0 ustar cokelaer cokelaer 0000000 0000000 import easydev
def test_path():
p = easydev.get_path_sphinx_themes()
import os
dirs = os.listdir(p)
assert 'standard' in dirs
def test_sphinx_themes():
p = easydev.get_sphinx_themes()
assert 'standard' in p
easydev-0.9.35/test/test_misc.py 0000664 0001750 0001750 00000001074 13130521312 020162 0 ustar cokelaer cokelaer 0000000 0000000 from easydev.misc import get_home, cmd_exists, in_ipynb
#from mock import patch
import nose.tools
import subprocess
import os.path
def test_get_home():
get_home()
#with patch.object(os.path, 'expanduser') as mymock:
# mymock.side_effect = ImportError
# get_home()
def test_cmd_exists():
assert cmd_exists('dummy_dummy') == False
assert cmd_exists('ls') == True
#with patch.object(subprocess, 'call') as mymock:
# mymock.side_effect = Exception
# cmd_exists('ls')
def test_in_ipynb():
assert in_ipynb() == False
easydev-0.9.35/test/test_doc.py 0000664 0001750 0001750 00000000123 12655403347 020010 0 ustar cokelaer cokelaer 0000000 0000000 from easydev import doc
def test_underline():
a = doc.underline("test")
easydev-0.9.35/test/test_profiler.py 0000664 0001750 0001750 00000000210 13036703751 021056 0 ustar cokelaer cokelaer 0000000 0000000 from easydev import do_profile
@do_profile()
def test_profile():
@do_profile()
def test_runme():
a = 1
a**2
easydev-0.9.35/test/test_multicore.py 0000664 0001750 0001750 00000001072 12655403347 021252 0 ustar cokelaer cokelaer 0000000 0000000 from easydev.multicore import MultiProcessing
def func(n=400, *args, **kargs):
"""A simple test function to play with MultiProcessing class
:param n: 400 takes about 5 seconds
"""
print("inside func", args, kargs)
import math
for i in range(0,n):
for j in range(0,n):
for k in range(0,n):
math.sqrt(float(i))
d = {'id':n}
return d
def test_func():
t = MultiProcessing(verbose=True)
t.add_job(func, 200)
t.add_job(func, 100)
t.add_job(func, 50)
t.run()
print(t.results)
easydev-0.9.35/test/test_dependencies.py 0000664 0001750 0001750 00000000224 12655403347 021673 0 ustar cokelaer cokelaer 0000000 0000000 from easydev.dependencies import get_dependencies
def test():
get_dependencies("easydev")
get_dependencies("easydev_dummyi_dont_exists")
easydev-0.9.35/test/test_copybutton.py 0000664 0001750 0001750 00000000646 12655403347 021463 0 ustar cokelaer cokelaer 0000000 0000000 from easydev import copybutton
def test_copybutton():
copybutton.get_copybutton_path()
def test_copy_javascript_into_static_path():
copybutton.copy_javascript_into_static_path("_static",
copybutton.get_copybutton_path())
copybutton.copy_javascript_into_static_path("_static",
copybutton.get_copybutton_path())
import os
os.remove("_static/copybutton.js")
os.rmdir("_static")
easydev-0.9.35/test/test_console.py 0000664 0001750 0001750 00000000476 13052647501 020712 0 ustar cokelaer cokelaer 0000000 0000000 from easydev.console import *
from easydev import console
def test_get_terminal_width():
get_terminal_width()
def test_term_width_line():
term_width_line('text')
def test_color_terminal():
color_terminal()
def test_print_color():
print(purple('\t%s' % "test"))
print(red('\t%s' % "test"))
easydev-0.9.35/test/test_progressbar.py 0000664 0001750 0001750 00000001134 13036702645 021574 0 ustar cokelaer cokelaer 0000000 0000000
from easydev import progressbar
import time
from easydev import Progress
def test_progressbar():
N = 2
p = progressbar.progress_bar(N)
for i in range(0,N):
time.sleep(.1)
p.animate(i+1, i)
p = progressbar.TextProgressBar(N, progressbar.consoleprint)
for i in range(0,N):
time.sleep(.1)
p.animate(i+1, i)
p = Progress(100)
p.animate(1)
assert p.pb.interval == 1
p = Progress(200)
assert p.pb.interval == 2
p.animate(1)
# IPYthon test ? fails on travis
# p = progressbar.IPythonNotebookPB(200)
# p.animate(1)
easydev-0.9.35/test/test_timer.py 0000664 0001750 0001750 00000000262 13036717151 020362 0 ustar cokelaer cokelaer 0000000 0000000 from easydev.timer import Timer
import time
def test_timer():
times = []
with Timer(times):
time.sleep(.1)
assert len(times) == 1
assert sum(times) <1
easydev-0.9.35/test/test_platform.py 0000664 0001750 0001750 00000001507 13130520603 021056 0 ustar cokelaer cokelaer 0000000 0000000 import easydev
from easydev.platform import get_platform, linux_distribution, is_windows
from easydev.platform import is_linux, is_mac
def test_platform(mocker):
assert get_platform() in ['Linux', 'Windows', 'Mac']
linux_distribution()
is_windows()
is_linux()
is_mac()
"""def func():
raise Exception
with patch("platform.linux_distribution", func):
get_platform()
"""
mocker.patch.object(easydev.platform, "get_platform")
easydev.platform.get_platform.return_value = "Windows"
assert is_linux() is False
assert is_mac() is False
assert is_windows() is True
mocker.patch.object(easydev.platform, "get_platform")
easydev.platform.get_platform.return_value = "Mac"
assert is_linux() is False
assert is_windows() is False
assert is_mac() is True
easydev-0.9.35/test/test_appdirs.py 0000664 0001750 0001750 00000001173 13052627642 020711 0 ustar cokelaer cokelaer 0000000 0000000 import mock
def test_app():
def getter(app):
app.user_data_dir
app.site_data_dir
app.user_config_dir
app.site_config_dir
app.user_cache_dir
app.user_log_dir
with mock.patch("sys.platform", "darwin"):
from easydev import appdirs
app = appdirs.AppDirs("test")
getter(app)
with mock.patch("sys.platform", "win32"):
from easydev import appdirs
app = appdirs.AppDirs("test")
getter(app)
with mock.patch("sys.platform", "linux"):
from easydev import appdirs
app = appdirs.AppDirs("test")
getter(app)
easydev-0.9.35/test/test_package.py 0000664 0001750 0001750 00000000515 12655403347 020643 0 ustar cokelaer cokelaer 0000000 0000000 from easydev import PackageBuilder
def test_package():
p = PackageBuilder("tstPkg")
p.logging.debugLevel = "ERROR"
p.buildPackage()
p.buildPackage(force=True)
import shutil
shutil.rmtree("tstPkg")
def test_options():
from easydev import package
package.OptionsBuildPackage(["--pkgname", "test"])
easydev-0.9.35/test/test_logging_tools.py 0000664 0001750 0001750 00000000710 13052637317 022111 0 ustar cokelaer cokelaer 0000000 0000000 from easydev import Logging
def test_logging():
l = Logging("INFO")
l.info("test")
l.level = "WARNING"
l.level == "INFO"
l.level == "CRITICAL"
l.level == "ERROR"
l.level == "DEBUG"
l.level = True
l.level = False
try:
l.level = "WARN"
assert Fales
except:
assert True
# FIXME is this working ??wierd syntax in loggibg_tools.
import copy
copy.copy(l)
copy.deepcopy(l)
easydev-0.9.35/test/test_md5.py 0000664 0001750 0001750 00000000376 13002701112 017714 0 ustar cokelaer cokelaer 0000000 0000000 from easydev.md5tools import md5
from easydev import TempFile
def test_md5():
with TempFile() as temp:
fh = open(temp.name, "w")
fh.write("youpi")
fh.close()
assert md5(fh.name) == "538e957924f0770b415f473ce900d686"
easydev-0.9.35/test/test_url.py 0000664 0001750 0001750 00000000670 13052634326 020047 0 ustar cokelaer cokelaer 0000000 0000000 from easydev import isurl_reachable
from nose.plugins.attrib import attr
def test_isurl():
assert isurl_reachable("www.google.com") == True
assert isurl_reachable("http://www.google.com") == True
assert isurl_reachable("https://fr.yahoo.com") == False # moved
assert isurl_reachable("wrong.co.ujj") == False
assert isurl_reachable("http://wrong.co.ujj") == False
assert isurl_reachable("http://wrong.co") == False
easydev-0.9.35/test/test_config.py 0000664 0001750 0001750 00000005402 13052644054 020507 0 ustar cokelaer cokelaer 0000000 0000000 from easydev.config_tools import ConfigExample, DynamicConfigParser, load_configfile
from easydev import CustomConfig
import os
def test_config_custom():
c = CustomConfig('dummy')
c.init()
c.user_config_dir
c.remove()
def test_configExample():
c = ConfigExample().config
assert 'General' in c.sections()
assert 'GA' in c.sections()
print(c)
c.remove_section('General')
def test_ordered_dict_attribute():
# disabled because incompatible with python 3
c = DynamicConfigParser()
c.add_section("GA")
c.GA.test = 2 # this is an attribute only, not yet a key
c.add_option("GA", "test", 1)
c.GA.test = 2
c['GA']['test'] = 4
del c['GA']['test']
def test_DynamicConfig():
c = ConfigExample()
dc = DynamicConfigParser(c.config)
dc.save('test.ini')
dc = DynamicConfigParser('test.ini')
#dc = DynamicConfigParser(c.config)
dc._replace_config(c.config)
dc.GA
dc.add_option("GA", "bool", 'True')
dc.get_options("GA")
os.remove('test.ini')
dc.remove_section('GA')
assert 'GA' not in dc.sections()
print(dc)
# try something stupid
try:
dc = DynamicConfigParser(234)
assert False
except TypeError:
assert True
dc = DynamicConfigParser()
try:
dc.read("test_dummy")
assert False
except:
assert True
def test_DynamicConfigDelete():
from easydev import ConfigExample
dcp = DynamicConfigParser(ConfigExample().config)
try:
del(dcp["GA"])
assert dcp.sections() == ['General']
except:
pass
def test_DynamicConfig_setter():
dc = DynamicConfigParser()
dc.add_section("GA")
dc.add_option("GA", "test", 1)
dc.save("test.ini")
dc2 = DynamicConfigParser("test.ini")
assert dc == dc2
dc2.GA.test == 1
dc.GA.test = 10
dc.save("test.ini")
dc2 = DynamicConfigParser("test.ini")
assert dc == dc2
assert dc2.GA.test == '10'
os.remove('test.ini')
def test_section2dict():
dc = DynamicConfigParser()
dc.add_section("GA")
dc.add_option("GA", "test", 1)
def test_compare():
dc = DynamicConfigParser()
dc.add_section("GA")
dc.add_option("GA", "test", 1)
dc2 = DynamicConfigParser()
dc2.add_section("GA2")
dc2.add_option("GA2", "test", 1)
assert (dc==dc2) == False
dc = DynamicConfigParser()
dc.add_section("GA")
dc.add_option("GA", "test", 1)
dc2 = DynamicConfigParser()
dc2.add_section("GA")
dc2.add_option("GA", "test", 2)
assert (dc==dc2) == False
dc = DynamicConfigParser()
dc.add_section("GA")
dc.add_option("GA", "test", 1)
dc2 = DynamicConfigParser()
dc2.add_section("GA")
dc2.add_option("GA", "test", 1)
assert (dc==dc2) == True
easydev-0.9.35/test/test_browse.py 0000664 0001750 0001750 00000001314 13052652162 020540 0 ustar cokelaer cokelaer 0000000 0000000 from easydev import browser
try:
from unittest.mock import patch
except:
from mock import patch
def test_browse(mocker):
def func(*args, **kwargs):
pass
with patch('webbrowser.open', func):
with patch('webbrowser.open_new', func):
browser.browse("http://pypi.python.org", verbose=True)
browser.browse("pypi.python.org", verbose=True)
browser.browse(".", verbose=True)
def test_browse_module(mocker):
from easydev.browser import main
def func(*args, **kwargs):
pass
with patch('webbrowser.open', func):
main(["browse", "--help"])
main(["browse", "." ])
main(["browse", "http://www.uniprot.org" ])
easydev-0.9.35/test/test_paths.py 0000664 0001750 0001750 00000001233 12701452245 020356 0 ustar cokelaer cokelaer 0000000 0000000 from easydev.paths import *
import os
def test_get_share_directory_path():
get_shared_directory_path("easydev")
try:
get_shared_directory_path("dummydummy")
assert False
except:
assert True
def test_get_share_directories():
a = get_shared_directories("easydev", "themes")
def test_get_share_file():
f = get_share_file("easydev", os.sep.join(["themes", "standard"]), "theme.conf")
def test_gsf():
f = gsf("easydev", os.sep.join(["themes", "standard"]), "theme.conf")
try:
f = gsf("easydev", os.sep.join(["themes", "standard"]), "theme.conf.dummy")
assert False
except:
assert True
easydev-0.9.35/test/test_chunks.py 0000664 0001750 0001750 00000000364 12715312360 020534 0 ustar cokelaer cokelaer 0000000 0000000 from easydev import split_into_chunks
def test_chunks():
assert list(split_into_chunks([0,1,2,3,4,5,6], 2)) == [[0, 2, 4, 6], [1, 3, 5]]
assert list(split_into_chunks([0,1,2,3,4,5], 2)) == [[0, 2, 4], [1, 3, 5]]
test_chunks()
easydev-0.9.35/test/test_options.py 0000664 0001750 0001750 00000001524 13032202235 020723 0 ustar cokelaer cokelaer 0000000 0000000 from easydev import SmartFormatter
import argparse
class Options(argparse.ArgumentParser):
def __init__(self, prog="test"):
usage = """standalone test"""
description="""blabla"""
super(Options, self).__init__(usage=usage, prog=prog,
description=description, formatter_class=SmartFormatter)
self.add_argument("--config-params", dest="config_params",
type=str,
help="""FORMAT|Overwrite any field in the config file by using
the following convention. A config file is in YAML format
and has a hierarchy of parametesr. For example:
samples:
file1: R1.fastq.gz
file2: R2.fastq.gz
bwa_mem_phix:
mem:
threads: 2
""")
def test():
options = Options()
try:
options.parse_args(["--help"])
except:
pass
easydev-0.9.35/test/test_decorators.py 0000664 0001750 0001750 00000001432 13036703471 021407 0 ustar cokelaer cokelaer 0000000 0000000 from easydev.decorators import requires, ifpandas, ifpylab, _require
class A(object):
def __init__(self):
pass
def create(self):
self.a = 1
self.b = 1
@requires("a", "what to do")
def print_str(self):
print(self.a)
@requires(["a",'b'], "what to do")
def print_list(self):
print(self.a +self.b)
@_require("a", "what to do")
def print_list(self):
print(self.a)
def test():
a = A()
try:
a.print_str()
assert False
except:
assert True
try:
a.print_list()
assert False
except:
assert True
a.create()
a.print_str()
a.print_list()
@ifpandas
def test_deco_pandas():
print(1)
@ifpylab
def test_deco_pylab():
print(1)
easydev-0.9.35/test/test_multisetup.py 0000664 0001750 0001750 00000004317 12655403347 021467 0 ustar cokelaer cokelaer 0000000 0000000 """Test make_develop for Multisetup object"""
import os
from easydev.multisetup import Multisetup
from nose import with_setup
"""!!For the following test, don't use intrusive commands such as install
together with run method. !!!!"""
curdir = '..' + os.sep + '..'
packages = ['easydev']
def test_init():
""" Test initialization of Multisetup object """
mysetup = Multisetup(curdir=curdir, commands='build', packages=packages)
assert mysetup.commands == ['build']
assert len(mysetup.packages) == 1
assert mysetup.packages == packages
def _test_wrong_package():
mysetup = Multisetup(curdir=curdir,
commands=['build', '--packages','corezzz'],
packages=['corezzz'])
try:
mysetup.run()
assert False
except:
assert True
def test_parse_packages():
""" Test of parse_packages() method with option --packages"""
mysetup = Multisetup(curdir=curdir, commands='dummy', packages=packages)
mysetup.commands = ['build', '--packages', 'easydev']
mysetup.parse_packages()
assert mysetup.packages == set(['easydev'])
def test_parse_no_packages():
""" Test of parse_packages() method with option --exclude-package"""
mysetup = Multisetup(curdir=curdir,
commands='commands --exclude-packages easydev',
packages=packages)
print(mysetup.packages)
assert mysetup.packages == []
def test_parse_commands():
""" Test of parse_commands() method"""
commands =['install', 'sdist', '-d', './dist', '--quiet', '--keep-going']
mysetup = Multisetup(curdir=curdir, commands=commands, packages=[])
mysetup.parse_commands()
mysetup.parse_packages()
assert len(mysetup.commands) == 2
assert mysetup.commands[0] == 'install'
assert mysetup.commands[1] == 'sdist -d ./dist'
assert mysetup.verbose == False
assert mysetup.force == True
def test_setup_failure():
""" Test of run() method with bad option"""
commands = '--packages easydev sdist --bad-option'
mysetup = Multisetup(curdir=curdir, commands=commands, packages=['easydev'])
try:
mysetup.run()
assert False
except:
assert True
easydev-0.9.35/test/test_codecs.py 0000664 0001750 0001750 00000001266 13002676246 020511 0 ustar cokelaer cokelaer 0000000 0000000 from easydev import codecs
def test_tolist():
assert codecs.tolist(1) == [1]
assert codecs.tolist(1.) == [1.]
assert codecs.tolist('1') == ['1']
assert codecs.tolist([1]) == [1]
assert codecs.tolist([1, 2]) == [1, 2]
try:
import numpy as np
x = np.array([1, 2])
assert codecs.tolist(x) == [1, 2]
except:
pass
assert sorted(codecs.tolist((1, 2))) == [1, 2]
codecs.tolist(set([1]))
def test_tostring():
assert codecs.list2string([1, 2]) == "1, 2"
assert codecs.list2string([1, 2], sep=";") == "1; 2"
assert codecs.list2string([1, 2], sep=';', space=False) == "1;2"
assert codecs.list2string(1) == "1"
easydev-0.9.35/test/test_tools.py 0000664 0001750 0001750 00000006771 13036702172 020412 0 ustar cokelaer cokelaer 0000000 0000000 from easydev import tools, TempFile
def test_check_range():
tools.check_range(1, 0,1)
tools.check_range(0, 0,1)
tools.check_range(0.5, 0,1)
try:
tools.check_range(1, 0,1, strict=True)
assert False
except:
assert True
try:
tools.check_range(0, 0,1, strict=True)
assert False
except:
assert True
try:
tools.check_range(10, 0,1, strict=False)
assert False
except:
assert True
try:
tools.check_range(-10, 0,1, strict=False)
assert False
except:
assert True
def test_swapdict():
assert {1:'a'} == tools.swapdict({'a':1})
# if the are non-unique values, we can catch the error or no:
try:
tools.swapdict({'a':1, 'b':1})
assert False
except:
assert True
tools.swapdict({'a':1, 'b':1}, check_ambiguity=False)
def test_tools():
tools.shellcmd('ls')
tools.shellcmd('ls', show=False)
tools.shellcmd('ls', show=True)
output = tools.shellcmd('ls', verbose=True)
tools.shellcmd('lssssssss', verbose=True, ignore_errors=True)
tools.execute('ls')
def test_tools2():
try:
tools.shellcmd('lsss', verbose=False)
assert False
except:
assert True
def test_checkParams():
tools.checkParam(1, [1, 2])
try:
tools.checkParam(0, [1, 2])
assert False
except:
assert True
try:
tools.checkParam(0, 0)
assert False
except TypeError:
assert True
def test_check_param_in_list():
tools.check_param_in_list(1, [0,1,5], "test")
try:
tools.check_param_in_list(10, [0,1,5])
assert False
except:
assert True
try:
tools.check_param_in_list(10, [0,1,5], 'testt')
assert False
except:
assert True
def test_precision():
assert tools.precision(2.123) == 2.12
assert tools.precision(2.123, 1) == 2.1
assert tools.precision(2.123,3) == 2.123
assert tools.precision(2123,-2) == 2100
def test_attrdict():
a = tools.AttrDict(value=1)
assert a.value == 1
assert 'value' in list(a.keys())
assert 1 in (a.values())
a.description = 'test'
assert a['description'] == 'test'
a['output'] = 'txt'
assert a.output == 'txt'
d = {'a':{'b':1}, 'aa':2}
ad = tools.AttrDict(**d)
assert ad.a.b == 1
ad.a.b = 2
assert ad.a.b == 2
ad['d'] = 4
assert ad.d == 4
try:
ad.update(1)
assert False
except:
assert True
# check json capabilities
fh = TempFile()
js = ad.to_json()
ad.to_json(filename=fh.name)
ad.from_json(fh.name)
fh.delete()
def test_devtools():
d = tools.DevTools()
d.check_param_in_list(1, [1,2])
d.check_range(1,0,2)
assert d.list2string(['a', 'b']) == 'a,b'
assert d.swapdict({'a':1}) == {1:'a'}
d.to_json({'a':1})
assert d.to_list('a') == ['a']
import tempfile, os
d.mkdirs(tempfile.mkdtemp() + os.sep + "test")
try:
d.check_exists("ttttttttttt")
assert False
except:
assert True
d.mkdir(tempfile.mkdtemp())
def test_mkdirs():
import tempfile, os
tools.mkdirs(tempfile.mkdtemp() + os.sep + "test")
try:
tools.mkdirs(tempfile.mkdtemp() + os.sep + "test")
assert False
except:
assert True
# without / , was not working but is now part of the API
tools.mkdirs(tempfile.mkdtemp())
def test_touch():
with TempFile() as fh:
fh.name
tools.touch(fh.name)
easydev-0.9.35/test/test_easytest.py 0000664 0001750 0001750 00000001021 13052637302 021072 0 ustar cokelaer cokelaer 0000000 0000000 from easydev.easytest import *
class A(object):
pass
def test_trysetattr():
trysetattr(A, "test", 1, possible=True)
try:
trysetattr(A, "test", 1, possible=False)
assert False
except:
assert True
def test_tempfile():
f = TempFile()
f.name
f.delete()
with TempFile() as fh:
pass
def test_list_almost_equal():
assert_list_almost_equal([1,2],[1,2])
try:
assert_list_almost_equal([1,2],[1,3])
assert False
except:
assert True
easydev-0.9.35/README.rst 0000664 0001750 0001750 00000003020 13052645332 016333 0 ustar cokelaer cokelaer 0000000 0000000 easydev
##########
.. image:: https://badge.fury.io/py/easydev.svg
:target: https://pypi.python.org/pypi/easydev
.. image:: https://secure.travis-ci.org/cokelaer/easydev.png
:target: http://travis-ci.org/cokelaer/easydev
.. image:: https://coveralls.io/repos/cokelaer/easydev/badge.svg?branch=master
:target: https://coveralls.io/r/cokelaer/easydev?branch=master
.. image:: https://landscape.io/github/cokelaer/easydev/master/landscape.png
:target: https://landscape.io/github/cokelaer/easydev/master
:documentation: http://easydev-python.readthedocs.io/en/latest/
:contributions: Please join https://github.com/cokelaer/easydev
:source: Please use https://github.com/cokelaer/easydev
:issues: Please use https://github.com/cokelaer/easydev/issues
:Python version supported: 2.6, 2.7, 3.3, 3.4, 3.5, 3.6
The `easydev `_ package
provides miscellaneous functions that are repeatidly used during
the development of Python packages. The goal is to help developers on
speeding up their own dev. It has been used also as an incubator for other
packages (e.g., http://pypi.python.org/pypi/colormap) and is stable.
.. warning:: I'm not pretending to provide universal and bug-free tools. The
tools provided may also change. However, **easydev** is used
in a few other packages such as
`bioservices `_,
`sequana `_ or
`GDSCTools `_ to give a few
examples.
easydev-0.9.35/COPYING 0000664 0001750 0001750 00000002777 13047373327 015727 0 ustar cokelaer cokelaer 0000000 0000000 New BSD License
Copyright (c) Thomas Cokelaer
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
a. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
b. 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.
c. Neither the name of the Scikit-learn Developers 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 REGENTS 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.
easydev-0.9.35/easydev/ 0000775 0001750 0001750 00000000000 13131155451 016305 5 ustar cokelaer cokelaer 0000000 0000000 easydev-0.9.35/easydev/platform.py 0000664 0001750 0001750 00000005200 13130521417 020476 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2017
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://easydev-python.readthedocs.io
#
##############################################################################
from __future__ import absolute_import # avoids conflict with standard module
import os
import sys
import platform as plf
__all__ = ["get_platform", "linux_distribution", ""]
def linux_distribution():
try:
# Note that this module has the same name as the standard module
# hence the renaming of the standard module here below
return plf.linux_distribution()
except Exception as err:
print(err)
return "unknown"
def get_platform():
"""Identify the platform (Linux/windows/Mac)
The folloing modules/functions can be used to identify the platform:
platform, sys.platform, os.name, os.environ. We use platform and return
the content of platform.system. If it does not work, sys.platform is used
and sys.platform output interpreted: linux, java, win and darwin are
searched for and returned aas Linux, Java, Windows, Darwin to be consistent
with the output of platform.syste. If those strings are not found,
just return the output of sys.platform.
:return: 'Linux' or 'Windows' or 'Darwin', 'Java' if platform
can be determined otherwise, the content of sys.platform()
"""
try:
platform = plf.system()
return platform
except:
# platform is not available under all systems (e.g., WLST tool
# see http://stackoverflow.com/questions/1854/python-what-os-am-i-running-on
# so, let us try sys.platform
platform = sys.platform
if platform.startswith('linux'):
platform = 'Linux'
elif platform.startswith('java'):
platform = 'Java'
elif platform.startswith('win'):
platform = 'Windows'
elif platform.startswith('darwin'):
platform = 'Darwin'
else:
print("platform not parsed. Return raw value of sys.platform.")
return platform
def is_windows():
if get_platform() == 'Windows':
return True
else:
return False
def is_linux():
if get_platform() == 'Linux':
return True
else:
return False
def is_mac():
if get_platform() == 'Mac':
return True
else:
return False
easydev-0.9.35/easydev/multicore.py 0000664 0001750 0001750 00000010643 13036730537 020676 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2017
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://easydev-python.readthedocs.io
#
##############################################################################
import time
from multiprocessing import cpu_count, Process, Queue, Pool
__all__ = ["MultiProcessing"]
class MultiProcessing(object):
"""Class to run jobs in an asynchronous manner.
You would use this class to run several jobs on a local computer that has
several cpus.
::
t = MultiProcessing(maxcpu=2)
t.add_job(func, func_args)
t.run()
t.results[0] # contain returned object from the function *func*.
.. warning:: the function must be a function, not a method. This is inherent
to multiprocess in the multiprocessing module.
.. warning:: the order in the results list may not be the same as the
list of jobs. see :meth:`run` for details
"""
def __init__(self, maxcpu=None, verbose=False, progress=True):
"""
:param maxcpu: default returned by multiprocessing.cpu_count()
:param verbose: print the output of each job. Could be very verbose
so we advice to keep it False.
:param progress: shows the progress
"""
if maxcpu == None:
maxcpu = cpu_count()
self.maxcpu = maxcpu
self.reset()
self.verbose = verbose
self.progress = progress
def reset(self):
"""remove joves and results"""
self.jobs = [] # a list of processes
self.results = Queue() # the results to append
def add_job(self, func, *args, **kargs):
"""add a job in the pool"""
if self.verbose:
print("Adding jobs in the queue..",)
t = Process(target=func, args=args, kwargs=kargs)
self.jobs.append(t)
def _cb(self, results):
if self.verbose is True:
print("callback", results)
if self.progress is True:
self.pb.animate(len(self.results)+1)
self.results.append(results)
def run(self, delay=0.1, verbose=True):
"""Run all the jobs in the Pool until all have finished.
Jobs that have been added to the job list in :meth:`add_job`
are now processed in this method by using a Pool. Here, we add
all jobs using the apply_async method from multiprocess module.
In order to ensure that the jobs are run sequentially in the same
order as in :attr:`jobs`, we introduce a delay between 2 calls
to apply_async (see http://docs.python.org/2/library/multiprocessing.html)
A better way may be t use a Manager but for now, this works.
"""
from easydev import Progress
if self.progress is True:
self.pb = Progress(len(self.jobs), 1)
self.pb.animate(0)
def init_worker():
import signal
signal.signal(signal.SIGINT, signal.SIG_IGN)
self.results = []
self.pool = Pool(self.maxcpu, init_worker)
for process in self.jobs:
self.pool.apply_async(process._target, process._args,
process._kwargs, callback=self._cb)
# ensure the results have same order as jobs
# maybe important if you expect the order of the results to
# be the same as inut; otherwise set delay to 0
time.sleep(delay)
try:
while True:
time.sleep(1)
# check if all processes are finished.
# if so, finished.
count = len(self.results)
if count == len(self.jobs):
break
except KeyboardInterrupt:
print("\nCaught interruption. " +
"Terminating the Pool of processes... ",)
self.pool.terminate()
self.pool.join()
print("... done")
else:
# Closing properly the pool
self.pool.close()
self.pool.join()
# Pool cannot be pickled. So, if we want to pickel "MultiProcessing"
# class itself, we must desctroy this instance
del self.pool
self.finished = True
easydev-0.9.35/easydev/profiler.py 0000664 0001750 0001750 00000003712 13052634677 020522 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2017
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://easydev-python.readthedocs.io
#
##############################################################################
"""
Usage::
from easydev import do_profile
@do_profile()
def test():
x = 1
x *= x
return x
# source: https://zapier.com/engineering/profiling-python-boss/
Requires line_profiler to be installed. line_profiler has C code and we wish
easydev to be as simple as possible. So, we do not want compiled code dependencies.
Consequently, we added line_profiler in the extra_requires instead of requires
in the setup.py One must install line_profiler itself.
"""
__all__ = ["do_profile"]
try:
from line_profiler import LineProfiler
def do_profile(follow=[]):
def inner(func):
def profiled_func(*args, **kwargs):
try:
profiler = LineProfiler()
profiler.add_function(func)
for f in follow:
profiler.add_function(f)
profiler.enable_by_count()
return func(*args, **kwargs)
finally:
profiler.print_stats()
return profiled_func
return inner
except ImportError:
def do_profile(follow=[]):
"Helpful if you accidentally leave in production!"
print("easydev warning:: line_profiler does not seem to be installed. " +
"Type 'pip install line_profiler'")
def inner(func):
def nothing(*args, **kwargs):
return func(*args, **kwargs)
return nothing
return inner
easydev-0.9.35/easydev/misc.py 0000664 0001750 0001750 00000004061 13130521322 017604 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2017
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://easydev-python.readthedocs.io
#
##############################################################################
import os
__all__ = ['get_home', 'cmd_exists']
def get_home():
# This function should be robust
# First, let us try with expanduser
try:
homedir = os.path.expanduser("~")
except ImportError:
# This may happen.
pass
else:
if os.path.isdir(homedir):
return homedir
# Then, with getenv
for this in ('HOME', 'USERPROFILE', 'TMP'):
# getenv is same as os.environ.get
homedir = os.environ.get(this)
if homedir is not None and os.path.isdir(homedir):
return homedir
def cmd_exists(cmd):
try:
import subprocess
# for unix/max only
result = subprocess.call("type " + cmd, shell=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if result == 0:
return True
else:
return False
except Exception:
# If subprocess is not found, we assume it exists.
# This choice ensure that if it fails, we keep going.
return True
def in_ipynb():
"""Checks if we are in an ipython notebook
:return: True if in an ipython notebook otherwise returns False
"""
try:
cfg = get_ipython().config
if 'parent_appname' in cfg['IPKernelApp'].keys() and \
cfg['IPKernelApp']['parent_appname'] == 'ipython-notebook':
return True
elif "connection_file" in cfg['IPKernelApp'].keys():
if "jupyter" in cfg['IPKernelApp']['connection_file']:
return True
return False
except NameError:
return False
easydev-0.9.35/easydev/decorators.py 0000664 0001750 0001750 00000012151 13036730473 021033 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2012-2014 -
#
# File author(s): Thomas Cokelaer (cokelaer, gmail.com)
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# website: http://github.com/cokelaer/easydev
#
##############################################################################
"""Handy decorators"""
from functools import wraps
import threading
__all__ = ['ifpylab', 'requires', 'ifpandas']
# decorator with arguments and optional arguments for a method
def _require(*args_deco, **kwds_deco):
"""Decorator for class method to check if an attribute exist
.. doctest::
from easydev.decorators import require
class Test(object):
def __init__(self):
self.m = 1
@require('m', "set the m attribute first")
def print(self):
print self.m
t = Test()
t.print()
.. todo:: first argument could be a list
"""
if len(args_deco) != 2:
raise ValueError("require decorator expects 2 parameter. First one is" +
"the required attribute. Second one is an error message.")
attribute = args_deco[0]
msg = args_deco[1]
if len(attribute.split('.')) > 2:
raise AttributeError('This version of require decorator introspect only 2 levels')
def decorator(func):
# func: function object of decorated method; has
# useful info like f.func_name for the name of
# the decorated method.
def newf(*args, **kwds):
# This code will be executed in lieu of the
# method you've decorated. You can call the
# decorated method via f(_args, _kwds).
names = attribute.split('.')
if len(names) == 1:
if hasattr(args[0], attribute):
return func(*args, **kwds)
else:
raise AttributeError('%s not found. %s' % (names, msg))
elif len(names) == 2:
if hasattr(getattr(args[0], names[0]), names[1]):
return func(*args, **kwds)
else:
raise AttributeError('%s not found. %s' % (names, msg))
newf.__name__ = func.__name__
newf.__doc__ = func.__doc__
return newf
return decorator
# for book keeping, could be useful:
"""
def _blocking(not_avail):
def blocking(f, *args, **kw):
if not hasattr(f, "thread"):
# no thread running
def set_result():
f.result = f(*args, **kw)
f.thread = threading.Thread(None, set_result)
f.thread.start()
return not_avail
elif f.thread.isAlive():
return not_avail
else:
# the thread is ended, return the stored result
del f.thread
return f.result
return blocking
"""
# same as require decorator but works with list of stirngs of
# single string and uses the functools utilities
def requires(requires, msg=""):
"""Decorator for class method to check if an attribute exist
.. doctest::
>>> from easydev.decorators import requires
>>> class Test(object):
... def __init__(self):
... self.m = 1
... self.x = 1
... @requires(['m','x'], "set the m attribute first")
... def printthis(self):
... print(self.m+self.x)
>>> t = Test()
>>> t.printthis()
2
"""
if isinstance(requires, str):
requires = [requires]
elif isinstance(requires, list) == False:
raise TypeError("First argument of the /requires/ decorator must be a" +
"string or list of string representing the required attributes" +
"to be found in your class. Second argument is a " +
"complementary message. ")
def actualDecorator(f):
@wraps(f)
def wrapper(*args, **kwds):
for require in requires:
if hasattr(args[0], require) == False:
raise AttributeError("{} not found in {}. ".format(require, args[0]) + msg)
return f(*args, **kwds)
return wrapper
return actualDecorator
# could be a macro maybe
def ifpandas(func):
"""check if pandas is available. If so, just return
the function, otherwise returns dumming function
that does nothing
"""
def wrapper(*args, **kwds):
return func(*args, **kwds)
try:
import pandas
return wrapper
except Exception:
def dummy():
pass
return dummy
def ifpylab(func):
"""check if pylab is available. If so, just return
the function, otherwise returns dumming function
that does nothing
"""
# for functions
def wrapper(*args, **kwds):
return func(*args, **kwds)
# for methods
try:
import pylab
return wrapper
except Exception:
def dummy():
pass
return dummy
easydev-0.9.35/easydev/tools.py 0000664 0001750 0001750 00000024120 13056023406 020016 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2017
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://easydev-python.readthedocs.io
#
##############################################################################
"""toolkit to ease development"""
import subprocess
import json
import os
import sys
__all__ = ["shellcmd", "swapdict", "check_param_in_list",
"check_range", "precision", "AttrDict", "DevTools", "execute",
"touch", "mkdirs"]
def precision(data, digit=2):
"""Round values in a list keeping only N digits precision
::
>>> precision(2.123)
2.12
>>> precision(2123, digit=-2)
2100
"""
data = int(data*pow(10, digit))
data /= pow(10., digit)
return data
def check_range(value, a, b, strict=False):
"""Check that a value lies in a given range
:param value: value to test
:param a: lower bound
:param b: upper bound
:return: nothing
.. doctest::
>>> from easydev.tools import check_range
>>> check_range(1,0, 2)
"""
if strict is True:
if value <= a:
raise ValueError(" {} must be greater (or equal) than {}".format(value, a))
if value >= b:
raise ValueError(" {} must be less (or less) than {}".format(value, b))
elif strict is False:
if value < a:
raise ValueError(" {} must be greater than {}".format(value, a))
if value > b:
raise ValueError(" {} must be less than {}".format(value, b))
def checkParam(param, valid_values):
"""
.. warning:: deprecated since 0.6.10 use :meth:`check_param_in_list` instead
"""
print("easydev WARNING:: deprecated; use check_param_in_list instead.")
check_param_in_list(param, valid_values)
def check_param_in_list(param, valid_values, name=None):
"""Checks that the value of param is amongst valid
:param param: a parameter to be checked
:param list valid_values: a list of values
::
check_param_in_list(1, [1,2,3])
check_param_in_list(mode, ["on", "off"])
"""
if isinstance(valid_values, list) is False:
raise TypeError("the valid_values second argument must be a list of valid values. {0} was provided.".format(valid_values))
if param not in valid_values:
if name:
msg = "Incorrect value provided for {} ({})".format(name, param)
else:
msg = "Incorrect value provided (%s)" % param
msg += " Correct values are %s" % valid_values
raise ValueError(msg)
def shellcmd(cmd, show=False, verbose=False, ignore_errors=False):
"""An alias to run system commands with Popen.
Based on subprocess.Popen.
:param str cmd: the command to call
:param bool show: print the command
:param bool verbose: print the output
:return: the output as a string
"""
if show:
print(cmd)
try:
ret = subprocess.Popen([cmd], stdout=subprocess.PIPE,
stderr=subprocess.PIPE, shell=True)
output = ret.stdout.read().strip()
error = ret.stderr.read().strip()
ret.wait()
if len(error) > 0:
if ignore_errors is False:
raise Exception(error)
else:
if verbose is True:
print("Errors/Warning" + str(error))
if verbose is True:
print(output)
return output
except Exception as err:
raise Exception("Error:: Command (%s) failed. Error message is %s" % (cmd, err))
def execute(cmd, showcmd=True, verbose=True):
"""An alias to run system commands using pexpect.
:param cmd:
:param showcmd:
:param verbose:
"""
import pexpect
if showcmd is True:
print(cmd)
p = pexpect.spawn(cmd, timeout=None)
line = p.readline()
while line:
if verbose:
try:
sys.stdout.write(line.decode())
except:
sys.stdout.write(line)
sys.stdout.flush()
line = p.readline()
def touch(fname, times=None):
"""Touch a file (like unix command)
"""
with open(fname, 'a'):
os.utime(fname, times)
def swapdict(dic, check_ambiguity=True):
"""Swap keys for values in a dictionary
::
>>> d = {'a':1}
>>> swapdict(d)
{1:'a'}
"""
# this version is more elegant but slightly slower : return {v:k for k,v in dic.items()}
if check_ambiguity:
assert len(set(dic.keys())) == len(set(dic.values())), "values is not a set. ambiguities for keys."
return dict(zip(dic.values(), dic.keys()))
def mkdirs(newdir, mode=0o777):
"""Recursive creation of a directory
:source: matplotlib mkdirs. In addition, handles "path" without slashes
make directory *newdir* recursively, and set *mode*. Equivalent to ::
> mkdir -p NEWDIR
> chmod MODE NEWDIR
"""
# mkdirs("analysis") # without / at the end led to an error
# since os.path.split returns ('', 'analysis')
try:
if not os.path.exists(newdir):
parts = os.path.split(newdir)
for i in range(1, len(parts) + 1):
thispart = os.path.join(*parts[:i])
# if no sep at the end, thispart may be an empty string
# so, we need to check if thispart exists and is not of len 0
if not os.path.exists(thispart) and len(thispart):
os.makedirs(thispart, mode)
except OSError as err:
import errno
# Reraise the error unless it's about an already existing directory
if err.errno != errno.EEXIST or not os.path.isdir(newdir):
raise
class AttrDict(dict):
"""dictionary-like object that exposes its keys as attributes.
When you have dictionary of dictionaries with many levels e.g.::
d = {'a': {'a1': {'a2': 2}}}
to get/set a values, one has to type something like::
d['a']['a1']['a2'] = 3
The :class:`AttrDict` allows the dictionary to work as attributes::
ad = AttrDict(**d)
ad.a.a1.a2 = 3
You can now add values as attribute, or with ['key'] syntax
.. doctest::
>>> from easydev import AttrDict
>>> a = AttrDict(**{'value': 1})
>>> a.value
1
>>>
>>> a.unit = 'meter'
>>> sorted(a.keys())
['unit', 'value']
If you need to add new simple values after the creation of the instance,
just use the setter::
>>> d['newa'] = 2
>>> d.newa = 2 # equivalent to the statement above
but if you want to set a dictionary (whichever recursive level), use
the :meth:`update` method::
>>> d.update({'newd': {'g': {'h':2}}})
>>> d.newd.g.h
2
Note that if you use the setter for a value that is a dictionary, e.g.::
ad.a = {'b':1}
then *a* is indeed a dictionary.
"""
def __init__(self, **kwargs):
dict.__init__(self, kwargs)
self.__dict__ = self
self.update(kwargs)
def update(self, content):
"""See class/constructor documentation for details
:param dict content: a valid dictionary
"""
# accepts dict and attrdict classes
try:
from collections import OrderedDict
except:
OrderedDict = AttrDict
if content.__class__ not in [dict, OrderedDict, AttrDict]:
raise TypeError
for k, v in content.items():
if v.__class__ not in [dict, AttrDict, OrderedDict]:
# fixme copy ?
self[k] = v
else:
self[k] = AttrDict(**v)
def from_json(self, filename):
"""
does not remove existing keys put replace them if already present
"""
res = json.load(open(filename, "r"))
for k,v in res.items():
self[k] = v
def to_json(self, filename=None):
import json
if filename is not None:
with open(filename, "w") as fout:
json.dump(self, fout)
else:
return json.dumps(self)
class DevTools(object):
"""Aggregate of easydev.tools functions.
"""
def check_range(self, value, a, b):
"""wrapper around :func:`easydev.check_range`"""
check_range(value, a, b, strict=False)
def check_param_in_list(self, param, valid_values):
"""wrapper around :func:`easydev.check_param_in_list`"""
param = self.to_list(param)
for name in param:
check_param_in_list(name, list(valid_values))
def swapdict(self, d):
"""wrapper around :func:`easydev.swapdict`"""
return swapdict(d)
def to_list(self, query):
"""Cast to a list if possible
'a' ->['a']
1 -> [1]
"""
from easydev import codecs
return codecs.to_list(query)
def list2string(self, query, sep=",", space=False):
"""
see :func:`easydev.tools.list2string`
"""
from easydev import codecs
return codecs.list2string(query, sep=sep, space=space)
def to_json(self, dictionary):
"""Transform a dictionary to a json object"""
return json.dumps(dictionary)
def mkdir(self, dirname):
"""Create a directory if it does not exists; pass without error otherwise"""
try:
os.mkdir(dirname)
except OSError:
pass # exists already
except Exception as err:
raise(err)
def shellcmd(self, cmd, show=False, verbose=False, ignore_errors=False):
"""See :func:`shellcmd`"""
return shellcmd(cmd, show=show, verbose=verbose, ignore_errors=ignore_errors)
def check_exists(self, filename):
"""Raise error message if the file does not exists"""
if os.path.exists(filename) is False:
raise ValueError("This file %s does not exists" % filename)
def mkdirs(self, dirname, mode=0o777):
mkdirs(dirname, mode=mode)
easydev-0.9.35/easydev/md5tools.py 0000664 0001750 0001750 00000001506 13036730522 020431 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2017
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://easydev-python.readthedocs.io
#
##############################################################################
"""md5 utility"""
import hashlib
def md5(fname, chunk=65536):
"""Return the MD5 checksums of a file
Takes about 25 seconds on a 8Gb file.
"""
hash_md5 = hashlib.md5()
with open(fname, "rb") as f:
for this in iter(lambda: f.read(chunk), b""):
hash_md5.update(this)
return hash_md5.hexdigest()
easydev-0.9.35/easydev/multisetup.py 0000664 0001750 0001750 00000031252 13036730544 021103 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2017
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://easydev-python.readthedocs.io
#
##############################################################################
"""Calling setup.py recursively and/or in multi python packages.
The commands are similar to those expected by setup.py. In addition,
there are a few commands dedicated to multisetup (see --help).
:Example:
.. doctest::
:options: +SKIP
>>> python multisetup install --quiet
>>> python multisetup install sdist --dist-dir ../dist
>>> python multisetup --keep-going install sdist --dist-dir ../dist
Based on OpenAlea.Misc http://openalea.gforge.inria.fr
"""
__license__ = "GPLv3"
__revision__ = "$Id$"
import sys
import os
from subprocess import PIPE, Popen
try:
from easydev.console import bold, red, green, \
color_terminal, nocolor, underline, purple
except ImportError:
pass
"""
args = sys.argv[1:]
if len(args) == 1 and args[0] in ['-h', '--help']:
Multisetup.help()
else:
if 'develop -u' in args:
dirs.reverse()
"""
class Multisetup(object):
"""The main base class to build Multisetup instances
In practice, you create a python script with this kind of code::
if __name__ == "__main__"
from easydev.multisetup import Multisetup
import sys
packages = ['pkg1', 'pkg2']
mysetup = Multisetup(commands=sys.argv[1:], packages=packages)
mysetup.run()
"""
def __init__(self, commands, packages=None, curdir='.', verbose=True):
""".. rubric:: Constructor
:param commands: list of user commands or command (see :meth:`parse_commands`)
accepted commands are --packages, --exclude-packages, -quiet, --keep-going
:param list packages: list of packages to process
:param str curdir: current directory default is .
:param bool verbose: verbose option
:type commands: a string or list of strings
The argument `commands` must be a list of strings combining arguments
from multisetup and setup.
:Examples:
.. doctest::
:options: +SKIP
>>> Multisetup("install --keep-going", ['pkg1', 'pkg2'], '.', verbose=True)
>>> Multisetup(["install","--keep-going"], ['pkg1', 'pkg2'], '.', verbose=True)
"""
if len(commands) == 1 and commands[0] in ['-h', '--help']:
Multisetup.help()
if 'develop -u' in " ".join(commands):
packages.reverse()
# default
self.curdir = os.path.abspath(curdir)
if isinstance(commands, list):
self.commands = list(commands)
elif isinstance(commands, str):
self.commands = list(commands.split(" "))
else:
raise TypeError("commands argument must be a list of arguments or a string")
self.packages = list(packages)
self.verbose = verbose
self.force = False
# parsing user arguments
self.parse_packages()
# self.parse_intern_commands()
self.parse_commands()
@classmethod
def help(cls):
"""help: to get more help and usage
"""
print("""
MultiSetup allows to build and install all the packages found in this
directory usinf the same commands and setuptools.
Examples:
---------
# Developer mode : Installation of the pks from svn
>>> python multisetup.py develop
# User mode: Installation of the packages on the system as root
>>> python multisetup.py install
# Administrator mode: Create distribution of the packages
>>> python multisetup.py nosetests -w test install bdist_egg -d ../dist sdist -d ../dist
Common commands:
multisetup.py sdist -d ./dist will create a source distribution underneath 'dist/'
multisetup.py install will install the package
Global options:
--quiet do not show setup outputs [default=False]
-k, --keep-going force the commands running[default=False]
-h, --help show detailed help message
--packages list of packages to run
[default: none]
--exclude-packages list of packages to not run
print "usage: multisetup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
""")
def parse_packages(self):
"""Search and remove package(S) from multisetup command (e.g., --package)
.. todo:: known issue: python multisetup.py --packages with two
packages will be confused by following commands. Must be put
at the end of the command
"""
if '--packages' in self.commands:
index = self.commands.index('--packages')
self.commands.remove('--packages')
self.packages = set()
found = True
while found is True:
try: #test is no more argument
self.commands[index]
except: # then breaks
break
# otherwise if next argument starts with -, break
if self.commands[index].startswith('-'):
break
# or carry on to gather package names
else:
self.packages.add(self.commands[index])
self.commands.remove(self.commands[index])
continue
#self.commands.pop(index)
if '--exclude-packages' in self.commands:
# keep track of --exclude-package index
index = self.commands.index('--exclude-packages')
# remove it from the commands
self.commands.remove('--exclude-packages')
# remove all packages provided afterwards until next arguments is found
found = True
while found is True:
# look for next argument/package that may be the end of the command
try:
package_to_remove = self.commands[index]
except:
break
# if this is a valid package name
if package_to_remove in self.packages:
# remove it from the package list
self.packages.remove(package_to_remove)
# and from the command line
self.commands.remove(package_to_remove)
# until we found another package
continue
# otherwise, it is an argument that
else:
#starts with a - sign
if package_to_remove.startswith('-'):
break
# or is invalid
raise ValueError('--exclude-packages error: package %s not found in package list' \
% self.commands[index])
#self.commands.pop(index)
def parse_commands(self):
"""Search and remove multisetup options
Get the user command line arguments (self.commands) that are dedicated
to multisetup such as --help, --quiet, --keep-going so that the
remaining commands are fully comptatible with setuptools.
"""
if '--quiet' in self.commands:
self.verbose = False
self.commands.remove('--quiet')
if '-k' in self.commands:
self.force = True
self.commands.remove('-k')
if '--keep-going' in self.commands:
self.force = True
self.commands.remove('--keep-going')
L = len(self.commands)
i = 0
while (i < L):
if self.commands[i].startswith('-'):
try:
self.commands[i-1] = self.commands[i-1] + ' ' + self.commands[i] + ' ' + self.commands[i+1]
self.commands.pop(i)
self.commands.pop(i)
except:
self.commands[i-1] = self.commands[i-1] + ' ' + self.commands[i]
self.commands.pop(i)
else:
i += 1
L = len(self.commands)
def run(self, color=True):
"""Executes 'python setup.py' with the user commands on all packages. """
if color:
try:
from easydev.console import bold, red, green, \
color_terminal, nocolor, underline, purple
except:
try:
sys.path.insert(0, os.path.join('deploy', 'src', 'deploy'))
from console import bold, red, green, \
color_terminal, nocolor, underline, purple
except:
pass
if not color_terminal():
# Windows' poor cmd box doesn't understand ANSI sequences
nocolor()
else:
bold = purple = red = green = underline = str
print(bold("Running multisetup version %s" % __revision__.split()[2]))
#project_dir = self.curdir.basename()
directories = [package for package in self.packages]
print('Will process the following directories: ',)
for directory in directories:
print(bold(directory)),
#print bold(directory.basename()),
print('')
try:
for directory in directories:
try:
os.chdir(directory)
print(underline('Entering %s package'
% os.path.basename(directory)))
# % directory.basename())
except OSError as err:
print(underline('Entering %s package'
% os.path.basename(directory)))
print(red("cannot find this directory (%s)"
% os.path.basename(directory)))
print(err)
print('Python exec : ' , sys.executable)
#print underline('Entering %s package' % directory.basename())
for cmd in self.commands:
setup_command = '%s setup.py %s ' % (sys.executable,cmd)
print("\tExecuting " + setup_command + '...processing',)
#Run setup.py with user commands
outputs = None
errors = None
if self.verbose:
process = Popen(setup_command,
shell=True)
status = process.wait()
else:
process = Popen(setup_command, stdout=PIPE, stderr=PIPE,
shell=True)
#status = process.wait()
outputs, errors = process.communicate()
if process.returncode == 0:
print(green('done'))
else:
if not self.verbose:
print(red('\tFailed. ( error code %s) ' %
(process.returncode)))
os.chdir(self.curdir)
if not self.force:
raise RuntimeError()
if 'pylint' in cmd:
if outputs is not None:
for x in outputs.split('\n'):
if x.startswith('Your code has been'):
print(purple('\t%s' % x))
if 'nosetests' in cmd:
if errors is not None:
for x in errors.split('\n'):
if x.startswith('TOTAL'):
res = x.replace('TOTAL', 'Total coverage')
res = " ".join (res.split())
print(purple('\t%s' % res))
if x.startswith('Ran'):
print(purple('\t%s' % x))
if x.startswith('FAILED'):
print(purple('\t%s' % x))
else:
print(purple('all right'))
os.chdir(self.curdir)
except RuntimeError:
sys.exit()
os.chdir(self.curdir)
easydev-0.9.35/easydev/logging_tools.py 0000664 0001750 0001750 00000005665 13052637441 021547 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
#
# This file is part of easydev software
#
# Copyright (c) 2012-2014
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
#
##############################################################################
import logging
__all__ = ["Logging"]
class Logging(object):
"""logging utility.
When using the logging utility, it works like a singleton.
So, once logging level is set, you cannot set it again easily.
Here is a class that allows to do that.
.. warning:: this is a bit of a hack. Maybe this is not a proper solution but
it seems to do the job.
::
>>> l = Logging("INFO")
>>> l.info("test")
INFO:root:test
>>> l.level = "WARNING"
>>> l.info("test")
"""
# I think that we can not inherit from logging.
def __init__(self, level):
""".. rubric:: constructor
:param str level: valid levels are ["INFO", "DEBUG", "WARNING",
"CRITICAL", "ERROR"]. If set to True, level is internally set to
INFO. If set to False, level is seet internally to ERROR.
"""
self._debugLevel = None
self.debugLevel = level
self.logging = logging
self.info = logging.info
self.warning = logging.warning
self.critical = logging.critical
self.error = logging.error
self.debug = logging.debug
def _set_level(self, level):
valid_level = [True, False, "INFO", "DEBUG", "WARNING", "CRITICAL", "ERROR"]
if level is True:
level = "INFO"
if level is False:
level = "ERROR"
if level in valid_level:
self._debugLevel = level
else:
raise ValueError("The level of debugging must be in %s " %valid_level)
# I'm not sure this is the best solution, but basicConfig can be called
# only once and populatse root.handlers list with one instance of
# logging.StreamHandler. So, I reset it before calling basicConfig
# that effectively changes the logging behaviour
logging.root.handlers = []
logging.basicConfig(level=self._debugLevel)
def _get_level(self):
return self._debugLevel
debugLevel = property(_get_level, _set_level,
doc="Read/Write access to the debug level. Must be one of INFO, " + \
"DEBUG, WARNING, CRITICAL, ERROR")
level = property(_get_level, _set_level,
doc="alias to :attr:`~easydev.logging_tools.Logging.debugLevel` (Read-only access)")
# Used copy/deepcopy module
def __copy__(self):
print("WARNING: easydev.logging_tools.__copy__ deprecated. use copy() instead")
s = Logging(self.level)
return s
def __deepcopy__(self, memo):
s = Logging(self.level)
return s
easydev-0.9.35/easydev/browser.py 0000664 0001750 0001750 00000011655 13052631440 020351 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2017
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://easydev-python.readthedocs.io
#
##############################################################################
"""Universal browser
This module provides a browser in 2 flavours: as a program to use in a Terminal,
or as a Python function that can be used in other software. The underlying code is based on the standard python module :mod:`webbrowser`. With webbrowser module itself, you can already open a URL as follows in a command line interface::
python -m webbrowser -t "http://www.python.org"
However, with **browse**, you can simply type::
browse http://www.python.org
It does not seem to be a big improvments but it is a bit more flexible. First,
there is no need to enter "http://" : it will be added if missing and if this is not a local file.::
browse docs.python.org
browse http://docs.python.org --verbose
Similarly, you can open an image (it uses the default image viewer)::
browse image.png
Or a txt file (or any document provided there is a default executable
to open it). It works like a charm under Linux. Under MAC, it uses the **open**
command so this should also work.
When invoking **browse**, under MacOSX, it actually tries to call **open**
first and then calls webbrowser, if unsuccessful only. Note tested under
Windows but uses webbrowser is used and works for open HTML document and URLs.
You can also look at a directory (starts nautilus under Fedora)::
browse ~/Pictures
See more examples below.
The interest of **browse** is that it can also be used programmatically::
from easydev.browser import browse
# open an image with the default image viewer:
browse("image.png")
# or a web page
browse("http://www.uniprot.org")
There is also an alias **onweb**::
from easydev import onweb
"""
import os
import sys, webbrowser
from optparse import OptionParser
import argparse
def browse(url, verbose=True):
from sys import platform as _platform
if _platform == "linux" or _platform == "linux2":
_browse_linux(url, verbose=True)
elif _platform == "darwin":
# under Mac, it looks like the standard webbrowser may not work as smoothly
# OS X
_browse_mac(url, verbose)
elif _platform == "win32":
# for windows and others, the same code as Linux should work
_browse_linux(url, verbose=True)
else:
_browse_linux(url, verbose=True)
def _browse_mac(url, verbose=True):
if verbose:
print("openning %s" % url)
import os
try:
os.system("open /Applications/Safari.app {}".format(url))
return
except:
pass
try:
os.system("open /Applications/Safari.app {}".format("http://" + url))
return
except:
pass
try:
webbrowser.open_new(url)
except:
if verbose:
print("Could not open %s. Trying to append http://" % url)
try:
webbrowser.open_new("open http://{}".format(url))
except:
print("Could not open http://%s" % url)
raise Exception
def _browse_linux(url, verbose=True):
if verbose:
print("openning %s" % url)
try:
webbrowser.open(url)
return
except:
pass
try:
if verbose:
print("Could not open %s" % url)
webbrowser.open("http://" + url)
return
except:
pass
raise Exception("Could not open http://{}".format(url))
def main(args=None):
if args is None:
args = sys.argv[:]
# check for verbosity
if "--verbose" in args:
verbose = True
args.remove("--verbose")
print(args)
else:
verbose = False
if "--help" in args or len(args) == 1:
print("Browse, a simple command line browser")
print("Author: Thomas Cokelaer, (c) 2012.")
print("USAGE\n\tbrowse http://docs.python.org ")
print("\tbrowse http://docs.python.org --verbose")
print("\tbrowse localfile.html")
print("\tbrowse local_directory (Linux only ?)")
return
url = args[1]
if os.path.exists(url):
if verbose:
print("%s is local file. Trying to open it.\n" % url)
browse(url, verbose)
else:
if verbose:
print("%s seems to be a web address. Trying to open it.\n" %url)
if url.startswith("http"):
browse(url, verbose)
else:
if verbose:
print("%s does not exists and does not starts with http, trying anyway." %url)
browse("http://"+url, verbose)
if __name__ == "__main__":
import sys
main(sys.argv)
easydev-0.9.35/easydev/dependencies.py 0000664 0001750 0001750 00000001616 13036730423 021313 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2017
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://easydev-python.readthedocs.io
#
##############################################################################
# $:Id $
import pkg_resources
__all__ = ["get_dependencies"]
def get_dependencies(pkgname):
"""Return dependencies of a package as a sorted list
:param str pkgname: package name
:return: list (empty list if no dependencies)
"""
try:
res = pkg_resources.require(pkgname)
res = list(set(res))
res.sort()
return res
except Exception:
return []
easydev-0.9.35/easydev/timer.py 0000664 0001750 0001750 00000002046 13036730577 020015 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2017
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://easydev-python.readthedocs.io
#
##############################################################################
"""A convenient timer"""
import time
class Timer():
"""Timer working with *with* statement
::
times = []
with Timer(times):
# do something
import time
time.sleep(0.1)
with Timer(imes):
# do something else
time.sleep(0.2)
"""
def __init__(self, times):
self.times = times
def __enter__(self):
self.t1 = time.time()
def __exit__(self, type, value, traceback):
self.t2 = time.time()
self.times.append(self.t2-self.t1)
easydev-0.9.35/easydev/copybutton.py 0000664 0001750 0001750 00000006561 13036730465 021105 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2014
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://packages.python.org/easydev
#
##############################################################################
"""This module is a copy of a sphinx extension. unknown origin.
added by Thomas Cokelaer: get_copybutton_path function.
Create a sphinx extension based on copybutton javascript from python website
Requires sphinx to be installed. imports are inside functions so not stricly
speaking required for the installation.
"""
import os
from os.path import join as pj
import shutil
try:
from docutils import nodes
except Exception:
# if docutils is not installed
class Dummy():
SkipNode = Exception
nodes = Dummy()
__all__ = ["get_copybutton_path", ]
def copy_javascript_into_static_path(static="_static", filepath="copybutton.js"):
"""This script can be included in a sphinx configuration file to copy the
copybutton in the static directory
:param str static: name of the static path (_static by default)
:param filename: full path of the file to copy
:Details: If the path *static* does not exists, it is created. If the
filename in filepath is already in the path *static*, nothing need to be done.
Otherwise, the file is copied in *static* directory.
"""
if os.path.isdir(static):
pass
else:
os.mkdir(static)
filename = os.path.split(filepath)[1]
if os.path.isfile(static + os.sep + filename):
pass
else:
shutil.copy(filepath, static + os.sep + filename)
def get_copybutton_path():
"""Return the path where the to find the copybutton javascript
Copy the copybutton.js javascript in the share directory of easydev so
that it is accesible by all packages that required it by typing:
.. doctest::
>>> from easydev import get_copybutton_path
>>> p = get_copybutton_path()
It can then be added with a Sphinx configuration file::
jscopybutton_path = easydev.copybutton.get_copybutton_path()
"""
import easydev
try: # install mode
packagedir = easydev.__path__[0]
packagedir = os.path.realpath(pj(packagedir, 'share'))
os.listdir(packagedir) # if this faisl, we are in deve mode
except OSError:
try:
packagedir = easydev.__path__[0]
packagedir = os.path.realpath(pj(packagedir, '..', 'share'))
except:
raise IOError("could not find data directory")
return pj(packagedir, "copybutton.js")
def setup(app):
cwd = os.getcwd()
# From Sphinx, we typing "make html", this is the place where we expect
# the JS to be found
staticpath = os.sep.join([cwd, "source", "_static"])
from easydev.tools import mkdirs
mkdirs(staticpath)
if os.path.exists(staticpath + os.sep + "copybutton.js"):
pass # the JS file is already there.
else:
# Not found, so let us copy it
import shutil
shutil.copy( get_copybutton_path(), staticpath)
# Now that the file is available, use it
app.add_javascript('copybutton.js')
easydev-0.9.35/easydev/url.py 0000664 0001750 0001750 00000002764 13052635220 017471 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2017
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://easydev-python.readthedocs.io
#
##############################################################################
"""Utilities related to the web"""
try:
import httplib
except ImportError:
import http.client as httplib
__all__ = ["isurl_reachable"]
def isurl_reachable(url, timeout=10, path="/"):
"""Checks if an URL exists or nor
:param str url: the url to look for
:param str path: Used in request.request at the
url path following the domain name. For instance,
www.ensembl.org is the site url but actually
we want to check this full url www.ensembl.org/biomart/martview
:return: True if it exists
.. versionchanged:: 0.9.30
"""
if url.startswith("http://") or url.startswith("https://"):
url = url.split("//")[1]
conn = httplib.HTTPConnection(url, timeout=timeout)
try:
conn.request("HEAD", path)
except:
return False
# 302 is a redirection
# 200 is okay
try:
response = conn.getresponse()
except:
return False
if response.status in [200, 302]:
return True
else:
return False
easydev-0.9.35/easydev/package.py 0000664 0001750 0001750 00000031375 13036730553 020271 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2017
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://easydev-python.readthedocs.io
#
##############################################################################
import os
from easydev.logging_tools import Logging
__all__ = ["PackageBuilder"]
setup_template1 = """# -*- coding: utf-8 -*-
__revision__ = "$Id$" # for the SVN Id
import sys
import os
from setuptools import setup, find_packages
import glob
_MAJOR = %(MAJOR)s
_MINOR = %(MINOR)s
_MICRO = %(MICRO)s
version = '%%d.%%d.%%d' %% (_MAJOR, _MINOR, _MICRO)
release = '%%d.%%d' %% (_MAJOR, _MINOR)
metainfo = {
'authors': {"main": ("%(author)s", "%(email)s")},
'version': version,
'license' : 'GPL',
'download_url' : ['http://pypi.python.org/pypi/%(name)s'],
'url' : ["http://pythonhosted.org/%(name)s/"],
'description': "%(description)s" ,
'platforms' : ['Linux', 'Unix', 'MacOsX', 'Windows'],
'keywords' : [''],
'classifiers' : [
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'Intended Audience :: Science/Research',
'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)',
'Operating System :: OS Independent',
'Programming Language :: Python :: 2.7',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: Scientific/Engineering :: Bio-Informatics',
'Topic :: Scientific/Engineering :: Information Analysis',
'Topic :: Scientific/Engineering :: Mathematics',
'Topic :: Scientific/Engineering :: Physics']
}
# files in share/data
datadir = os.path.join('share','data')
datafiles = [(datadir, [f for f in glob.glob(os.path.join(datadir, '*'))])]
"""
setup_template2 = """
setup(
name = "%(name)s",
version = version,
maintainer = metainfo['authors']['main'][0],
maintainer_email = metainfo['authors']['main'][1],
author = metainfo['authors']['main'][0],
author_email = metainfo['authors']['main'][1],
long_description = open("README.txt").read(),
keywords = metainfo['keywords'],
description = metainfo['description'],
license = metainfo['license'],
platforms = metainfo['platforms'],
url = metainfo['url'],
download_url = metainfo['download_url'],
classifiers = metainfo['classifiers'],
# package installation
package_dir = {'':'src'},
packages = ["%(pkgname)s"],
install_requires = %(install_require)s,
# uncomment if you have share/data files
#data_files = datafiles,
#use_2to3 = True, # causes issue with nosetests
)
"""
setup_template3 = """
namespace = '%(namespace)s'
# messy but works for namespaces under Python 2.7
pkgs = [pkg for pkg in find_packages("src")]
top_pkgs = [pkg for pkg in pkgs if len(pkg.split('.')) < 2]
package_dir = {"": "src"}
for pkg in top_pkgs:
package_dir[namespace + "." + pkg] = "src" + os.sep + pkg
setup(
name = "%(name)s",
version = version,
maintainer = metainfo['authors']['main'][0],
maintainer_email = metainfo['authors']['main'][1],
author = metainfo['authors']['main'][0],
author_email = metainfo['authors']['main'][1],
long_description = open("README.txt").read(),
keywords = metainfo['keywords'],
description = metainfo['description'],
license = metainfo['license'],
platforms = metainfo['platforms'],
url = metainfo['url'],
download_url = metainfo['download_url'],
classifiers = metainfo['classifiers'],
# package installation
package_dir = package_dir,
packages = find_packages("src"),
namespace_packages = [namespace],
install_requires = %(install_require)s,
# uncomment if you have share/data files
#data_files = datafiles,
#use_2to3 = True, # causes issue with nosetests
)
"""
namespace_init_template = """try:
__import__('pkg_resources').declare_namespace(__name__)
except:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
"""
namespace_init_pkg_template = """# Redirect path
import os
cdir = os.path.dirname(__file__)
pdir = os.path.join(cdir, "../../%(pkgname)s")
pdir = os.path.abspath(pdir)
__path__ = [pdir] + __path__[:]
from %(namespace)s.%(pkgname)s.__init__ import *
del cdir
del pdir
"""
setup_cfg_template = """
[build_sphinx]
source_dir = doc/source
build_dir = doc/build
all_files = 1
[nosetests]
where=test
with_coverage=
cover_package=%(name)s
cover_erase=
verbosity=2
;cover_html=
;cover_html_dir=html
logging_level=ERROR
[upload_docs]
upload_dir=doc/build/html/
"""
class PackageBuilder(object):
"""simple class to automatically build a package layout
.. doctest::
:options: +SKIP
>>> from easydev import PackageBuilder
>>> p = PackageBuilder(name="testpackage")
>>> p.buildPackage()
For the time being, this example creates the following layout::
pkg/
|-- doc
| |-- source
| |-- _static
|-- README.txt
|-- setup.py
|-- share
| |-- data
|-- src
| |-- pkg
| |-- __init__.py
|-- test
You can avoid the shared directory creation.
The namespace is not implemented so far.
The doc directory is empty so far.
The version is set to 0.0.1
Metainfo in the setup file need to be filed but the package should already be functional.
New modules can be added inside the src/pkgname directory.
"""
def __init__(self, name, share=True, namespace=None):
""".. rubric:: Constructor
:param str name:
:param str share:
"""
self.pkgname = name # can be only the pkg name without namespace
self.name = name # can be pkg or namespace.pkg
self.share = share
self.namespace = namespace
self.metainfo = {
"pkgname": self.pkgname,
"name":self.pkgname,
"version": "version",
"MINOR": '0',
"MAJOR": '0',
"MICRO": '1',
"install_require": '[]',
"description": "Put a short description here",
"author": "yourname",
"email": "email@whatever.org",
"namespace": self.namespace,
}
if self.namespace:
self.metainfo["name"] = ".".join([self.namespace, self.pkgname])
self.metainfo["url"] = os.sep.join([self.namespace, self.pkgname])
self.logging = Logging("INFO")
#self.init()
def init(self, force=False):
self.logging.info("Creating the package directory")
if os.path.isdir(self.pkgname):
self.logging.warning("Directory %s already exists." % self.pkgname)
self.logging.warning("You are about to delete this directory %s. " % self.pkgname)
if force==True:
res = "y"
else:
res = raw_input("Do you wish to proceed (y/n)?")
if res == "y":
import shutil
shutil.rmtree(self.pkgname)
os.mkdir(self.pkgname)
return True
else:
return False
else:
os.mkdir(self.pkgname)
return True
def create_namespace(self):
if self.namespace == None:
self.logging.warning("namespace is not set, cannot create namespace directories")
return
dir1 = "src" + os.sep + self.namespace
dir2 = "src" + os.sep + self.namespace + os.sep + self.pkgname
self._mkdir(dir1)
self._mkdir(dir2)
f = open(self.pkgname + os.sep + dir1 + os.sep + "__init__.py", "w")
f.write(namespace_init_template)
f.close()
f = open(self.pkgname + os.sep + dir2 + os.sep + "__init__.py", "w")
f.write(namespace_init_pkg_template % self.metainfo)
f.close()
def create_setup(self):
"""Creates a setup.py file"""
self.logging.info("Creating the setup.py file (you will need to update the metadata!")
filename = self.pkgname + os.sep + "setup.py"
f = open(filename, "w")
f.write(setup_template1 % self.metainfo)
if self.namespace == None:
f.write(setup_template2 % self.metainfo)
else:
f.write(setup_template3 % self.metainfo)
f.close()
# config file
filename = self.pkgname + os.sep + "setup.cfg"
f = open(filename, "w")
f.write("# a setup configuration")
f.write(setup_cfg_template % self.metainfo)
f.close()
def create_readme(self):
"""Creates a README file"""
self.logging.info("Creating a README file")
filename = self.pkgname + os.sep + "README.txt"
f = open(filename, "w")
f.write("""Provide some information to users about this package.""")
f.close()
def create_sphinx_directory(self):
"""Create layout for sphinx documentation"""
self._mkdir("doc")
self._mkdir("doc" + os.sep + "source")
self._mkdir("doc" + os.sep + "_static")
def create_test_directory(self):
"""Create a test directory"""
self._mkdir("test")
def _mkdir(self, name):
filename = self.pkgname + os.sep
self.logging.info("Creating a directory %s " % (filename + name))
os.mkdir(filename + name)
def create_src_directory(self):
"""Create a source directory and empty __init__ file"""
self._mkdir("src")
dirname = "src" + os.sep + self.pkgname
self._mkdir(dirname)
dirname = self.pkgname + os.sep + dirname
self.logging.info("Create %s/__init__ file " % dirname)
f = open(dirname + os.sep + "__init__.py", "w")
f.write("""__version__ = "$Rev: 10 $"
import pkg_resources
try:
version = pkg_resources.require("%(name)s")[0].version
except:
version = __version__
""" % self.metainfo)
f.close()
def create_share_directory(self):
"""Create share/data directory if required"""
self._mkdir("share")
self._mkdir("share" + os.sep + "data")
def buildPackage(self, force=False):
"""Builds the entire package
This function removes the directory "pkgname" if it exists,
to create it back (empty), and then calsl the methods starting with "create" word.
"""
res = self.init(force=force)
if res == False:
return
self.create_setup()
self.create_readme()
self.create_sphinx_directory()
self.create_test_directory()
self.create_src_directory()
if self.share:
self.create_share_directory()
if self.namespace:
self.create_namespace()
import argparse
class OptionsBuildPackage(argparse.ArgumentParser):
"""Options Parser for BuildPackage
"""
def __init__(self, args, version="1.0", prog="easydev_buildPackage"):
usage = """USAGE: %s --pkgname pkgName""" % prog
super(OptionsBuildPackage, self).__init__(usage=usage, prog=prog)
self.add_general_options()
self.options = self.parse_args(args)
self.version = version
def add_general_options(self):
#self.add_argument('--version',
# action='version', version=self.version)
self.add_argument("--pkgname", dest="pkgname",
help="Name of the package to be created")
self.add_argument("--package", dest="pkgname",
help="Name of the package to be created")
self.add_argument("--namespace", dest="namespace", default=None,
help="If provided, creates a namespace.")
self.add_argument("--no-share-directory", action="store_false",
help="if five, the share directory is not created")
self.add_argument("--verbosity", dest="verbosity", default="INFO",
help="set verbosity to INFO, WARNING or ERROR")
def buildPackage():
"""The executable easydev_buildPackage """
import sys
if len(sys.argv) > 1:
parser = OptionsBuildPackage(sys.argv[1:])
p = PackageBuilder(
name=parser.options.pkgname,
share=parser.options.no_share_directory,
namespace=parser.options.namespace)
p.logging.debugLevel = parser.options.verbosity
p.buildPackage()
else:
parser = OptionsBuildPackage(["--help"])
easydev-0.9.35/easydev/options.py 0000664 0001750 0001750 00000003300 13036730423 020350 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2017
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://easydev-python.readthedocs.io
#
##############################################################################
import argparse
__all__ = ["SmartFormatter"]
class SmartFormatter(argparse.HelpFormatter):
"""Formatter to be used with argparse ArgumentParser
When using the argparse Python module one can design
standalone applications with arguments (e.g; --help, --verbose...)
One can easily define the help as well. However, The help message
is wrapped by ArgumentParser, removing all formatting in the process.
The reason being that the entire documentation is consistent.
Sometines, one want to keep the format. This class can be used to
do that.
Example::
import argparse
from easydev import SmartFormatter
class Options(argparse.ArgumentParser):
def __init__(self, prog="sequana"):
usage = "blabla"
description="blabla"
super(Options, self).__init__(usage=usage, prog=prog,
description=description,
formatter_class=SmartFormatter)
"""
def _split_lines(self, text, width):
if text.startswith('FORMAT|'):
return text[7:].splitlines()
# this is the RawTextHelpFormatter._split_lines
return argparse.HelpFormatter._split_lines(self, text, width)
easydev-0.9.35/easydev/codecs.py 0000664 0001750 0001750 00000004731 13036714634 020134 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2017
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://www.assembla.com/spaces/pyeasydev/wiki
# Documentation: http://packages.python.org/easydev
#
##############################################################################
# $:Id $
"""various type convertors (e.g., list to string)"""
__all__ = ["to_list", "tolist", "list2string"]
def tolist(data, verbose=True):
"""alias to :func:`easydev.codecs.to_list`"""
return to_list(data, verbose=verbose)
def to_list(data, verbose=True):
"""Transform an object into a list if possible
:param data: a list, tuple, or simple type (e.g. int)
:return: a list
- if the object is list or tuple, do nothing
- if the object is not a list, we assume this is a primitive type and a list
of length 1 is returned, the item being the parameter provided.
.. code-block:: python
>>> from easydev import transform_to_list
>>> to_list(1)
[1]
>>> to_list([1,2])
[1,2]
"""
if isinstance(data, list) or isinstance(data, tuple):
return data #nothing to do
elif isinstance(data, float):
return [data]
elif isinstance(data, int):
return [data]
elif isinstance(data, str):
return [data]
else:
try:
data = data.tolist()
return data
except:
if verbose:
print("not known type. Trying to cast into a list")
return list(data)
def list2string(data, sep=",", space=True):
"""Transform a list into a string
:param list data: list of items that have a string representation.
the input data could also be a simple object, in which case
it is simply returned with a cast into a string
:param str sep: the separator to be use
.. code-block:: python
>>> list2string([1, 2]
"1, 2"
>>> list2string([1, 2], sep=;)
"1; 2"
>>> list2string([1, 2], sep=;, space=False)
"1;2"
>>> list2string(1, sep=;, space=False)
"1"
.. note:: the cast is performed with str()
"""
data = to_list(data)
if space is True:
sep = sep + " "
res = sep.join([str(x) for x in data])
return res
easydev-0.9.35/easydev/config_tools.py 0000664 0001750 0001750 00000033370 13052645074 021361 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2014
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://packages.python.org/easydev
#
##############################################################################
try:
from ConfigParser import ConfigParser
except ImportError:
from configparser import ConfigParser
import os
__all__ = ["CustomConfig", "DynamicConfigParser", "ConfigExample",
"load_configfile"]
# 53, 59, 64-65, 181, 260, 262, 267-270, 288-290, 329, 332-337, 340-341, 359-360, 386-388, 400-401, 406-426, 431-435
class _DictSection(object):
"""Dictionary section.
Reference: https://gist.github.com/dangoakachan/3855920
"""
def __init__(self, config, section):
object.__setattr__(self, '_config', config)
object.__setattr__(self, '_section', section)
def __getattr__(self, attr):
return self.get(attr, None)
__getitem__ = __getattr__
def get(self, attr, default = None):
if attr in self:
return self._config.get(self._section, attr)
else:
return default
def __setattr__(self, attr, value):
if attr.startswith('_'):
object.__setattr__(self, attr, value)
else:
self.__setitem__(attr, value)
def __setitem__(self, attr, value):
if self._section not in self._config:
self._config.add_section(self._section)
self._config.set(self._section, attr, str(value))
def __delattr__(self, attr):
if attr in self:
self._config.remove_option(self._section, attr)
__delitem__ = __delattr__
def __contains__(self, attr):
config = self._config
section = self._section
return config.has_section(section) and config.has_option(section, attr)
class ConfigExample(object):
"""Create a simple example of ConfigParser instance to play with
::
>>> from easydev.pipeline.config import ConfigExample
>>> c = ConfigExample().config # The ConfigParser instance
>>> assert 'General' in c.sections()
>>> assert 'GA' in c.sections()
This example builds up a ConfigParser instance from scratch.
This is equivalent to having the following input file::
[General]
verbose = True
tag = test
[GA]
popsize = 1
which can be read with ConfigParser as follows:
.. code-block:: python
>>> from ConfigParser import ConfigParser
>>> config = ConfigParser()
>>> config.read("file.ini")
[]
"""
def __init__(self):
self.config = ConfigParser()
self.config.add_section('General')
self.config.set('General', 'verbose', 'true')
self.config.add_section('GA')
self.config.set('GA', 'popsize', '50')
class DynamicConfigParser(ConfigParser, object):
"""Enhanced version of Config Parser
Provide some aliases to the original ConfigParser class and
new methods such as :meth:`save` to save the config object in a file.
.. code-block:: python
>>> from easydev.config_tools import ConfigExample
>>> standard_config_file = ConfigExample().config
>>> c = DynamicConfigParser(standard_config_file)
>>>
>>> # then to get the sections, simply type as you would normally do with ConfigParser
>>> c.sections()
>>> # or for the options of a specific sections:
>>> c.get_options('General')
You can now also directly access to an option as follows::
>>> c.General.tag
Then, you can add or remove sections (:meth:`remove_section`, :meth:`add_section`),
or option from a section :meth:`remove_option`. You can save the instance into a file
or print it::
>>> print(c)
.. warning:: if you set options manually (e.G. self.GA.test =1 if GA is a
section and test one of its options), then the save/write does not work
at the moment even though if you typoe self.GA.test, it has the correct value
Methods inherited from ConfigParser are available:
::
# set value of an option in a section
c.set(section, option, value=None)
# but with this class, you can also use the attribute
c.section.option = value
# set value of an option in a section
c.remove_option(section, option)
c.remove_section(section)
"""
def __init__(self, config_or_filename=None, *args, **kargs):
object.__setattr__(self, '_filename', config_or_filename)
# why not a super usage here ? Maybe there were issues related
# to old style class ?
ConfigParser.__init__(self, *args, **kargs)
if isinstance(self._filename, str) and os.path.isfile(self._filename):
self.read(self._filename)
elif isinstance(config_or_filename, ConfigParser):
self._replace_config(config_or_filename)
elif config_or_filename == None:
pass
else:
raise TypeError("config_or_filename must be a valid filename or valid ConfigParser instance")
def read(self, filename):
"""Load a new config from a filename (remove all previous sections)"""
if os.path.isfile(filename)==False:
raise IOError("filename {0} not found".format(filename))
config = ConfigParser()
config.read(filename)
self._replace_config(config)
def _replace_config(self, config):
"""Remove all sections and add those from the input config file
:param config:
"""
for section in self.sections():
self.remove_section(section)
for section in config.sections():
self.add_section(section)
for option in config.options(section):
data = config.get(section, option)
self.set(section, option, data)
def get_options(self, section):
"""Alias to get all options of a section in a dictionary
One would normally need to extra each option manually::
for option in config.options(section):
config.get(section, option, raw=True)#
then, populate a dictionary and finally take care of the types.
.. warning:: types may be changed .For instance the string "True"
is interpreted as a True boolean.
.. seealso:: internally, this method uses :meth:`section2dict`
"""
return self.section2dict(section)
def section2dict(self, section):
"""utility that extract options of a ConfigParser section into a dictionary
:param ConfigParser config: a ConfigParser instance
:param str section: the section to extract
:returns: a dictionary where key/value contains all the
options/values of the section required
Let us build up a standard config file:
.. code-block:: python
>>> import ConfigParser
>>> c = ConfigParser.ConfigParser()
>>> c.add_section('general')
>>> c.set('general', 'step', str(1))
>>> c.set('general', 'verbose', 'True')
To access to the step options, you would write::
>>> c.get('general', 'step')
this function returns a dictionary that may be manipulated as follows::
>>> d_dict.general.step
.. note:: a value (string) found to be True, Yes, true,
yes is transformed to True
.. note:: a value (string) found to be False, No, no,
false is transformed to False
.. note:: a value (string) found to be None; none,
"" (empty string) is set to None
.. note:: an integer is cast into an int
"""
options = {}
for option in self.options(section):
data = self.get(section, option, raw=True)
if data.lower() in ['true', 'yes']:
options[option] = True
elif data.lower() in ['false', 'no']:
options[option] = False
elif data in ['None', None, 'none', '']:
options[option] = None
else:
try: # numbers
try:
options[option] = self.getint(section, option)
except:
options[option] = self.getfloat(section, option)
except: #string
options[option] = self.get(section, option, raw=True)
return options
def save(self, filename):
"""Save all sections/options to a file.
:param str filename: a valid filename
::
config = ConfigParams('config.ini') #doctest: +SKIP
config.save('config2.ini') #doctest: +SKIP
"""
try:
if os.path.exists(filename) == True:
print("Warning: over-writing %s " % filename)
fp = open(filename,'w')
except Exception as err:
print(err)
raise Exception('filename could not be opened')
self.write(fp)
fp.close()
def add_option(self, section, option, value=None):
"""add an option to an existing section (with a value)
.. code-block:: python
>>> c = DynamicConfigParser()
>>> c.add_section("general")
>>> c.add_option("general", "verbose", True)
"""
assert section in self.sections(), "unknown section"
#TODO I had to cast to str with DictSection
self.set(section, option, value=str(value))
def __str__(self):
str_ = ""
for section in self.sections():
str_ += '[' + section + ']\n'
for option in self.options(section):
data = self.get(section, option, raw=True)
str_ += option + ' = ' + str(data)+'\n'
str_ += '\n\n'
return str_
def __getattr__(self, key):
return _DictSection(self, key)
__getitem__ = __getattr__
def __setattr__(self, attr, value):
if attr.startswith('_') or attr:
object.__setattr__(self, attr, value)
else:
self.__setitem__(attr, value)
def __setitem__(self, attr, value):
if isinstance(value, dict):
section = self[attr]
for k, v in value.items():
section[k] = v
else:
raise TypeError('value must be a valid dictionary')
def __delattr__(self, attr):
if attr in self:
self.remove_section(attr)
def __contains__(self, attr):
return self.has_section(attr)
def __eq__(self, data):
# FIXME if you read file, the string "True" is a string
# but you may want it to be converted to a True boolean value
if sorted(data.sections()) != sorted(self.sections()):
print("Sections differ")
return False
for section in self.sections():
for option in self.options(section):
try:
if str(self.get(section, option,raw=True)) != \
str(data.get(section,option, raw=True)):
print("option %s in section %s differ" % (option, section))
return False
except:
return False
return True
class CustomConfig(object):
"""Base class to manipulate a config directory"""
def __init__(self, name, verbose=False):
self.verbose = verbose
from easydev import appdirs
self.appdirs = appdirs.AppDirs(name)
def init(self):
sdir = self.appdirs.user_config_dir
self._get_and_create(sdir)
def _get_config_dir(self):
sdir = self.appdirs.user_config_dir
return self._get_and_create(sdir)
user_config_dir = property(_get_config_dir,
doc="return directory of this configuration file")
def _get_and_create(self, sdir):
if not os.path.exists(sdir):
print("Creating directory %s " % sdir)
try:
self._mkdirs(sdir)
except Exception:
print("Could not create the path %s " % sdir)
return None
return sdir
def _mkdirs(self, newdir, mode=0o777):
"""See :func:`easydev.tools.mkdirs`"""
from easydev.tools import mkdirs
mkdirs(newdir, mode)
def remove(self):
try:
sdir = self.appdirs.user_config_dir
os.rmdir(sdir)
except Exception as err:
raise Exception(err)
def _load_configfile(configpath):
"Tries to load a JSON or YAML file into a dict."
try:
with open(configpath) as f:
try:
import json
return json.load(f)
except ValueError:
f.seek(0) # try again
try:
import yaml
except ImportError:
raise IOError("Config file is not valid JSON and PyYAML "
"has not been installed. Please install "
"PyYAML to use YAML config files.")
try:
return yaml.load(f)
except yaml.YAMLError:
raise IOError("Config file is not valid JSON or YAML. "
"In case of YAML, make sure to not mix "
"whitespace and tab indentation.")
except Exception as err:
raise(err)
def load_configfile(configpath):
"Loads a JSON or YAML configfile as a dict."
config = _load_configfile(configpath)
if not isinstance(config, dict):
raise IOError("Config file must be given as JSON or YAML "
"with keys at top level.")
return config
easydev-0.9.35/easydev/chunks.py 0000664 0001750 0001750 00000002543 13036730430 020156 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2017
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://easydev-python.readthedocs.io
#
##############################################################################
#http://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks-in-python
#
# Here's a generator that yields the chunks you want:
#
# def chunks(l, n):
# """Yield successive n-sized chunks from l."""
# for i in range(0, len(l), n):
# yield l[i:i+n]
#
#The issue here is that the chunks are not evenly sized chunks
#
__all__ = ['split_into_chunks']
try:
range = xrange # py2
except:
pass #py3
def split_into_chunks(items, maxchunks=10):
"""Split a list evenly into N chunks
.. doctest::
>>> from easydev import split_into_chunks
>>> data = [1,1,2,2,3,3]
>>> list(split_into_chunks(data, 3))
[[1, 2], [1, 3], [2, 3]]
"""
chunks = [[] for _ in range(maxchunks)]
for i, item in enumerate(items):
chunks[i % maxchunks].append(item)
return filter(None, chunks)
easydev-0.9.35/easydev/__init__.py 0000664 0001750 0001750 00000003407 13052645165 020432 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2014
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://packages.python.org/easydev
#
##############################################################################
from __future__ import print_function
#from __future__ import absolute_import
__version__ = "0.9.34"
import pkg_resources
try:
version = pkg_resources.require("easydev")[0].version
except:
version = __version__
from . import browser
from .browser import browse as onweb
from . import codecs
from .codecs import *
from . import chunks
from .chunks import *
from . import copybutton
from .copybutton import *
from . import decorators
from .decorators import *
from . import doc
from .doc import *
from . import easytest
from .easytest import *
from . import logging_tools
from .logging_tools import *
from . import sphinx_themes
from .sphinx_themes import *
from . import tools
from .tools import *
from . import multisetup
from .md5tools import md5
from . import options
from .options import *
from . import paths
from .paths import *
from . import misc
from .misc import *
from . import package
from .package import *
from . import config_tools
from .config_tools import *
#from . import timer
from .timer import Timer
from . import url
from .url import *
#import dependencies
from .dependencies import get_dependencies
from . import multicore
from .multicore import *
from .progressbar import TextProgressBar, progress_bar, Progress
from .profiler import do_profile
easydev-0.9.35/easydev/easytest.py 0000664 0001750 0001750 00000006737 13052636640 020543 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2014
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://packages.python.org/easydev
#
##############################################################################
# $:Id $
# keep nose inside the functions to avoid dependencies
import tempfile
__all__ = ["assert_list_almost_equal", "trysetattr", "TempFile"]
#from easydev.decorators import ifpandas
def assert_list_almost_equal(first, second, places=None, deltas=None):
"""Combined version nose.tools.assert_almost_equal and assert_list_equal
This function checks that 2 lists contain identical items.
The equality between pair of items is checked with assert_almost_equal
function, which means you can check for the places argument
.. note:: there may be already some tools to
check that either in nosetests or unittest
but could not find.
.. doctest::
>>> from easydev.easytest import assert_list_almost_equal
>>> assert_list_almost_equal([0,0,1], [0,0,0.9999], places=3)
>>> assert_list_almost_equal([0,0,1], [0,0,0.9999], deltas=1e-4)
"""
from nose.tools import assert_almost_equal
for x, y in zip(first, second):
# PYTHON 2.6 hack. This assert_almost_equal function
# fails but I don't think this is correct. So let us
# catch the TypeError
try:
assert_almost_equal(x, y, places=places, delta=deltas)
except TypeError:
pass
def trysetattr(this, attrname, value, possible):
"""A common test pattern: try to set a non-writable attribute
::
class A(object):
def __init__(self):
self._a = 1
self._b = 2
def _get_a(self):
return self._a
def _set_a(self, value):
self._a = value
a = property(_get_a, _get_b)
def _get_b(self):
return self._b
b = property(_get_b)
>>> o = A()
>>> trysetattr(A, "a", 1, possible=True)
>>> trysetattr(A, "b", 1, False)
AssertionError
"""
if possible == True:
a1 = True
a2 = False
else:
a1 = False
a2 = True
try:
setattr(this, attrname, value)
assert a1 # if the setattr is possible, this should be True
except Exception:
assert a2
class TempFile(object):
"""A small wrapper around tempfile.NamedTemporaryFile function
::
f = TempFile(suffix="csv")
f.name
f.delete() # alias to delete=False and close() calls
"""
def __init__(self, suffix='', dir=None):
self.temp = tempfile.NamedTemporaryFile(suffix=suffix, delete=False,
dir=dir)
def delete(self):
try:
self.temp._closer.delete = True
except:
self.temp.delete = True
self.temp.close()
def _get_name(self):
return self.temp.name
name = property(_get_name)
def __exit__(self, type, value, traceback):
try:
self.delete()
except AttributeError:
pass
finally:
self.delete()
def __enter__(self):
return self
easydev-0.9.35/easydev/console.py 0000664 0001750 0001750 00000006327 13052635726 020343 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
# It is a modified version of console.py from the sphinx software
#
# Copyright (c) 2011-2014
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://packages.python.org/easydev
#
##############################################################################
"""Format colored consoled output. Modified from sphinx.util.console"""
import os
import sys
__all__ = ["color_terminal", "get_terminal_width", "term_width_line"]
from easydev.platform import is_windows
if is_windows() is True:
import colorama
colorama.init()
# colors and other functions from the attributes codes are added dynamically to
# this __all__ variable
codes = {}
def get_terminal_width():
"""Returns the current terminal width"""
try:
import termios, fcntl, struct
call = fcntl.ioctl(0, termios.TIOCGWINSZ,
struct.pack('hhhh', 0, 0, 0, 0))
_, width = struct.unpack('hhhh', call)[:2]
terminal_width = width
except (SystemExit, KeyboardInterrupt):
raise
except:
# FALLBACK
terminal_width = int(os.environ.get('COLUMNS', 80)) - 1
return terminal_width
def term_width_line(text):
"""prints pruned version of the input text (limited to terminal width)
:param str text:
:return str text:
"""
_tw = get_terminal_width()
if not codes:
# if no coloring, don't output fancy backspaces
return text + '\n'
else:
return text.ljust(_tw) + '\r'
def color_terminal():
"""Does terminal allows coloring
:return: boolean"""
if not hasattr(sys.stdout, 'isatty'):
return False
if not sys.stdout.isatty():
return False
if 'COLORTERM' in os.environ:
return True
term = os.environ.get('TERM', 'dumb').lower()
if term in ('xterm', 'linux') or 'color' in term:
return True
return False
def __nocolor():
"""set color codes off"""
codes.clear()
def __coloron():
"""Set color codes on"""
codes.update(_orig_codes)
def _colorize(name, text):
return codes.get(name, '') + text + codes.get('reset', '')
def _create_color_func(name):
def inner(text):
return _colorize(name, text)
globals()[name] = inner
_attrs = {
'reset': '39;49;00m',
'bold': '01m',
'faint': '02m',
'standout': '03m',
'underline': '04m',
'blink': '05m',
}
for _name, _value in _attrs.items():
codes[_name] = '\x1b[' + _value
_colors = [
('black', 'darkgray'),
('darkred', 'red'),
('darkgreen', 'green'),
('brown', 'yellow'),
('darkblue', 'blue'),
('purple', 'fuchsia'),
('turquoise', 'teal'),
('lightgray', 'white'),
]
for i, (dark, light) in enumerate(_colors):
codes[dark] = '\x1b[%im' % (i+30)
codes[light] = '\x1b[%i;01m' % (i+30)
_orig_codes = codes.copy()
for _name in codes:
_create_color_func(_name)
# dynamically set the colors
for x in codes.keys():
__all__.append(x)
easydev-0.9.35/easydev/sphinx_themes.py 0000664 0001750 0001750 00000002774 13036730573 021557 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2017
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://easydev-python.readthedocs.io
#
##############################################################################
"""Common tools to ease access to a easydev sphinx themes."""
import os
from os.path import join as pj
__all__ = ["get_path_sphinx_themes", "get_sphinx_themes"]
def get_path_sphinx_themes():
"""Returns the path where the sphinx themes can be found
.. doctest::
>>> from easydev import sphinx_themes
>>> themes_path = sphinx_themes.get_path_sphinx_themes()
"""
import easydev
sharedir = easydev.get_shared_directory_path("easydev")
sharedir = os.path.join(sharedir, "themes")
return sharedir
def get_sphinx_themes():
"""Returns the sphinx themes found in easydev
.. doctest::
>>> from easydev import sphinx_themes
>>> themes = sphinx_themes.get_sphinx_themes()
>>> "standard" in themes
True
"""
from easydev import get_shared_directory_path
sharedir = get_shared_directory_path("easydev")
sharedir = pj(sharedir, "themes")
themes = [x for x in os.listdir(sharedir) if x.startswith(".") == False]
return themes
easydev-0.9.35/easydev/progressbar.py 0000664 0001750 0001750 00000013346 13130514143 021213 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2017
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://easydev-python.readthedocs.io
#
##############################################################################
"""A progress bar copied and adapted from pyMC code (dec 2014)"""
from __future__ import print_function
import sys
import time
import uuid
try:
from IPython.core.display import HTML, Javascript, display
except ImportError:
pass
__all__ = ['progress_bar', 'TextProgressBar', 'Progress']
class ProgressBar(object):
def __init__(self, iterations, interval=None):
self.iterations = iterations
# if no interval provided, set it to 1%
if interval is None:
if iterations <= 100:
interval = 1 # everything % of the data
else:
interval = int(iterations/100)
self.interval = interval
self.start = time.time()
self.last = 0
def _percentage(self, i):
if self.iterations !=0:
return 100 * i / float(self.iterations)
else:
# could be 100 ?
return 100
def _get_elapsed(self):
return time.time() - self.start
elapsed = property(_get_elapsed)
class TextProgressBar(ProgressBar):
"""Use :class:`Progress`"""
def __init__(self, iterations, printer, width=40, interval=None):
self.fill_char = '-'
self.width = width
self.printer = printer
ProgressBar.__init__(self, iterations, interval=interval)
def animate(self, i, dummy=None):
# dummy=None is for back-compatibility
if dummy is not None:
print("second argument in easydev.progress_bar.animate is deprecated. Update your code")
# +1 if i starts at 0 and finishes at N-1
if divmod(i, self.interval)[1] != 0 and i != self.iterations:
pass
else:
self.printer(self.progbar(i))
def progbar(self, i):
# +1 if i starts at 0 and finishes at N-1
bar = self.bar(self._percentage(i))
return "[%s] %i of %i complete in %.1f sec" % (
bar, (i), self.iterations, round(self.elapsed, 1))
def bar(self, percent):
all_full = self.width - 2
num_hashes = int(percent / 100 * all_full)
bar = self.fill_char * num_hashes + ' ' * (all_full - num_hashes)
info = '%d%%' % percent
loc = (len(bar) - len(info)) // 2
return replace_at(bar, info, loc, loc + len(info))
def replace_at(str, new, start, stop):
return str[:start] + new + str[stop:]
def consoleprint(s):
if sys.platform.lower().startswith('win'):
print(s, '\r', end='')
else:
print('\r', s, end='')
sys.stdout.flush()
def ipythonprint(s):
print('\r', s, end='')
sys.stdout.flush()
class IPythonNotebookPB(ProgressBar):
"""Use :class:`Progress`"""
def __init__(self, iterations, interval=None):
self.divid = str(uuid.uuid4())
self.sec_id = str(uuid.uuid4())
pb = HTML(
"""
""" % (self.divid, self.sec_id))
display(pb)
ProgressBar.__init__(self, iterations, interval=interval)
def animate(self, i, dummy=None):
if dummy is not None:
print("second argument in easydev.progress_bar.animate is deprecated. Update your code")
# +1 if i starts at 0 and finishes at N-1
if divmod(i, self.interval)[1] != 0 and i != self.iterations :
pass
else:
percentage = self._percentage(i)
fraction = percentage
display(
Javascript("$('div#%s').width('%i%%')" %
(self.divid, percentage)))
display(
Javascript("$('label#%s').text('%i%% in %.1f sec')" %
(self.sec_id, fraction, round(self.elapsed, 1))))
def _run_from_ipython():
try:
__IPYTHON__
return True
except NameError:
return False
def progress_bar(iters, interval=None):
"""A progress bar for Python/IPython/IPython notebook
:param int iters: number of iterations (steps in the loop)
:param interval: number of intervals to use to update the progress bar (20
by default)
::
from easydev import progress_bar
pb = progress_bar(10)
for i in range(1,10):
import time
time.sleep(0.1)
pb.animate(i)
"""
if _run_from_ipython():
from easydev.misc import in_ipynb
if in_ipynb() is True:
return IPythonNotebookPB(iters, interval=interval)
else:
return TextProgressBar(iters, printer=ipythonprint,
interval=interval)
else:
return TextProgressBar(iters, printer=consoleprint,
interval=interval)
class Progress(object):
"""Generic progress bar for python, IPython, IPython notebook
::
from easydev import Progress
pb = Progress(100, interval=1)
pb.animate(10)
"""
def __init__(self, iters, interval=None):
self.pb = progress_bar(iters, interval=interval)
def animate(self, i):
self.pb.animate(i)
def _get_elapsed(self):
return self.pb.elapsed
elapsed = property(_get_elapsed)
easydev-0.9.35/easydev/doc.py 0000664 0001750 0001750 00000001747 13036730423 017437 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2017
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://easydev-python.readthedocs.io
#
##############################################################################
"""Module related to documentation
.. testsetup::
from easydev.doc import *
"""
__all__ = ["underline"]
def underline(text, symbol="="):
"""Underlines a string with a specific character
:param str text: the text to underline
:param str symbol: the character to be used to underline the text
:return: underlined text.
.. doctest::
>>> print(underline("test"))
test
====
"""
length = len(text)
return text + "\n" + length * symbol
easydev-0.9.35/easydev/paths.py 0000664 0001750 0001750 00000011403 13036730423 017777 0 ustar cokelaer cokelaer 0000000 0000000 # -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2017
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://easydev-python.readthedocs.io
#
##############################################################################
# -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2011-2017
#
# File author(s): Thomas Cokelaer
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# Documentation: http://easydev-python.readthedocs.io
#
##############################################################################
# $:Id $
"""Utilities to ease access to share data paths"""
import os
from os.path import join as pj
import pkg_resources
__all__ = ["get_shared_directory_path", "get_shared_directories",
"get_share_file", "gsf", "get_package_location"]
def get_package_location(package):
"""Return physical location of a package"""
try:
info = pkg_resources.get_distribution(package)
location = info.location
except pkg_resources.DistributionNotFound as err:
print("package provided (%s) not installed." % package)
raise
return location
def get_shared_directory_path(package):
"""Returns the share directory path of an installed package
::
sharedir = get_shared_directory_path("easydev")
"""
location = get_package_location(package)
#print("install mode ? ")
sharedir = os.path.realpath(pj(location, package, 'share'))
if os.path.isdir(sharedir) == True:
# looks like we have found the share directory so it is an install mode
#print ("yes")
return sharedir
else:
#print("no. searching for share dir as if in develop mode")
# let us try a couple of directories
# FIXME: do we need the 3 cases ??
# probably just 2 are required, one for develop and one for install mode
sharedir = os.path.realpath(pj(location, '..', 'share'))
if os.path.isdir(sharedir) == True:
return sharedir
sharedir = os.path.realpath(pj(location, '..', '..', 'share'))
if os.path.isdir(sharedir) == True:
return sharedir
sharedir = os.path.realpath(pj(location, '..', '..', '..', 'share'))
if os.path.isdir(sharedir) == True:
return sharedir
# could not be found,
sharedir = []
print("could not find any share directory in %s" % package)
return sharedir
def get_shared_directories(package, datadir="data"):
"""Returns all directory paths found in the package share/datadir directory
:param str datadir: scans package/share/ where datadir is "data" by
default. If it does not exists, the list returned is empty.
.. doctest::
>>> from easydev import get_shared_directories
>>> shared_directories = get_shared_directories("easydev", "themes")
>>> len(shared_directories)>=2
True
"""
packagedir = get_shared_directory_path(package)
if len(packagedir) == 0:
return []
packagedir = pj(packagedir, datadir)
directories = os.listdir(packagedir)
# get rid of .svn (for the packages installed with develop)
directories_to_process = []
for directory in directories:
fullpath = os.path.join(packagedir,directory)
if directory != '.svn' and os.path.isdir(fullpath):
directories_to_process.append(fullpath)
directories_to_process.sort()
return directories_to_process
def gsf(package, datadir, filename):
return get_share_file(package, datadir, filename)
def get_share_file(package, datadir, filename):
"""Creates the full path of a file to be found in the share directory of a package
"""
packagedir = get_shared_directory_path(package)
fullpath = os.path.join(packagedir, datadir)
# check that it exists
if os.path.isdir(fullpath) == False:
raise ValueError("The directory %s in package %s does not seem to exist" % (packagedir, fullpath))
filename_path = os.path.join(fullpath, filename)
if os.path.isfile(filename_path)==False:
correct_files = [x for x in os.listdir(fullpath) if os.path.isfile(x)]
msg = "The file %s does not exists. Correct filenames found in %s/%s are:\n" % (filename_path, package, datadir)
for f in correct_files:
msg += "%s\n" % f
raise ValueError(msg)
return filename_path
easydev-0.9.35/easydev/share/ 0000775 0001750 0001750 00000000000 13131155451 017407 5 ustar cokelaer cokelaer 0000000 0000000 easydev-0.9.35/easydev/share/__pycache__/ 0000775 0001750 0001750 00000000000 13131155451 021617 5 ustar cokelaer cokelaer 0000000 0000000 easydev-0.9.35/easydev/share/__pycache__/__init__.cpython-35.pyc 0000664 0001750 0001750 00000000217 12701446454 026013 0 ustar cokelaer cokelaer 0000000 0000000
GW @ s d S)N r r r s easydev-0.9.35/easydev/share/copybutton.js 0000664 0001750 0001750 00000005260 13002651721 022154 0 ustar cokelaer cokelaer 0000000 0000000 $(document).ready(function() {
/* Add a [>>>] button on the top-right corner of code samples to hide
* the >>> and ... prompts and the output and thus make the code
* copyable. */
var div = $('.highlight-python .highlight,' +
'.highlight-python3 .highlight'
)
var pre = div.find('pre');
// get the styles from the current theme
pre.parent().parent().css('position', 'relative');
var hide_text = 'Hide the prompts and output';
var show_text = 'Show the prompts and output';
var border_width = pre.css('border-top-width');
var border_style = pre.css('border-top-style');
var border_color = pre.css('border-top-color');
var button_styles = {
'cursor':'pointer', 'position': 'absolute', 'top': '0', 'right': '0',
'border-color': border_color, 'border-style': border_style,
'border-width': border_width, 'color': border_color, 'text-size': '75%',
'font-family': 'monospace', 'padding-left': '0.2em', 'padding-right': '0.2em',
'border-radius': '0 3px 0 0'
}
// create and add the button to all the code blocks that contain >>>
div.each(function(index) {
var jthis = $(this);
if (jthis.find('.gp').length > 0) {
var button = $('>>>');
button.css(button_styles)
button.attr('title', hide_text);
button.data('hidden', 'false');
jthis.prepend(button);
}
// tracebacks (.gt) contain bare text elements that need to be
// wrapped in a span to work with .nextUntil() (see later)
jthis.find('pre:has(.gt)').contents().filter(function() {
return ((this.nodeType == 3) && (this.data.trim().length > 0));
}).wrap('');
});
// define the behavior of the button when it's clicked
$('.copybutton').click(function(e){
e.preventDefault();
var button = $(this);
if (button.data('hidden') === 'false') {
// hide the code output
button.parent().find('.go, .gp, .gt').hide();
button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'hidden');
button.css('text-decoration', 'line-through');
button.attr('title', show_text);
button.data('hidden', 'true');
} else {
// show the code output
button.parent().find('.go, .gp, .gt').show();
button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'visible');
button.css('text-decoration', 'none');
button.attr('title', hide_text);
button.data('hidden', 'false');
}
});
});
easydev-0.9.35/easydev/share/__init__.py 0000664 0001750 0001750 00000000000 12701443770 021514 0 ustar cokelaer cokelaer 0000000 0000000 easydev-0.9.35/easydev/share/themes/ 0000775 0001750 0001750 00000000000 13131155451 020674 5 ustar cokelaer cokelaer 0000000 0000000 easydev-0.9.35/easydev/share/themes/cno/ 0000775 0001750 0001750 00000000000 13131155451 021453 5 ustar cokelaer cokelaer 0000000 0000000 easydev-0.9.35/easydev/share/themes/cno/theme.conf 0000664 0001750 0001750 00000000741 12701443770 023434 0 ustar cokelaer cokelaer 0000000 0000000 [theme]
inherit = agogo
stylesheet = software.css
pygments_style = tango
[options]
bodyfont = "Verdana", Arial, sans-serif
headerfont = "Georgia", "Times New Roman", serif
pagewidth = 70em
documentwidth = 50em
sidebarwidth = 20em
bgcolor = #eeeeec
headerbg = url(bgtop.png) top left repeat-x
footerbg = url(bgfooter.png) top left repeat-x
linkcolor = #ce5c00
headercolor1 = #204a87
headercolor2 = #3465a4
headerlinkcolor = #fcaf3e
textalign = justify
homepage = 'user argument'
easydev-0.9.35/easydev/share/themes/cno/indexsidebar.html 0000664 0001750 0001750 00000001003 12701443770 025002 0 ustar cokelaer cokelaer 0000000 0000000 {% extends "!indexsidebar.html" %}