Coverage for src / rendercv / schema / models / cv / entries / publication.py: 100%

32 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-25 13:49 +0000

1import functools 

2from typing import Self 

3 

4import pydantic 

5 

6from .bases.entry import BaseEntry 

7from .bases.entry_with_date import BaseEntryWithDate 

8 

9url_validator = pydantic.TypeAdapter[pydantic.HttpUrl](pydantic.HttpUrl) 

10 

11 

12class BasePublicationEntry(BaseEntry): 

13 title: str = pydantic.Field( 

14 examples=[ 

15 "Deep Learning for Computer Vision", 

16 "Advances in Quantum Computing", 

17 ], 

18 ) 

19 authors: list[str] = pydantic.Field( 

20 description="You can bold your name with **double asterisks**.", 

21 examples=[["John Doe", "**Jane Smith**", "Bob Johnson"]], 

22 ) 

23 summary: str | None = pydantic.Field( 

24 default=None, 

25 examples=["This paper presents a new method for computer vision."], 

26 ) 

27 doi: str | None = pydantic.Field( 

28 default=None, 

29 description=( 

30 "The DOI (Digital Object Identifier). If provided, it will be used as the" 

31 " link instead of the URL." 

32 ), 

33 examples=["10.48550/arXiv.2310.03138"], 

34 pattern=r"\b10\..*", 

35 ) 

36 url: pydantic.HttpUrl | None = pydantic.Field( 

37 default=None, 

38 description="A URL link to the publication. Ignored if DOI is provided.", 

39 ) 

40 journal: str | None = pydantic.Field( 

41 default=None, 

42 description="The journal, conference, or venue where it was published.", 

43 examples=["Nature", "IEEE Conference on Computer Vision", "arXiv preprint"], 

44 ) 

45 

46 @pydantic.model_validator(mode="after") 

47 def ignore_url_if_doi_is_given(self) -> Self: 

48 """Prioritize DOI over custom URL when both provided. 

49 

50 Why: 

51 DOI is canonical, stable identifier for publications. When provided, 

52 ignore user's URL to ensure templates use official DOI link. 

53 

54 Returns: 

55 Publication instance with url cleared if DOI exists. 

56 """ 

57 doi_is_provided = self.doi is not None 

58 

59 if doi_is_provided: 

60 self.url = None 

61 

62 return self 

63 

64 @pydantic.model_validator(mode="after") 

65 def validate_doi_url(self) -> Self: 

66 """Validate generated DOI URL is well-formed. 

67 

68 Why: 

69 DOI URL generation from DOI string might produce invalid URLs. 

70 Post-validation ensures generated URLs are valid. 

71 

72 Returns: 

73 Validated publication instance. 

74 """ 

75 if self.doi_url: 

76 url_validator.validate_strings(self.doi_url) 

77 

78 return self 

79 

80 @functools.cached_property 

81 def doi_url(self) -> str | None: 

82 """Generate DOI URL from DOI identifier. 

83 

84 Why: 

85 DOI identifiers need https://doi.org/ prefix for linking. 

86 Property generates complete URL from DOI string. 

87 

88 Returns: 

89 Complete DOI URL, or None if no DOI provided. 

90 """ 

91 doi_is_provided = self.doi is not None 

92 

93 if doi_is_provided: 

94 return f"https://doi.org/{self.doi}" 

95 

96 return None 

97 

98 

99# This approach ensures PublicationEntryBase keys appear first in the key order: 

100class PublicationEntry(BaseEntryWithDate, BasePublicationEntry): 

101 pass