rmd_reader.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. #-*- conding: utf-8 -*-
  2. import os
  3. import warnings
  4. import logging
  5. logger = logging.getLogger('RMD_READER')
  6. from pelican import readers
  7. from pelican import signals
  8. from pelican import settings
  9. KNITR = None
  10. RMD = False
  11. FIG_PATH = None
  12. R_STARTED = False
  13. def startr():
  14. global KNITR, R_OBJECTS, R_STARTED
  15. if R_STARTED:
  16. return
  17. logger.debug('STARTING R')
  18. with warnings.catch_warnings():
  19. warnings.simplefilter("ignore")
  20. import rpy2.rinterface
  21. rpy2.rinterface.set_initoptions((b'rpy2', b'--no-save', b'--vanilla', b'--quiet'))
  22. import rpy2.robjects as R_OBJECTS
  23. from rpy2.robjects.packages import importr
  24. KNITR = importr('knitr')
  25. logger.debug('R STARTED')
  26. R_STARTED = True
  27. def initsignal(pelicanobj):
  28. global RMD, FIG_PATH
  29. try:
  30. startr()
  31. R_OBJECTS.r('Sys.setlocale("LC_ALL", "C")')
  32. R_OBJECTS.r('Sys.setlocale("LC_NUMERIC", "C")')
  33. R_OBJECTS.r('Sys.setlocale("LC_MESSAGES", "C")')
  34. idx = KNITR.opts_knit.names.index('set')
  35. path = pelicanobj.settings.get('PATH','%s/content' % settings.DEFAULT_CONFIG.get('PATH'))
  36. logger.debug("RMD_READER PATH = %s", path)
  37. KNITR.opts_knit[idx](**{'base.dir': path})
  38. knitroptsknit = pelicanobj.settings.get('RMD_READER_KNITR_OPTS_KNIT', None)
  39. if knitroptsknit:
  40. KNITR.opts_knit[idx](**{str(k): v for k,v in knitroptsknit.items()})
  41. idx = KNITR.opts_chunk.names.index('set')
  42. knitroptschunk = pelicanobj.settings.get('RMD_READER_KNITR_OPTS_CHUNK', None)
  43. if knitroptschunk:
  44. FIG_PATH = knitroptschunk['fig.path'] if 'fig.path' in knitroptschunk else 'figure/'
  45. KNITR.opts_chunk[idx](**{str(k): v for k,v in knitroptschunk.items()})
  46. RMD = True
  47. except ImportError as ex:
  48. RMD = False
  49. class RmdReader(readers.BaseReader):
  50. file_extensions = ['Rmd', 'rmd']
  51. @property
  52. def enabled():
  53. return RMD
  54. # You need to have a read method, which takes a filename and returns
  55. # some content and the associated metadata.
  56. def read(self, filename):
  57. """Parse content and metadata of markdown files"""
  58. QUIET = self.settings.get('RMD_READER_KNITR_QUIET', True)
  59. ENCODING = self.settings.get('RMD_READER_KNITR_ENCODING', 'UTF-8')
  60. CLEANUP = self.settings.get('RMD_READER_CLEANUP', True)
  61. RENAME_PLOT = self.settings.get('RMD_READER_RENAME_PLOT', 'chunklabel')
  62. if type(RENAME_PLOT) is bool:
  63. logger.error("RMD_READER_RENAME_PLOT takes a string value (either chunklabel or directory), please see the readme.")
  64. if RENAME_PLOT:
  65. RENAME_PLOT = 'chunklabel'
  66. logger.error("Defaulting to chunklabel")
  67. else:
  68. RENAME_PLOT = 'disabled'
  69. logger.error("Disabling plot renaming")
  70. logger.debug("RMD_READER_KNITR_QUIET = %s", QUIET)
  71. logger.debug("RMD_READER_KNITR_ENCODING = %s", ENCODING)
  72. logger.debug("RMD_READER_CLEANUP = %s", CLEANUP)
  73. logger.debug("RMD_READER_RENAME_PLOT = %s", RENAME_PLOT)
  74. # replace single backslashes with double backslashes
  75. filename = filename.replace('\\', '\\\\')
  76. # parse Rmd file - generate md file
  77. md_filename = filename.replace('.Rmd', '.aux').replace('.rmd', '.aux')
  78. if RENAME_PLOT == 'chunklabel' or RENAME_PLOT == 'directory':
  79. if RENAME_PLOT == 'chunklabel':
  80. chunk_label = os.path.splitext(os.path.basename(filename))[0]
  81. logger.debug('Chunk label: %s', chunk_label)
  82. elif RENAME_PLOT == 'directory':
  83. chunk_label = 'unnamed-chunk'
  84. PATH = self.settings.get('PATH','%s/content' % settings.DEFAULT_CONFIG.get('PATH'))
  85. src_name = os.path.splitext(os.path.relpath(filename, PATH))[0]
  86. idx = KNITR.opts_chunk.names.index('set')
  87. knitroptschunk = { 'fig.path': '%s-' % os.path.join(FIG_PATH, src_name) }
  88. KNITR.opts_chunk[idx](**{str(k): v for k,v in knitroptschunk.items()})
  89. logger.debug('Figures path: %s, chunk label: %s', knitroptschunk['fig.path'], chunk_label)
  90. R_OBJECTS.r('''
  91. opts_knit$set(unnamed.chunk.label="{unnamed_chunk_label}")
  92. render_markdown()
  93. hook_plot <- knit_hooks$get('plot')
  94. knit_hooks$set(plot=function(x, options) hook_plot(paste0("{{filename}}/", x), options))
  95. '''.format(unnamed_chunk_label=chunk_label))
  96. with warnings.catch_warnings():
  97. warnings.simplefilter("ignore")
  98. KNITR.knit(filename, md_filename, quiet=QUIET, encoding=ENCODING)
  99. # read md file - create a MarkdownReader
  100. md_reader = readers.MarkdownReader(self.settings)
  101. content, metadata = md_reader.read(md_filename)
  102. # remove md file
  103. if CLEANUP:
  104. os.remove(md_filename)
  105. return content, metadata
  106. def add_reader(readers):
  107. readers.reader_classes['rmd'] = RmdReader
  108. def register():
  109. signals.readers_init.connect(add_reader)
  110. signals.initialized.connect(initsignal)