Mercurial > repos > vimalkumarvelayudhan > riboplot
changeset 11:7571f5c89090
Simple error message now output to HTML. Detailed error goes to standard error.
Other changes:
* Remove information on time taken (riboplot).
* Remove striped table styles (not used. unusable on sorting).
* log before re-raising errors.
author | Vimalkumar Velayudhan <vimal@biotechcoder.com> |
---|---|
date | Wed, 19 Aug 2015 10:14:52 +0100 |
parents | 8964641b04ef |
children | 61c47a1d6a7a |
files | .hgignore data/ribocount.html docs/_static/alabaster.css_t docs/_styles/custom.style docs/_styles/fonts/Cabin-Bold.ttf docs/_styles/fonts/Cabin-BoldItalic.ttf docs/_styles/fonts/Cabin-Italic.ttf docs/_styles/fonts/Cabin-Regular.ttf docs/_styles/fonts/SourceSansPro-Bold.ttf docs/_styles/fonts/SourceSansPro-BoldItalic.ttf docs/_styles/fonts/SourceSansPro-Italic.ttf docs/_styles/fonts/SourceSansPro-Regular.ttf docs/_templates/about.html docs/_templates/layout.html docs/_templates/searchbox.html docs/modules.rst docs/riboplot.rst riboplot.egg-info/PKG-INFO riboplot.egg-info/SOURCES.txt riboplot/__init__.py riboplot/ribocore.py riboplot/ribocount.py riboplot/riboplot.py run_coverage.sh |
diffstat | 24 files changed, 918 insertions(+), 87 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Mon Aug 17 10:51:58 2015 +0100 +++ b/.hgignore Wed Aug 19 10:14:52 2015 +0100 @@ -2,5 +2,12 @@ *.pyc *.swp .git* +.ropeproject +.coverage +build +dist +docs/_build +htmlcov tests/data/*.bam* tests/data/*.fna* +riboplot/riboplot_multi.py
--- a/data/ribocount.html Mon Aug 17 10:51:58 2015 +0100 +++ b/data/ribocount.html Wed Aug 19 10:14:52 2015 +0100 @@ -53,7 +53,6 @@ {table_content} </tbody> </table> - <p class="text-muted">Time taken for generating counts (H:MM:SS): {duration}</p> </div> </div> </div> @@ -61,4 +60,4 @@ <script type="text/javascript" src="js/jquery.tablesorter.min.js"></script> <script type="text/javascript" src="js/custom.js"></script> </body> -</html> \ No newline at end of file +</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/_static/alabaster.css_t Wed Aug 19 10:14:52 2015 +0100 @@ -0,0 +1,612 @@ +{% set sidebar_width = '300px' %} + +{% set theme_sidebar_header = theme_sidebar_header or theme_gray_1 %} +{% set theme_sidebar_link = theme_sidebar_link or theme_gray_1 %} +{% set theme_anchor_hover_fg = theme_anchor_hover_fg or theme_gray_1 %} + +{% set theme_note_bg = theme_note_bg or theme_gray_2 %} +{% set theme_footnote_border = theme_footnote_border or theme_gray_2 %} +{% set theme_pre_bg = theme_pre_bg or theme_gray_2 %} + +{% set theme_warn_bg = theme_warn_bg or theme_pink_1 %} +{% set theme_warn_border = theme_warn_border or theme_pink_2 %} + +{% set theme_seealso_bg = theme_seealso_bg or theme_gray_2 %} + +{% set theme_narrow_sidebar_link = theme_narrow_sidebar_link or theme_gray_3 %} +{% set theme_sidebar_hr = theme_sidebar_hr or theme_gray_3 %} + + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +html { + position: relative; + min-height: 100%; +} + +body { + font-family: {{ theme_font_family }}; + font-weight: 300; + font-size: 18px; + line-height: 1.6; + background-color: #ffffff; + color: #333; + margin: 20px 0px 50px 0px; + padding: 0; +} + +div.document { + margin: 0px 30px; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 320px; + padding-left: 1px; + border-left: 1px dotted #f0f0f0; +} + +div.sphinxsidebar { + width: {{ sidebar_width }}; +} + +hr { + border: 1px solid #B1B4B6; +} + +div.body { + background-color: #ffffff; + color: {{ theme_body_text }}; + padding: 0 30px 0 30px; +} + +div.footer { + position: absolute; + bottom: 0; + width: 100%; + height: 50px; + font-size: 0.4em; + color: {{ theme_footer_text }}; + text-align: center; +} + +div.footer a { + color: {{ theme_footer_text }}; +} + +div.related { + display: none; +} + +div.sphinxsidebar a { + color: {{ theme_link }}; + text-decoration: none; + /*border-bottom: 1px dotted {{ theme_sidebar_link_underscore }};*/ +} + +div.sphinxsidebar a:hover { + border-bottom: 1px solid {{ theme_sidebar_link_underscore }}; +} + +div.sphinxsidebar { + font-size: 16px; + line-height: 1.5; +} + +div.sphinxsidebarwrapper { + padding: 18px 10px; +} + +div.sphinxsidebarwrapper p.logo { + padding: 0; + margin: -10px 0 0 0px; + text-align: center; +} + +div.sphinxsidebarwrapper h1.logo { + margin-top: -10px; + text-align: center; + margin-bottom: 20px; + text-align: {{ theme_logo_text_align }}; + font-family: {{ theme_head_font_family }} +} + +div.sphinxsidebarwrapper h1.logo-name { + margin-top: 0px; +} + +div.sphinxsidebarwrapper p.blurb { + margin-top: 0; + font-style: {{ theme_description_font_style }}; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: {{ theme_head_font_family }}; + color: {{ theme_sidebar_header }}; + font-size: 24px; + font-weight: normal; + margin: 0 0 5px 0; + padding: 0; +} + +div.sphinxsidebar h4 { + font-size: 20px; +} + +div.sphinxsidebar h3 a { + color: {{ theme_link }}; +} + +div.sphinxsidebar p.logo a, +div.sphinxsidebar h3 a, +div.sphinxsidebar p.logo a:hover, +div.sphinxsidebar h3 a:hover { + border: none; +} + +div.sphinxsidebar p { + color: {{ theme_sidebar_text }}; + margin: 10px 0; +} + +div.sphinxsidebar ul { + margin: 10px 0; + padding: 0; + color: {{ theme_sidebar_list }}; +} + +div.sphinxsidebar ul li.toctree-l1 > a { + font-size: 120%; +} + +div.sphinxsidebar ul li.toctree-l2 > a { + font-size: 110%; +} + +div.sphinxsidebar input { + border: 1px solid {{ theme_sidebar_search_button }}; + font-family: {{ theme_font_family }}; + font-size: 1.1em; +} + +div.sphinxsidebar hr { + border: none; + height: 1px; + color: {{ theme_sidebar_link_underscore }}; + background: {{ theme_sidebar_link_underscore }}; + + text-align: left; + margin-left: 0; + width: 50%; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: {{ theme_link }}; + text-decoration: underline; +} + +a:hover { + color: {{ theme_link_hover }}; + text-decoration: underline; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: {{ theme_head_font_family }}; + font-weight: 400; + line-height: 1.4; + margin: 30px 0px 10px 0px; + padding: 0; + color: #666; +} + +div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } +div.body h2 { font-size: 180%; } +div.body h3 { font-size: 150%; } +div.body h4 { font-size: 130%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: {{ theme_anchor }}; + padding: 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + color: {{ theme_anchor_hover_fg }}; + background: {{ theme_anchor_hover_bg }}; +} + +div.admonition { + margin: 20px 0px; + padding: 10px 30px; + background-color: {{ theme_warn_bg }}; + border: 1px solid {{ theme_warn_border }}; +} + +div.admonition tt.xref, div.admonition a tt { + border-bottom: 1px solid #fafafa; +} + +dd div.admonition { + margin-left: -60px; + padding-left: 60px; +} + +div.admonition p.admonition-title { + margin: 0 0 10px 0; + padding: 0; + line-height: 1; +} + +div.admonition p.last { + margin-bottom: 0; +} + +div.highlight { + background-color: white; +} + +dt:target, .highlight { + background: #FAF3E8; +} + +div.note { + background-color: {{ theme_note_bg }}; + border: 1px solid {{ theme_note_border }}; +} + +div.seealso { + background-color: {{ theme_seealso_bg }}; + border: 1px solid {{ theme_seealso_border }}; +} + +div.topic { + background-color: #eee; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +em { + color: #313131; +} + +pre, tt, code { + font-family: {{theme_code_font_family}}; + font-size: {{ theme_code_font_size }}; + font-weight: 400; +} + +img.screenshot { +} + +tt.descname, tt.descclassname, code.descname, code.descclassname { + font-size: 0.95em; +} + +tt.descname, code.descname { + padding-right: 0.08em; +} + +img.screenshot { + -moz-box-shadow: 2px 2px 4px #eee; + -webkit-box-shadow: 2px 2px 4px #eee; + box-shadow: 2px 2px 4px #eee; +} + +table.docutils { + border: 1px solid #888; + -moz-box-shadow: 2px 2px 4px #eee; + -webkit-box-shadow: 2px 2px 4px #eee; + box-shadow: 2px 2px 4px #eee; +} + +table.docutils td, table.docutils th { + border: 1px solid #888; + padding: 0.25em 0.7em; +} + +table.field-list, table.footnote { + border: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +table.footnote { + margin: 15px 0; + width: 100%; + border: 1px solid {{ theme_footnote_border }}; + background: {{ theme_footnote_bg }}; + font-size: 0.9em; +} + +table.footnote + table.footnote { + margin-top: -15px; + border-top: none; +} + +table.field-list th { + padding: 0 0.8em 0 0; +} + +table.field-list td { + padding: 0; +} + +table.footnote td.label { + width: 0px; + padding: 0.3em 0 0.3em 0.5em; +} + +table.footnote td { + padding: 0.3em 0.5em; +} + +dl { + margin: 0; + padding: 0; +} + +dl dd { + margin-left: 30px; +} + +blockquote { + margin: 0 0 0 30px; + padding: 0; +} + +ul, ol { + margin: 10px 0 10px 30px; + padding: 0; +} + +pre { + background: {{ theme_pre_bg }}; + padding: 7px 30px; + margin: 15px 0px; + line-height: 1.3em; +} + +dl pre, blockquote pre, li pre { + margin-left: -60px; + padding-left: 60px; +} + +dl dl pre { + margin-left: -90px; + padding-left: 90px; +} + +tt, code { + background-color: {{ theme_pre_bg }}; + color: #444; + /* padding: 1px 2px; */ +} + +tt.xref, code.xref, a tt { + background-color: #FBFBFB; + border-bottom: 1px solid white; +} + +a.reference { + text-decoration: none; + color: {{ theme_link }} +} + +a.reference:hover { + color: {{ theme_link_hover }}; + border-bottom: 1px solid {{ theme_link_hover }}; +} + +a.footnote-reference { + text-decoration: none; + font-size: 0.7em; + vertical-align: top; + border-bottom: 1px dotted {{ theme_link }}; +} + +a.footnote-reference:hover { + border-bottom: 1px solid {{ theme_link_hover }}; +} + +a:hover tt, a:hover code { + background: #EEE; +} + + +@media screen and (max-width: 870px) { + + div.sphinxsidebar { + display: none; + } + + div.document { + width: 100%; + + } + + div.documentwrapper { + margin-left: 0; + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + } + + div.bodywrapper { + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + margin-left: 0; + border-left: 0px; + } + + ul { + margin-left: 0; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .bodywrapper { + margin: 0; + } + + .footer { + width: auto; + } + + .github { + display: none; + } + + + +} + + + +@media screen and (max-width: 875px) { + + body { + margin: 0; + padding: 20px 30px; + } + + div.documentwrapper { + float: none; + background: white; + } + + div.sphinxsidebar { + display: block; + float: none; + width: 102.5%; + margin: 50px -30px -20px -30px; + padding: 10px 20px; + background: {{ theme_narrow_sidebar_bg }}; + color: {{ theme_narrow_sidebar_fg }}; + } + + div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, + div.sphinxsidebar h3 a { + color: white; + } + + div.sphinxsidebar a { + color: {{ theme_narrow_sidebar_link }}; + } + + div.sphinxsidebar p.logo { + display: none; + } + + div.document { + width: 100%; + margin: 0; + } + + div.related { + display: block; + margin: 0; + padding: 10px 0 20px 0; + } + + div.related ul, + div.related ul li { + margin: 0; + padding: 0; + } + + div.footer { + display: none; + } + + div.bodywrapper { + margin: 0; + } + + div.body { + min-height: 0; + padding: 0; + } + + .rtd_doc_footer { + display: none; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .footer { + width: auto; + } + + .github { + display: none; + } +} + + +/* misc. */ + +.revsys-inline { + display: none!important; +} + +/* Make nested-list/multi-paragraph items look better in Releases changelog + * pages. Without this, docutils' magical list fuckery causes inconsistent + * formatting between different release sub-lists. + */ +div#changelog > div.section > ul > li > p:only-child { + margin-bottom: 0; +} + +/* Hide fugly table cell borders in ..bibliography:: directive output */ +table.docutils.citation, table.docutils.citation td, table.docutils.citation th { + border:none; +} + +#searchbox { + margin-top: 1.5em; + margin-bottom: 1.5em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + width: 220px; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + width: 40px; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/_styles/custom.style Wed Aug 19 10:14:52 2015 +0100 @@ -0,0 +1,33 @@ + { + "fontsAlias" : { + "stdFont": "Open Sans :style=Regular", + "stdBold": "Open Sans :style=Bold", + "stdItalic": "Open Sans :style=Italic", + "stdBoldItalic": "Open Sans :style=Bold Italic", + "stdMono": "Source Code Pro", + "stdMonoItalic": "Source Code Pro", + "stdMonoBold": "Source Code Pro", + "stdMonoBoldItalic": "Source Code Pro" + }, + "styles": { + "base": { + "leading": 14 + }, + "literal": { + "backColor": "#fffce6", + "fontSize": 9 + }, + "code": { + "backColor": "#f9f9f9", + "borderColor": "#f1f1f1", + "fontSize": 9 + }, + "admonition": { + "backColor": "#f9f9f9" + }, + "note": { + "backColor": "#e6f7ff", + "borderColor": "#ccefff" + } + } + } \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/_templates/about.html Wed Aug 19 10:14:52 2015 +0100 @@ -0,0 +1,1 @@ +<h1 class="logo"><a href="{{ pathto(master_doc) }}">{{ project }}</a></h1>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/_templates/layout.html Wed Aug 19 10:14:52 2015 +0100 @@ -0,0 +1,53 @@ +{%- extends "basic/layout.html" %} +{%- block extrahead %} + {{ super() }} + {% if theme_touch_icon %} + <link rel="apple-touch-icon" href="{{ pathto('_static/' ~ theme_touch_icon, 1) }}" /> + {% endif %} + <meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9"> +{% endblock %} +{%- block relbar2 %}{% endblock %} +{%- block footer %} + <div class="footer"> + <small> + {%- if last_updated %} + {% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %} + {%- endif %} + </small> + + {% if theme_show_powered_by|lower == 'true' %} + | + Powered by <a href="http://sphinx-doc.org/">Sphinx {{ sphinx_version }}</a> + & <a href="https://github.com/bitprophet/alabaster">Alabaster {{ alabaster_version }}</a> + {% endif %} + {%- if show_source and has_source and sourcename %} + | + <a href="{{ pathto('_sources/' + sourcename, true)|e }}" + rel="nofollow">{{ _('Page source') }}</a></li> + {%- endif %} + </div> + + {% if theme_github_banner|lower != 'false' %} + <a href="https://github.com/{{ theme_github_user }}/{{ theme_github_repo }}" class="github"> + <img style="position: absolute; top: 0; right: 0; border: 0;" src="{{ pathto('_static/' ~ theme_github_banner, 1) if theme_github_banner|lower != 'true' else 'http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png' }}" alt="Fork me on GitHub" class="github"/> + </a> + {% endif %} + + {% if theme_analytics_id %} + <script type="text/javascript"> + + var _gaq = _gaq || []; + _gaq.push(['_setAccount', '{{ theme_analytics_id }}']); + _gaq.push(['_setDomainName', 'none']); + _gaq.push(['_setAllowLinker', true]); + _gaq.push(['_trackPageview']); + + (function() { + var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; + ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; + var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); + })(); + + </script> + {% endif %} +{%- endblock %}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/_templates/searchbox.html Wed Aug 19 10:14:52 2015 +0100 @@ -0,0 +1,21 @@ +{# + basic/searchbox.html + ~~~~~~~~~~~~~~~~~~~~ + + Sphinx sidebar template: quick search box. + + :copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +#} +{%- if pagename != "search" and builder != "singlehtml" %} +<div id="searchbox" style="display: none" role="search"> + <!--<h3>{{ _('Search') }}</h3>--> + <form class="search" action="{{ pathto('search') }}" method="get"> + <input type="text" name="q" placeholder="Search"/> + <input type="submit" value="{{ _('Go') }}" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> +{%- endif %}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/modules.rst Wed Aug 19 10:14:52 2015 +0100 @@ -0,0 +1,7 @@ +riboplot +======== + +.. toctree:: + :maxdepth: 4 + + riboplot
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/riboplot.rst Wed Aug 19 10:14:52 2015 +0100 @@ -0,0 +1,54 @@ +riboplot package +================ + +Submodules +---------- + +riboplot.config module +---------------------- + +.. automodule:: riboplot.config + :members: + :undoc-members: + :show-inheritance: + +riboplot.ribocore module +------------------------ + +.. automodule:: riboplot.ribocore + :members: + :undoc-members: + :show-inheritance: + +riboplot.ribocount module +------------------------- + +.. automodule:: riboplot.ribocount + :members: + :undoc-members: + :show-inheritance: + +riboplot.riboplot module +------------------------ + +.. automodule:: riboplot.riboplot + :members: + :undoc-members: + :show-inheritance: + +riboplot.riboplot_multi module +------------------------------ + +.. automodule:: riboplot.riboplot_multi + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: riboplot + :members: + :undoc-members: + :show-inheritance:
--- a/riboplot.egg-info/PKG-INFO Mon Aug 17 10:51:58 2015 +0100 +++ b/riboplot.egg-info/PKG-INFO Wed Aug 19 10:14:52 2015 +0100 @@ -27,7 +27,7 @@ **ribocount** Output read counts for all transcripts in an alignment. - For help on using these programs, please refer to :doc:`usage`. + For help on using these programs, please refer to :ref:`usage`. Free software: BSD license.
--- a/riboplot.egg-info/SOURCES.txt Mon Aug 17 10:51:58 2015 +0100 +++ b/riboplot.egg-info/SOURCES.txt Wed Aug 19 10:14:52 2015 +0100 @@ -32,6 +32,10 @@ riboplot.egg-info/top_level.txt tests/__init__.py tests/test_riboplot.py +tests/.ropeproject/config.py +tests/.ropeproject/globalnames +tests/.ropeproject/history +tests/.ropeproject/objectdb tests/data/5hRPF.bam tests/data/5hRPF.bam.bai tests/data/5hRPFsorted.bam
--- a/riboplot/__init__.py Mon Aug 17 10:51:58 2015 +0100 +++ b/riboplot/__init__.py Wed Aug 19 10:14:52 2015 +0100 @@ -2,4 +2,4 @@ __author__ = 'Vimalkumar Velayudhan' __email__ = 'vimalkumarvelayudhan@gmail.com' -__version__ = '0.1.0' \ No newline at end of file +__version__ = '0.1.0'
--- a/riboplot/ribocore.py Mon Aug 17 10:51:58 2015 +0100 +++ b/riboplot/ribocore.py Wed Aug 19 10:14:52 2015 +0100 @@ -4,6 +4,19 @@ import subprocess +# create logger for the entire program +log = logging.getLogger('riboplot') +log.setLevel(logging.DEBUG) + +# create console handler with a higher log level +ch = logging.StreamHandler() +ch.setLevel(logging.INFO) + +formatter = logging.Formatter('%(asctime)s - %(module)s %(levelname)s %(message)s', datefmt='%Y-%m-%d %H:%M:%S') +ch.setFormatter(formatter) +log.addHandler(ch) + + class ArgumentError(Exception): """Raised when invalid arguments are sent in the command line.""" pass @@ -33,6 +46,8 @@ f = pysam.AlignmentFile(bam_file) except ValueError: raise + except: + raise else: f.close() @@ -95,7 +110,9 @@ try: sequence, length = f.fetch(transcript), f.get_reference_length(transcript) except KeyError: - raise ArgumentError('Transcript "{}" does not exist in FASTA file "{}"'.format(transcript, fasta)) + msg = 'Transcript "{}" does not exist in transcriptome FASTA file'.format(transcript) + log.error(msg) + raise ArgumentError(msg) records[transcript] = {'sequence': sequence, 'length': length} f.close() return records @@ -129,38 +146,41 @@ return read_counts, total_reads + def check_required_arguments(ribo_file, transcriptome_fasta, transcript_name=None): """Check required arguments of both riboplot and ribocount.""" # Is this a valid BAM file? i.e., can pysam read it? try: is_bam_valid(ribo_file) except ValueError: - logging.error('The given RiboSeq BAM file is not valid') + log.error('The given RiboSeq BAM file is not valid') raise # Does the BAM file have an index? If not, create it. if not bam_has_index(ribo_file): - logging.info('Creating an index for the BAM file...') + log.info('Creating an index for the BAM file...') create_bam_index(ribo_file) # Is FASTA file valid? try: fasta_valid = is_fasta_valid(transcriptome_fasta) except IOError: - logging.error('This FASTA file is not valid -> {}'.format(transcriptome_fasta)) + log.error('Transcriptome FASTA file is not valid') + raise if fasta_valid and transcript_name: try: get_fasta_records(transcriptome_fasta, [transcript_name]) except IOError: - logging.error('This FASTA file is not valid -> {}'.format(transcriptome_fasta)) - raise - except ArgumentError: # does transcript exist in fasta? + log.error('Transcriptome FASTA file is not valid') raise with pysam.AlignmentFile(ribo_file, 'rb') as bam_file: if transcript_name not in bam_file.references: - raise ArgumentError('Transcript "{}" does not exist in BAM file'.format(transcript_name)) + msg = 'Transcript "{}" does not exist in BAM file'.format(transcript_name) + log.error(msg) + raise ArgumentError(msg) + def check_optional_arguments(ribo_file, read_length=None, read_offset=None, rna_file=None): """Check all optional arguments.""" @@ -168,28 +188,33 @@ try: subprocess.check_output(['bedtools', '--version']) except OSError: - logging.error('Could not find bedtools in PATH. bedtools is ' - 'required for generating RNA coverage plot.') + log.error('Could not find bedtools in PATH. bedtools is required' + 'for generating RNA coverage plot.') raise # Is this a valid BAM file? i.e., can pysam read it? try: is_bam_valid(rna_file) except ValueError: - logging.error('The given RNASeq BAM file is not valid') + log.error('The given RNASeq BAM file is not valid') raise # If read_length is given, it must be a positive integer or reads of that # length must exist in the BAM file if read_length: if read_length < 0: - raise ArgumentError('Read length must be a positive value') + msg = 'Read length must be a positive value' + log.error(msg) + raise ArgumentError(msg) bam_read_lengths = get_bam_read_lengths(ribo_file) if read_length not in bam_read_lengths: - raise ArgumentError('Reads of the length "{}" does not exist in the BAM file'.format(read_length)) + msg = 'Reads of the length "{}" does not exist in the BAM file'.format(read_length) + log.error(msg) + raise ArgumentError(msg) # If read_offset is given, it must be a positive integer if read_offset: if read_offset < 0: - raise ArgumentError('Read offset must be 0 or greater') - + msg = 'Read offset must be 0 or greater' + log.error(msg) + raise ArgumentError(msg)
--- a/riboplot/ribocount.py Mon Aug 17 10:51:58 2015 +0100 +++ b/riboplot/ribocount.py Wed Aug 19 10:14:52 2015 +0100 @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +"""ribocount""" import sys # check dependencies @@ -14,7 +15,6 @@ import zipfile import logging import argparse -from datetime import datetime import ribocore import config @@ -22,6 +22,15 @@ # Default is production CONFIG = config.ProductionConfig() +log = logging.getLogger('riboplot') + + +class ErrorLogFormatter(logging.Formatter): + """Custom error log format for the HTML file""" + + def format(self, record): + return '<h2>RiboCount Error</h2><p>{}</p>'.format(record.msg) + def create_parser(): """Argument parser. """ @@ -38,38 +47,35 @@ metavar='INTEGER', type=int) parser.add_argument('-s', '--read_offset', help='Read offset (default: %(default)s)', metavar='INTEGER', type=int, default=0) - parser.add_argument('-m', '--html_file', help='Output file for results (HTML)', default='output/index.html') + parser.add_argument('-m', '--html_file', help='Output file for results (HTML)', default='ribocount.html') parser.add_argument('-o', '--output_path', help='Files are saved in this directory', default='output') parser.add_argument('-d', '--debug', help='Flag. Produce debug output', action='store_true') return parser -if __name__ == '__main__': - parsed = create_parser() - args = parsed.parse_args() +def main(args): + """Main program""" + (ribo_file, transcriptome_fasta, read_length, read_offset, output_path, html_file) = ( + args.ribo_file, args.transcriptome_fasta, args.read_length, + args.read_offset, args.output_path, args.html_file) - if args.debug: - level = logging.DEBUG - else: - level = logging.INFO - - logging.basicConfig(format='%(levelname)s: %(message)s', - level=level, stream=sys.stdout, datefmt='%d/%m/%Y %I:%M:%S %p') + log.debug('Supplied arguments\n{}'.format( + '\n'.join(['{:<20}: {}'.format(k, v) for k, v in vars(args).items()]))) - start = datetime.now() - logging.debug('Supplied arguments\n{}'.format('\n'.join(['{:<20}: {}'.format(k, v) for k, v in vars(args).items()]))) - - (ribo_file, transcriptome_fasta, read_length, read_offset, output_path) = ( - args.ribo_file, args.transcriptome_fasta, args.read_length, args.read_offset, args.output_path) + # error messages (simple format) are written to html file + fh = logging.FileHandler(html_file) + fh.setLevel(logging.ERROR) + fh.setFormatter(ErrorLogFormatter('%(message)s')) + log.addHandler(fh) - logging.info('Checking if required arguments are valid...') + log.info('Checking if required arguments are valid...') ribocore.check_required_arguments(ribo_file=ribo_file, transcriptome_fasta=transcriptome_fasta) - logging.info('Done') + log.info('Done') - logging.info('Checking if optional arguments are valid...') + log.info('Checking if optional arguments are valid...') ribocore.check_optional_arguments(ribo_file=ribo_file, read_length=read_length, read_offset=read_offset) - logging.info('Done') + log.info('Done') if not os.path.exists(output_path): os.mkdir(output_path) @@ -84,17 +90,17 @@ if not os.path.exists(csv_dir): os.mkdir(csv_dir) - logging.info('Get RiboSeq read counts for all transcripts in FASTA') count = 0 table_content = '' bam_fileobj = pysam.AlignmentFile(ribo_file, 'rb') fasta_file = pysam.FastaFile(transcriptome_fasta) + log.info('Get RiboSeq read counts for all transcripts in FASTA') for transcript in fasta_file.references: rp_counts, rp_reads = ribocore.get_ribo_counts(bam_fileobj, transcript, read_length) if not rp_reads: # no reads for this transcript. skip. continue - logging.debug('Writing counts for {}'.format(transcript)) + log.debug('Writing counts for {}'.format(transcript)) count += 1 csv_file = 'RiboCounts{}.csv'.format(count) with open(os.path.join(csv_dir, csv_file), 'w') as f: @@ -106,12 +112,8 @@ pos, rp_counts[pos][1], rp_counts[pos][2], rp_counts[pos][3])) else: f.write('{0},{1},{2},{3}\n'.format(pos, 0, 0, 0)) - if count % 2 == 0: - table_content += '<tr>' - else: - table_content += '<tr class="odd">' - table_content += '<td>{0}</td><td>{1}</td><td>{2}</td><td><a href="csv/{3}">{3}</a></td></tr>'.format( - count, transcript, rp_reads, csv_file) + table_content += ('<tr><td>{0}</td><td>{1}</td><td>{2}</td><td><a href="csv/{3}">' + '{3}</a></td></tr>'.format(count, transcript, rp_reads, csv_file)) fasta_file.close() bam_fileobj.close() @@ -119,21 +121,17 @@ if not read_length: read_length = 'All' - duration = str(datetime.now() - start).split('.')[0] - logging.info('Done') + log.info('Done') if not count: if read_length: - logging.info('No transcripts found for read length {}'.format(read_length)) + log.info('No transcripts found for read length {}'.format(read_length)) else: - logging.info('No transcripts found') + log.info('No transcripts found') else: - logging.info('Time taken for generating counts for {0} transcripts: {1}, footprint ' - 'length: {2}'.format(count, duration, read_length)) - with open(os.path.join(CONFIG.DATA_DIR, 'ribocount.html')) as g,\ open(os.path.join(zip_dir, 'index.html'), 'w') as h: - h.write(g.read().format(count=count, length=read_length, table_content=table_content, duration=duration)) + h.write(g.read().format(count=count, length=read_length, table_content=table_content)) for asset in ('css', 'js'): asset_dir = os.path.join(zip_dir, asset) @@ -144,7 +142,7 @@ shutil.copy(os.path.join(asset_data_dir, fname), os.path.join(zip_dir, asset, fname)) - logging.info('Creating zip file') + log.info('Creating zip file') os.chdir(output_path) with zipfile.ZipFile('ribocount_output.zip', 'w') as zipf: for root, d, f in os.walk('ribocount_output'): @@ -152,8 +150,13 @@ zipf.write(os.path.join(root, name)) shutil.rmtree('ribocount_output') os.chdir('../') - logging.debug('Writing HTML report') + log.debug('Writing HTML report') with open(os.path.join(CONFIG.DATA_DIR, 'ribocount_index.html')) as j, open(args.html_file, 'w') as k: k.write(j.read().format(count=count, read_length=read_length)) - logging.info('Finished') + log.info('Finished') + +if __name__ == '__main__': + parsed = create_parser() + args = parsed.parse_args() + main(args)
--- a/riboplot/riboplot.py Mon Aug 17 10:51:58 2015 +0100 +++ b/riboplot/riboplot.py Wed Aug 19 10:14:52 2015 +0100 @@ -36,6 +36,16 @@ # Default is production CONFIG = config.ProductionConfig() +# create logger +log = logging.getLogger('riboplot') + + +class ErrorLogFormatter(logging.Formatter): + """Custom error log format for the HTML file""" + + def format(self, record): + return '<h2>RiboPlot Error</h2><p>{}</p>'.format(record.msg) + def get_start_stops(transcript_sequence, start_codons=None, stop_codons=None): """Return start and stop positions for all frames in the given @@ -245,7 +255,7 @@ metavar='INTEGER', type=int) parser.add_argument('-s', '--read_offset', help='Read offset (default: %(default)s)', metavar='INTEGER', type=int, default=0) - parser.add_argument('-m', '--html_file', help='Output file for results (HTML)', default='index.html') + parser.add_argument('-m', '--html_file', help='Output file for results (HTML)', default='riboplot.html') parser.add_argument('-o', '--output_path', help='Files are saved in this directory', default='output') parser.add_argument('-d', '--debug', help='Flag. Produce debug output', action='store_true') @@ -253,31 +263,32 @@ def main(args): - """Start program""" - if args.debug: - level = logging.DEBUG - else: - level = logging.INFO + """Main program""" + (ribo_file, rna_file, transcript_name, transcriptome_fasta, read_length, + read_offset, output_path, html_file) = ( + args.ribo_file, args.rna_file, args.transcript_name, args.transcriptome_fasta, + args.read_length, args.read_offset, args.output_path, args.html_file) - logging.basicConfig(format='%(levelname)s: %(message)s', - level=level, stream=sys.stdout, datefmt='%d/%m/%Y %I:%M:%S %p') - logging.debug('Supplied arguments\n{}'.format( + log.debug('Supplied arguments\n{}'.format( '\n'.join(['{:<20}: {}'.format(k, v) for k, v in vars(args).items()]))) - (ribo_file, rna_file, transcript_name, transcriptome_fasta, read_length, - read_offset, output_path) = (args.ribo_file, args.rna_file, - args.transcript_name, args.transcriptome_fasta, - args.read_length, args.read_offset, args.output_path) + # error messages (simple format) are written to html file + fh = logging.FileHandler(args.html_file) + fh.setLevel(logging.ERROR) + fh.setFormatter(ErrorLogFormatter('%(message)s')) + log.addHandler(fh) - logging.info('Checking if required arguments are valid...') + log.info('Checking if required arguments are valid...') ribocore.check_required_arguments(ribo_file=ribo_file, transcriptome_fasta=transcriptome_fasta, transcript_name=transcript_name) + log.info('Done') - logging.info('Checking if optional arguments are valid...') + log.info('Checking if optional arguments are valid...') ribocore.check_optional_arguments(ribo_file=ribo_file, read_length=read_length, read_offset=read_offset, rna_file=rna_file) + log.info('Done') - logging.info('Get ribo-seq read counts and total reads in Ribo-Seq...') + log.info('Get ribo-seq read counts and total reads in Ribo-Seq...') bam_fileobj = pysam.AlignmentFile(ribo_file, 'rb') ribo_counts, total_reads = ribocore.get_ribo_counts(bam_fileobj, transcript_name, read_length) bam_fileobj.close() @@ -285,37 +296,36 @@ if not ribo_counts: msg = ('No RiboSeq read counts for transcript {}. No plot will be ' 'generated!'.format(transcript_name)) - logging.error(msg) + log.error(msg) raise ribocore.RiboPlotError(msg) else: - logging.info('Get RNA counts for the given transcript...') + log.info('Get RNA counts for the given transcript...') mrna_counts = {} if rna_file: try: mrna_counts = get_rna_counts(rna_file, transcript_name) except OSError as e: - logging.error(e) + log.error(e) raise if not mrna_counts: - logging.warn('No RNA counts for this transcript from the given RNA Seq file. ' - 'RNA-Seq coverage will not be generated') - + log.warn('No RNA counts for this transcript from the given RNA Seq file. ' + 'RNA-Seq coverage will not be generated') else: - logging.debug('No RNA-Seq data provided. Not generating coverage') + log.debug('No RNA-Seq data provided. Not generating coverage') - logging.info('Get sequence and length of the given transcripts from FASTA file...') + log.info('Get sequence and length of the given transcripts from FASTA file...') fasta_records = ribocore.get_fasta_records(transcriptome_fasta, [transcript_name]) transcript_seq, transcript_length = (fasta_records[transcript_name]['sequence'], fasta_records[transcript_name]['length']) - logging.info('Get start/stop positions in transcript sequence (3 frames)...') + log.info('Get start/stop positions in transcript sequence (3 frames)...') codon_positions = get_start_stops(transcript_seq) if not os.path.exists(output_path): os.mkdir(output_path) - logging.info('Writing RiboSeq read counts for {}'.format(transcript_name)) + log.info('Writing RiboSeq read counts for {}'.format(transcript_name)) with open(os.path.join(output_path, 'RiboCounts.csv'), 'w') as f: f.write('"Position","Frame 1","Frame 2","Frame 3"\n') @@ -326,11 +336,11 @@ else: f.write('{0},{1},{2},{3}\n'.format(pos, 0, 0, 0)) - logging.info('Generating RiboPlot...') + log.info('Generating RiboPlot...') plot_profile(ribo_counts, transcript_name, transcript_length, codon_positions, read_length, read_offset, mrna_counts, html_file=args.html_file, output_path=args.output_path) - logging.info('Finished!') + log.info('Finished!') if __name__ == '__main__': parsed = create_parser()