Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Landscape #655

Merged
merged 15 commits into from
Apr 30, 2024
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ computation related to assembly, annotation, and comparative genomics.
| ------- | ---------------------------------------------------------------- |
| Authors | Haibao Tang ([tanghaibao](http://github.com/tanghaibao)) |
| | Vivek Krishnakumar ([vivekkrish](https://github.com/vivekkrish)) |
| | Jingping Li ([Jingping](https://github.com/Jingping)) |
| | Xingtan Zhang ([tangerzhang](https://github.com/tangerzhang)) |
| | Won Cheol Yim ([wyim-pgl](https://github.com/wyim-pgl)) |
| Email | <[email protected]> |
| License | [BSD](http://creativecommons.org/licenses/BSD/) |

Expand Down
13 changes: 9 additions & 4 deletions jcvi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@
from pkg_resources import get_distribution, DistributionNotFound


__author__ = ("Haibao Tang", "Vivek Krishnakumar", "Jingping Li")
__copyright__ = "Copyright (c) 2010-{}, Haibao Tang".format(datetime.now().year)
__author__ = (
"Haibao Tang",
"Vivek Krishnakumar",
"Xingtan Zhang",
"Won Cheol Yim",
)
__copyright__ = f"Copyright (c) 2010-{datetime.now().year}, Haibao Tang"
__email__ = "[email protected]"
__license__ = "BSD"
__status__ = "Development"
Expand All @@ -14,10 +19,10 @@
except DistributionNotFound: # pragma: no cover
try:
from .version import version as VERSION # noqa
except ImportError: # pragma: no cover
except ImportError as exc: # pragma: no cover
raise ImportError(
"Failed to find (autogenerated) version.py. "
"This might be because you are installing from GitHub's tarballs, "
"use the PyPI ones."
)
) from exc
__version__ = VERSION
File renamed without changes.
115 changes: 44 additions & 71 deletions jcvi/apps/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,42 @@
"""

import errno
import fnmatch
import logging
import os
import time
import os.path as op
import shutil
import signal
import sys
import logging
import fnmatch
import time

from collections.abc import Iterable
from http.client import HTTPSConnection
from urllib.parse import urlencode
from configparser import (
ConfigParser,
RawConfigParser,
NoOptionError,
NoSectionError,
ParsingError,
)

from http.client import HTTPSConnection
from optparse import OptionGroup, OptionParser as OptionP, SUPPRESS_HELP
from socket import gethostname
from subprocess import PIPE, call, check_output
from optparse import OptionParser as OptionP, OptionGroup, SUPPRESS_HELP
from subprocess import CalledProcessError, PIPE, call, check_output
from time import ctime
from typing import Any, Collection, List, Optional, Tuple, Union

from urllib.parse import urlencode
from natsort import natsorted
from rich.console import Console
from rich.logging import RichHandler

from jcvi import __copyright__, __version__
from .. import __copyright__, __version__ as version

# http://newbebweb.blogspot.com/2012/02/python-head-ioerror-errno-32-broken.html
nobreakbuffer = lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL)
nobreakbuffer()
os.environ["LC_ALL"] = "C"
JCVIHELP = "JCVI utility libraries {} [{}]\n".format(__version__, __copyright__)

os.environ["LC_ALL"] = "C"
# http://newbebweb.blogspot.com/2012/02/python-head-ioerror-errno-32-broken.html
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
JCVIHELP = f"JCVI utility libraries {version} [{__copyright__}]\n"
TextCollection = Union[str, List[str], Tuple[str, ...]]


Expand All @@ -58,7 +58,9 @@ def debug(level=logging.DEBUG):


def get_logger(name: str, level: int = logging.DEBUG):
"""Return a logger with a default ColoredFormatter."""
"""
Return a logger with a default ColoredFormatter.
"""
logger = logging.getLogger(name)
if logger.hasHandlers():
logger.handlers.clear()
Expand Down Expand Up @@ -628,7 +630,9 @@ def set_image_options(
return opts, args, iopts

def set_dotplot_opts(self, theme: int = 2) -> OptionGroup:
"""Used in compara.catalog and graphics.dotplot"""
"""
Used in compara.catalog and graphics.dotplot
"""
from jcvi.graphics.base import set1

group = OptionGroup(self, "Dot plot parameters")
Expand Down Expand Up @@ -1002,42 +1006,15 @@ def set_annot_reformat_opts(self):
)

def set_home(self, prog, default=None):
tag = "--{0}_home".format(prog)
default = default or {
"amos": "~/code/amos-code",
"trinity": "~/export/trinityrnaseq-2.0.6",
"hpcgridrunner": "~/export/hpcgridrunner-1.0.2",
"cdhit": "~/export/cd-hit-v4.6.1-2012-08-27",
"maker": "~/export/maker",
"augustus": "~/export/maker/exe/augustus",
"pasa": "~/export/PASApipeline-2.0.2",
"gatk": "~/export",
"gmes": "~/export/gmes",
"gt": "~/export/genometools",
"sspace": "~/export/SSPACE-STANDARD-3.0_linux-x86_64",
"gapfiller": "~/export/GapFiller_v1-11_linux-x86_64",
"pbjelly": "~/export/PBSuite_15.2.20",
"picard": "~/export/picard-tools-1.138",
"khmer": "~/export/khmer",
"tassel": "/usr/local/projects/MTG4/packages/tassel",
"tgi": "~/export/seqclean-x86_64",
"eddyyeh": "/home/shared/scripts/eddyyeh",
"fiona": "~/export/fiona-0.2.0-Linux-x86_64",
"fermi": "~/export/fermi",
"lobstr": "/mnt/software/lobSTR",
"shapeit": "/mnt/software/shapeit",
"impute": "/mnt/software/impute",
"beagle": "java -jar /mnt/software/beagle.14Jan16.841.jar",
"minimac": "/mnt/software/Minimac3/bin",
}.get(prog, None)
tag = f"--{prog}_home"
if default is None: # Last attempt at guessing the path
try:
default = op.dirname(which(prog))
except:
default = None
else:
default = op.expanduser(default)
help = "Home directory for {0}".format(prog.upper())
help = f"Home directory for {prog.upper()}"
self.add_option(tag, default=default, help=help)

def set_aligner(self, aligner="bowtie"):
Expand All @@ -1053,17 +1030,17 @@ def set_verbose(self, help="Print detailed reports"):
def ConfigSectionMap(Config, section):
"""
Read a specific section from a ConfigParser() object and return
a dict() of all key-value pairs in that section
a dict of all key-value pairs in that section
"""
cfg = {}
options = Config.options(section)
for option in options:
try:
cfg[option] = Config.get(section, option)
if cfg[option] == -1:
logger.debug("skip: %s", option)
logger.debug("Skip: %s", option)
except:
logger.debug("exception on %s!", option)
logger.error("Exception on %s", option)
cfg[option] = None
return cfg

Expand All @@ -1085,7 +1062,13 @@ def get_abs_path(link_name):


datadir = get_abs_path(op.join(op.dirname(__file__), "../utils/data"))
datafile = lambda x: op.join(datadir, x)


def datafile(x: str, datadir: str = datadir):
"""
Return the full path to the data file in the data directory.
"""
return op.join(datadir, x)


def splitall(path):
Expand Down Expand Up @@ -1466,9 +1449,8 @@ def download(
str: Local file name.
"""
from urllib.parse import urlsplit
from subprocess import CalledProcessError

scheme, netloc, path, query, fragment = urlsplit(url)
_, _, path, _, _ = urlsplit(url)
basepath = op.basename(path)
if basepath:
url_gzipped = basepath.endswith(".gz")
Expand Down Expand Up @@ -1546,14 +1528,14 @@ def getfilesize(filename, ratio=None):

def main():
actions = (
("expand", "move files in subfolders into the current folder"),
("less", "enhance the unix `less` command"),
("mdownload", "multiple download a list of files"),
("mergecsv", "merge a set of tsv files"),
("notify", "send an email/push notification"),
("timestamp", "record timestamps for all files in the current folder"),
("expand", "move files in subfolders into the current folder"),
("touch", "recover timestamps for files in the current folder"),
("mdownload", "multiple download a list of files"),
("waitpid", "wait for a PID to finish and then perform desired action"),
("notify", "send an email/push notification"),
("mergecsv", "merge a set of tsv files"),
)
p = ActionDispatcher(actions)
p.dispatch(globals())
Expand All @@ -1569,7 +1551,7 @@ def mdownload(args):
from jcvi.apps.grid import Jobs

p = OptionParser(mdownload.__doc__)
opts, args = p.parse_args(args)
_, args = p.parse_args(args)

if len(args) != 1:
sys.exit(not p.print_help())
Expand Down Expand Up @@ -1630,13 +1612,13 @@ def timestamp(args):
This file can be used later to recover previous timestamps through touch().
"""
p = OptionParser(timestamp.__doc__)
opts, args = p.parse_args(args)
_, args = p.parse_args(args)

if len(args) != 1:
sys.exit(not p.print_help())

(path,) = args
for root, dirs, files in os.walk(path):
for root, _, files in os.walk(path):
for f in files:
filename = op.join(root, f)
atime, mtime = get_times(filename)
Expand All @@ -1650,10 +1632,8 @@ def touch(args):
Recover timestamps for files in the current folder.
CAUTION: you must execute this in the same directory as timestamp().
"""
from time import ctime

p = OptionParser(touch.__doc__)
opts, args = p.parse_args(args)
_, args = p.parse_args(args)

if len(args) != 1:
sys.exit(not p.print_help())
Expand Down Expand Up @@ -1707,7 +1687,7 @@ def less(args):
from jcvi.formats.base import must_open

p = OptionParser(less.__doc__)
opts, args = p.parse_args(args)
_, args = p.parse_args(args)

if len(args) != 2:
sys.exit(not p.print_help())
Expand Down Expand Up @@ -2019,7 +1999,6 @@ def pid_exists(pid):
"""Check whether pid exists in the current process table."""
if pid < 0:
return False
import errno

try:
os.kill(pid, 0)
Expand Down Expand Up @@ -2137,13 +2116,6 @@ def waitpid(args):
if len(args) == 0:
sys.exit(not p.print_help())

if not opts.message:
"""
If notification message not specified by user, just get
the name of the running command and use it as the message
"""
from subprocess import check_output

sep = ":::"
cmd = None
if sep in args:
Expand Down Expand Up @@ -2269,7 +2241,8 @@ def inspect(object):


def sample_N(a: Collection[Any], N: int, seed: Optional[int] = None) -> List[Any]:
"""When size of N is > size of a, random.sample() will emit an error:
"""
When size of N is > size of a, random.sample() will emit an error:
ValueError: sample larger than population

This method handles such restrictions by repeatedly sampling when that
Expand Down
Loading