Coverage for src / local_deep_research / exporters / ris_exporter.py: 100%

29 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-14 23:55 +0000

1"""RIS export service. 

2 

3This module provides the RISExporter class that wraps the existing 

4RISExporter implementation from text_optimization.citation_formatter. 

5""" 

6 

7from typing import Optional 

8 

9from loguru import logger 

10 

11from .base import BaseExporter, ExportOptions, ExportResult 

12from .registry import ExporterRegistry 

13 

14 

15@ExporterRegistry.register 

16class RISExporter(BaseExporter): 

17 """RIS exporter using the existing RISExporter implementation. 

18 

19 This exporter extracts references from markdown content and converts 

20 them to RIS (Research Information Systems) format, which can be 

21 imported into reference managers like Zotero, Mendeley, or EndNote. 

22 """ 

23 

24 def __init__(self): 

25 """Initialize RIS exporter.""" 

26 # Import here to avoid circular imports 

27 from ..text_optimization.citation_formatter import ( 

28 RISExporter as LegacyRISExporter, 

29 ) 

30 

31 self._legacy = LegacyRISExporter() 

32 

33 @property 

34 def format_name(self) -> str: 

35 return "ris" 

36 

37 @property 

38 def file_extension(self) -> str: 

39 return ".ris" 

40 

41 @property 

42 def mimetype(self) -> str: 

43 return "text/plain" 

44 

45 def export( 

46 self, 

47 markdown_content: str, 

48 options: Optional[ExportOptions] = None, 

49 ) -> ExportResult: 

50 """Extract references from markdown and convert to RIS format. 

51 

52 Args: 

53 markdown_content: The markdown text containing sources/references 

54 options: Optional export options (title, metadata) 

55 

56 Returns: 

57 ExportResult with RIS content as UTF-8 bytes, filename, and mimetype 

58 

59 Raises: 

60 ValueError: If content exceeds maximum size limit 

61 """ 

62 try: 

63 # Check content size limit to prevent OOM errors 

64 self._validate_content_size(markdown_content) 

65 

66 options = options or ExportOptions() 

67 

68 content = self._legacy.export_to_ris(markdown_content) 

69 filename = self._generate_safe_filename(options.title) 

70 

71 logger.info(f"Generated RIS in memory, size: {len(content)} bytes") 

72 

73 return ExportResult( 

74 content=content.encode("utf-8"), 

75 filename=filename, 

76 mimetype=self.mimetype, 

77 ) 

78 

79 except Exception: 

80 logger.exception("Error generating RIS") 

81 raise