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

31 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-02-25 01:07 +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# Maximum content size (50 MB) to prevent OOM errors 

15MAX_CONTENT_SIZE = 50 * 1024 * 1024 

16 

17 

18@ExporterRegistry.register 

19class RISExporter(BaseExporter): 

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

21 

22 This exporter extracts references from markdown content and converts 

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

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

25 """ 

26 

27 def __init__(self): 

28 """Initialize RIS exporter.""" 

29 # Import here to avoid circular imports 

30 from ..text_optimization.citation_formatter import ( 

31 RISExporter as LegacyRISExporter, 

32 ) 

33 

34 self._legacy = LegacyRISExporter() 

35 

36 @property 

37 def format_name(self) -> str: 

38 return "ris" 

39 

40 @property 

41 def file_extension(self) -> str: 

42 return ".ris" 

43 

44 @property 

45 def mimetype(self) -> str: 

46 return "text/plain" 

47 

48 def export( 

49 self, 

50 markdown_content: str, 

51 options: Optional[ExportOptions] = None, 

52 ) -> ExportResult: 

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

54 

55 Args: 

56 markdown_content: The markdown text containing sources/references 

57 options: Optional export options (title, metadata) 

58 

59 Returns: 

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

61 

62 Raises: 

63 ValueError: If content exceeds maximum size limit 

64 """ 

65 try: 

66 # Check content size limit to prevent OOM errors 

67 if len(markdown_content) > MAX_CONTENT_SIZE: 

68 raise ValueError( 

69 f"Content exceeds maximum size of " 

70 f"{MAX_CONTENT_SIZE // (1024 * 1024)} MB" 

71 ) 

72 

73 options = options or ExportOptions() 

74 

75 content = self._legacy.export_to_ris(markdown_content) 

76 filename = self._generate_safe_filename(options.title) 

77 

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

79 

80 return ExportResult( 

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

82 filename=filename, 

83 mimetype=self.mimetype, 

84 ) 

85 

86 except Exception: 

87 logger.exception("Error generating RIS") 

88 raise