gperdrizet commited on
Commit
f9a80bc
·
verified ·
1 Parent(s): 146e731

Moved multiple instances of 'pylint: disable=broad-exception-caught' to top of file

Browse files
functions/github.py CHANGED
@@ -12,6 +12,8 @@ from pathlib import Path
12
 
13
  import requests
14
 
 
 
15
  # Set up logging
16
  logging.basicConfig(level=logging.INFO)
17
  logger = logging.getLogger(__name__)
@@ -99,12 +101,12 @@ def get_github_repositories(github_url: str) -> Dict:
99
  json.dump(result, f, indent=2, ensure_ascii=False)
100
 
101
  logger.info("GitHub repositories saved to %s", output_file)
102
- except Exception as save_error: # pylint: disable=broad-exception-caught
103
  logger.warning("Failed to save GitHub repositories to file: %s", str(save_error))
104
 
105
  return result
106
 
107
- except Exception as e: # pylint: disable=broad-exception-caught
108
  logger.error("Error retrieving GitHub repositories: %s", str(e))
109
 
110
  return {
@@ -146,7 +148,7 @@ def _extract_github_username(github_url: str) -> Optional[str]:
146
 
147
  return None
148
 
149
- except Exception as e: # pylint: disable=broad-exception-caught
150
  logger.warning("Error extracting username from URL %s: %s", github_url, str(e))
151
 
152
  return None
 
12
 
13
  import requests
14
 
15
+ # pylint: disable=broad-exception-caught
16
+
17
  # Set up logging
18
  logging.basicConfig(level=logging.INFO)
19
  logger = logging.getLogger(__name__)
 
101
  json.dump(result, f, indent=2, ensure_ascii=False)
102
 
103
  logger.info("GitHub repositories saved to %s", output_file)
104
+ except Exception as save_error:
105
  logger.warning("Failed to save GitHub repositories to file: %s", str(save_error))
106
 
107
  return result
108
 
109
+ except Exception as e:
110
  logger.error("Error retrieving GitHub repositories: %s", str(e))
111
 
112
  return {
 
148
 
149
  return None
150
 
151
+ except Exception as e:
152
  logger.warning("Error extracting username from URL %s: %s", github_url, str(e))
153
 
154
  return None
functions/gradio.py CHANGED
@@ -13,6 +13,8 @@ from functions.job_call import summarize_job_call
13
  from functions.writer_agent import write_resume
14
  from configuration import DEFAULT_GITHUB_PROFILE
15
 
 
 
16
  # Set up logging
17
  logging.basicConfig(level=logging.INFO)
18
  logger = logging.getLogger(__name__)
@@ -82,6 +84,7 @@ def process_inputs(linkedin_pdf, github_url, job_post_text, user_instructions):
82
 
83
  # Process LinkedIn PDF file
84
  if linkedin_pdf is not None:
 
85
  # Handle both file objects and mock file objects with path strings
86
  file_path = linkedin_pdf.name
87
  file_display_name = Path(file_path).name
@@ -103,6 +106,7 @@ def process_inputs(linkedin_pdf, github_url, job_post_text, user_instructions):
103
  shutil.copy2(file_path, default_pdf_path)
104
  result += " ✅ Saved as new default LinkedIn profile\n"
105
  logger.info("Saved uploaded LinkedIn PDF as new default: %s", default_pdf_path)
 
106
  except Exception as save_error:
107
  result += f" ⚠️ Could not save as default: {str(save_error)}\n"
108
  logger.warning("Failed to save LinkedIn PDF as default: %s", str(save_error))
@@ -190,7 +194,7 @@ def process_inputs(linkedin_pdf, github_url, job_post_text, user_instructions):
190
  result += "\n✅ Resume generated successfully\n"
191
  logger.info("Resume generation completed successfully")
192
 
193
- except Exception as e: # pylint: disable=broad-exception-caught
194
  result += f"\n❌ Resume generation failed: {str(e)}\n"
195
  logger.error("Resume generation failed: %s", str(e))
196
  else:
 
13
  from functions.writer_agent import write_resume
14
  from configuration import DEFAULT_GITHUB_PROFILE
15
 
16
+ # pylint: disable=broad-exception-caught
17
+
18
  # Set up logging
19
  logging.basicConfig(level=logging.INFO)
20
  logger = logging.getLogger(__name__)
 
84
 
85
  # Process LinkedIn PDF file
86
  if linkedin_pdf is not None:
87
+
88
  # Handle both file objects and mock file objects with path strings
89
  file_path = linkedin_pdf.name
90
  file_display_name = Path(file_path).name
 
106
  shutil.copy2(file_path, default_pdf_path)
107
  result += " ✅ Saved as new default LinkedIn profile\n"
108
  logger.info("Saved uploaded LinkedIn PDF as new default: %s", default_pdf_path)
109
+
110
  except Exception as save_error:
111
  result += f" ⚠️ Could not save as default: {str(save_error)}\n"
112
  logger.warning("Failed to save LinkedIn PDF as default: %s", str(save_error))
 
194
  result += "\n✅ Resume generated successfully\n"
195
  logger.info("Resume generation completed successfully")
196
 
197
+ except Exception as e:
198
  result += f"\n❌ Resume generation failed: {str(e)}\n"
199
  logger.error("Resume generation failed: %s", str(e))
200
  else:
functions/job_call.py CHANGED
@@ -5,6 +5,8 @@ import logging
5
  from openai import OpenAI
6
  from configuration import JOB_CALL_EXTRACTION_PROMPT
7
 
 
 
8
  # Set up logging
9
  logging.basicConfig(level=logging.INFO)
10
  logger = logging.getLogger(__name__)
@@ -47,7 +49,7 @@ def summarize_job_call(job_call: str) -> str:
47
  try:
48
  response = client.chat.completions.create(**completion_args)
49
 
50
- except Exception as e: # pylint: disable=broad-exception-caught
51
  response = None
52
  logger.error('Error during Modal API call: %s', e)
53
 
 
5
  from openai import OpenAI
6
  from configuration import JOB_CALL_EXTRACTION_PROMPT
7
 
8
+ # pylint: disable=broad-exception-caught
9
+
10
  # Set up logging
11
  logging.basicConfig(level=logging.INFO)
12
  logger = logging.getLogger(__name__)
 
49
  try:
50
  response = client.chat.completions.create(**completion_args)
51
 
52
+ except Exception as e:
53
  response = None
54
  logger.error('Error during Modal API call: %s', e)
55
 
functions/linkedin_resume.py CHANGED
@@ -13,6 +13,8 @@ import json
13
  from pathlib import Path
14
  import PyPDF2
15
 
 
 
16
  # Set up logging
17
  logging.basicConfig(level=logging.INFO)
18
  logger = logging.getLogger(__name__)
@@ -66,7 +68,7 @@ def extract_text_from_linkedin_pdf(pdf_file) -> dict:
66
  page_text = page.extract_text()
67
  extracted_text += page_text + "\n\n"
68
 
69
- except Exception as e: # pylint: disable=broad-exception-caught
70
  logger.warning("Error extracting text from page %d: %s", page_num + 1, str(e))
71
 
72
  continue
@@ -115,12 +117,12 @@ def extract_text_from_linkedin_pdf(pdf_file) -> dict:
115
 
116
  logger.info("LinkedIn resume extraction saved to %s", output_file)
117
 
118
- except Exception as save_error: # pylint: disable=broad-exception-caught
119
  logger.warning("Failed to save LinkedIn resume extraction to file: %s", str(save_error))
120
 
121
  return result
122
 
123
- except Exception as e: # pylint: disable=broad-exception-caught
124
  logger.error("Error processing PDF file: %s", str(e))
125
 
126
  return {
 
13
  from pathlib import Path
14
  import PyPDF2
15
 
16
+ # pylint: disable=broad-exception-caught
17
+
18
  # Set up logging
19
  logging.basicConfig(level=logging.INFO)
20
  logger = logging.getLogger(__name__)
 
68
  page_text = page.extract_text()
69
  extracted_text += page_text + "\n\n"
70
 
71
+ except Exception as e:
72
  logger.warning("Error extracting text from page %d: %s", page_num + 1, str(e))
73
 
74
  continue
 
117
 
118
  logger.info("LinkedIn resume extraction saved to %s", output_file)
119
 
120
+ except Exception as save_error:
121
  logger.warning("Failed to save LinkedIn resume extraction to file: %s", str(save_error))
122
 
123
  return result
124
 
125
+ except Exception as e:
126
  logger.error("Error processing PDF file: %s", str(e))
127
 
128
  return {
functions/writer_agent.py CHANGED
@@ -6,6 +6,8 @@ import os
6
  from smolagents import CodeAgent
7
  from configuration import AGENT_MODEL, INSTRUCTIONS
8
 
 
 
9
  logging.basicConfig(level=logging.INFO)
10
  logger = logging.getLogger(__name__)
11
 
@@ -65,7 +67,7 @@ def write_resume(content: str, user_instructions: str = None) -> str:
65
 
66
  logger.info("Resume saved to: %s", resume_file_path)
67
 
68
- except Exception as e: # pylint: disable=broad-exception-caught
69
  logger.error("Failed to save resume to file: %s", e)
70
 
71
  return submitted_answer
 
6
  from smolagents import CodeAgent
7
  from configuration import AGENT_MODEL, INSTRUCTIONS
8
 
9
+ # pylint: disable=broad-exception-caught
10
+
11
  logging.basicConfig(level=logging.INFO)
12
  logger = logging.getLogger(__name__)
13
 
 
67
 
68
  logger.info("Resume saved to: %s", resume_file_path)
69
 
70
+ except Exception as e:
71
  logger.error("Failed to save resume to file: %s", e)
72
 
73
  return submitted_answer
tests/test_linkedin_resume.py CHANGED
@@ -8,45 +8,55 @@ import os
8
  from unittest.mock import patch, MagicMock
9
  from functions import linkedin_resume as ca
10
 
 
 
11
 
12
  class TestCleanExtractedText(unittest.TestCase):
13
  """Test cases for the _clean_extracted_text function."""
14
-
15
  def test_normalize_multiple_newlines(self):
16
  """Test normalization of multiple newlines."""
 
17
  raw = "Line 1\n\nLine 2\n\n\nLine 3"
18
  expected = "Line 1\nLine 2\nLine 3"
19
  self.assertEqual(ca._clean_extracted_text(raw), expected)
20
-
21
  def test_remove_artifacts(self):
22
  """Test removal of PDF artifacts."""
 
23
  raw = " 123 \n|---|\nSome text\n"
24
  expected = "Some text"
25
  self.assertEqual(ca._clean_extracted_text(raw), expected)
26
-
27
  def test_normalize_spaces(self):
28
  """Test normalization of multiple spaces."""
 
29
  raw = "A B C"
30
  expected = "A B C"
31
  self.assertEqual(ca._clean_extracted_text(raw), expected)
32
-
33
  def test_empty_string(self):
34
  """Test handling of empty string."""
 
35
  self.assertEqual(ca._clean_extracted_text(""), "")
36
-
37
  def test_none_input(self):
38
  """Test handling of None input."""
 
39
  self.assertEqual(ca._clean_extracted_text(None), "")
40
 
41
 
42
  class TestStructureResumeText(unittest.TestCase):
43
  """Test cases for the _structure_resume_text function."""
44
-
45
  def test_basic_structure(self):
46
  """Test basic resume text structuring."""
47
- text = "Contact Info\nJohn Doe\nSummary\nExperienced dev\nExperience\nCompany X\nEducation\nMIT\nSkills\nPython, C++"
 
 
 
48
  result = ca._structure_resume_text(text)
49
-
50
  self.assertIn("contact_info", result["sections"])
51
  self.assertIn("summary", result["sections"])
52
  self.assertIn("experience", result["sections"])
@@ -54,21 +64,23 @@ class TestStructureResumeText(unittest.TestCase):
54
  self.assertIn("skills", result["sections"])
55
  self.assertGreater(result["word_count"], 0)
56
  self.assertGreaterEqual(result["section_count"], 5)
57
-
58
  def test_empty_text(self):
59
  """Test handling of empty text."""
 
60
  result = ca._structure_resume_text("")
61
  self.assertEqual(result["sections"], {})
62
  self.assertEqual(result["full_text"], "")
63
  self.assertEqual(result["word_count"], 0)
64
  self.assertEqual(result["section_count"], 0)
65
-
66
  def test_contains_required_fields(self):
67
  """Test that result contains all required fields."""
 
68
  text = "Some basic text"
69
  result = ca._structure_resume_text(text)
70
-
71
- required_fields = ["sections", "full_text", "llm_formatted", "summary",
72
  "format", "word_count", "section_count"]
73
  for field in required_fields:
74
  self.assertIn(field, result)
@@ -76,9 +88,10 @@ class TestStructureResumeText(unittest.TestCase):
76
 
77
  class TestFormatForLLM(unittest.TestCase):
78
  """Test cases for the _format_for_llm function."""
79
-
80
  def test_section_formatting(self):
81
  """Test proper formatting of sections for LLM."""
 
82
  sections = {
83
  "summary": "A summary.",
84
  "contact_info": "Contact details.",
@@ -86,9 +99,8 @@ class TestFormatForLLM(unittest.TestCase):
86
  "education": "School info.",
87
  "skills": "Python, C++"
88
  }
89
- full_text = "..."
90
- formatted = ca._format_for_llm(sections, full_text)
91
-
92
  self.assertIn("[SUMMARY]", formatted)
93
  self.assertIn("[CONTACT INFO]", formatted)
94
  self.assertIn("[EXPERIENCE]", formatted)
@@ -96,46 +108,50 @@ class TestFormatForLLM(unittest.TestCase):
96
  self.assertIn("[SKILLS]", formatted)
97
  self.assertTrue(formatted.startswith("=== RESUME CONTENT ==="))
98
  self.assertTrue(formatted.endswith("=== END RESUME ==="))
99
-
100
  def test_empty_sections(self):
101
  """Test handling of empty sections."""
 
102
  sections = {}
103
- full_text = "test"
104
- formatted = ca._format_for_llm(sections, full_text)
105
-
106
  self.assertTrue(formatted.startswith("=== RESUME CONTENT ==="))
107
  self.assertTrue(formatted.endswith("=== END RESUME ==="))
108
 
109
 
110
  class TestGetLLMContextFromResume(unittest.TestCase):
111
  """Test cases for the get_llm_context_from_resume function."""
112
-
113
  def test_success_with_llm_formatted(self):
114
  """Test successful extraction with LLM formatted text."""
 
115
  extraction_result = {
116
  "status": "success",
117
  "structured_text": {"llm_formatted": "LLM text", "full_text": "Full text"}
118
  }
119
  result = ca.get_llm_context_from_resume(extraction_result)
120
  self.assertEqual(result, "LLM text")
121
-
122
  def test_fallback_to_full_text(self):
123
  """Test fallback to full text when LLM formatted not available."""
 
124
  extraction_result = {
125
  "status": "success",
126
  "structured_text": {"full_text": "Full text"}
127
  }
128
  result = ca.get_llm_context_from_resume(extraction_result)
129
  self.assertEqual(result, "Full text")
130
-
131
  def test_error_status(self):
132
  """Test handling of error status."""
 
133
  extraction_result = {"status": "error"}
134
  result = ca.get_llm_context_from_resume(extraction_result)
135
  self.assertEqual(result, "")
136
-
137
  def test_missing_structured_text(self):
138
  """Test handling of missing structured_text."""
 
139
  extraction_result = {"status": "success"}
140
  result = ca.get_llm_context_from_resume(extraction_result)
141
  self.assertEqual(result, "")
@@ -143,50 +159,54 @@ class TestGetLLMContextFromResume(unittest.TestCase):
143
 
144
  class TestExtractTextFromLinkedInPDF(unittest.TestCase):
145
  """Test cases for the extract_text_from_linkedin_pdf function."""
146
-
147
  def test_none_input(self):
148
  """Test handling of None input."""
 
149
  result = ca.extract_text_from_linkedin_pdf(None)
150
  self.assertEqual(result["status"], "error")
151
  self.assertIn("No PDF file provided", result["message"])
152
-
153
  @patch('PyPDF2.PdfReader')
154
  @patch('builtins.open')
155
  def test_successful_extraction(self, mock_open, mock_pdf_reader):
156
  """Test successful PDF text extraction with mocked PyPDF2."""
 
157
  # Create a temporary file
158
  with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp:
159
  tmp_path = tmp.name
160
-
161
  try:
162
  # Mock file reading
163
  mock_file = MagicMock()
164
  mock_file.read.return_value = b"fake pdf content"
165
  mock_open.return_value.__enter__.return_value = mock_file
166
-
167
  # Mock PDF reader and page
168
  mock_page = MagicMock()
169
- mock_page.extract_text.return_value = "Contact Info\nJohn Doe\nSummary\nDeveloper\nExperience\nCompany X"
170
-
 
171
  mock_reader_instance = MagicMock()
172
  mock_reader_instance.pages = [mock_page]
173
  mock_pdf_reader.return_value = mock_reader_instance
174
-
175
  # Test the function
176
  result = ca.extract_text_from_linkedin_pdf(tmp_path)
177
-
178
  self.assertEqual(result["status"], "success")
179
  self.assertIn("structured_text", result)
180
  self.assertIn("metadata", result)
181
  self.assertIn("contact_info", result["structured_text"]["sections"])
182
-
183
  finally:
184
  # Clean up
185
  if os.path.exists(tmp_path):
186
  os.remove(tmp_path)
187
-
188
  def test_nonexistent_file(self):
189
  """Test handling of non-existent file."""
 
190
  result = ca.extract_text_from_linkedin_pdf("/nonexistent/path.pdf")
191
  self.assertEqual(result["status"], "error")
192
  self.assertIn("Failed to extract text from PDF", result["message"])
 
8
  from unittest.mock import patch, MagicMock
9
  from functions import linkedin_resume as ca
10
 
11
+ # pylint: disable=protected-access
12
+
13
 
14
  class TestCleanExtractedText(unittest.TestCase):
15
  """Test cases for the _clean_extracted_text function."""
16
+
17
  def test_normalize_multiple_newlines(self):
18
  """Test normalization of multiple newlines."""
19
+
20
  raw = "Line 1\n\nLine 2\n\n\nLine 3"
21
  expected = "Line 1\nLine 2\nLine 3"
22
  self.assertEqual(ca._clean_extracted_text(raw), expected)
23
+
24
  def test_remove_artifacts(self):
25
  """Test removal of PDF artifacts."""
26
+
27
  raw = " 123 \n|---|\nSome text\n"
28
  expected = "Some text"
29
  self.assertEqual(ca._clean_extracted_text(raw), expected)
30
+
31
  def test_normalize_spaces(self):
32
  """Test normalization of multiple spaces."""
33
+
34
  raw = "A B C"
35
  expected = "A B C"
36
  self.assertEqual(ca._clean_extracted_text(raw), expected)
37
+
38
  def test_empty_string(self):
39
  """Test handling of empty string."""
40
+
41
  self.assertEqual(ca._clean_extracted_text(""), "")
42
+
43
  def test_none_input(self):
44
  """Test handling of None input."""
45
+
46
  self.assertEqual(ca._clean_extracted_text(None), "")
47
 
48
 
49
  class TestStructureResumeText(unittest.TestCase):
50
  """Test cases for the _structure_resume_text function."""
51
+
52
  def test_basic_structure(self):
53
  """Test basic resume text structuring."""
54
+
55
+ text = "Contact Info\nJohn Doe\nSummary\nExperienced dev" + \
56
+ "\nExperience\nCompany X\nEducation\nMIT\nSkills\nPython, C++"
57
+
58
  result = ca._structure_resume_text(text)
59
+
60
  self.assertIn("contact_info", result["sections"])
61
  self.assertIn("summary", result["sections"])
62
  self.assertIn("experience", result["sections"])
 
64
  self.assertIn("skills", result["sections"])
65
  self.assertGreater(result["word_count"], 0)
66
  self.assertGreaterEqual(result["section_count"], 5)
67
+
68
  def test_empty_text(self):
69
  """Test handling of empty text."""
70
+
71
  result = ca._structure_resume_text("")
72
  self.assertEqual(result["sections"], {})
73
  self.assertEqual(result["full_text"], "")
74
  self.assertEqual(result["word_count"], 0)
75
  self.assertEqual(result["section_count"], 0)
76
+
77
  def test_contains_required_fields(self):
78
  """Test that result contains all required fields."""
79
+
80
  text = "Some basic text"
81
  result = ca._structure_resume_text(text)
82
+
83
+ required_fields = ["sections", "full_text", "llm_formatted", "summary",
84
  "format", "word_count", "section_count"]
85
  for field in required_fields:
86
  self.assertIn(field, result)
 
88
 
89
  class TestFormatForLLM(unittest.TestCase):
90
  """Test cases for the _format_for_llm function."""
91
+
92
  def test_section_formatting(self):
93
  """Test proper formatting of sections for LLM."""
94
+
95
  sections = {
96
  "summary": "A summary.",
97
  "contact_info": "Contact details.",
 
99
  "education": "School info.",
100
  "skills": "Python, C++"
101
  }
102
+ formatted = ca._format_for_llm(sections)
103
+
 
104
  self.assertIn("[SUMMARY]", formatted)
105
  self.assertIn("[CONTACT INFO]", formatted)
106
  self.assertIn("[EXPERIENCE]", formatted)
 
108
  self.assertIn("[SKILLS]", formatted)
109
  self.assertTrue(formatted.startswith("=== RESUME CONTENT ==="))
110
  self.assertTrue(formatted.endswith("=== END RESUME ==="))
111
+
112
  def test_empty_sections(self):
113
  """Test handling of empty sections."""
114
+
115
  sections = {}
116
+ formatted = ca._format_for_llm(sections)
117
+
 
118
  self.assertTrue(formatted.startswith("=== RESUME CONTENT ==="))
119
  self.assertTrue(formatted.endswith("=== END RESUME ==="))
120
 
121
 
122
  class TestGetLLMContextFromResume(unittest.TestCase):
123
  """Test cases for the get_llm_context_from_resume function."""
124
+
125
  def test_success_with_llm_formatted(self):
126
  """Test successful extraction with LLM formatted text."""
127
+
128
  extraction_result = {
129
  "status": "success",
130
  "structured_text": {"llm_formatted": "LLM text", "full_text": "Full text"}
131
  }
132
  result = ca.get_llm_context_from_resume(extraction_result)
133
  self.assertEqual(result, "LLM text")
134
+
135
  def test_fallback_to_full_text(self):
136
  """Test fallback to full text when LLM formatted not available."""
137
+
138
  extraction_result = {
139
  "status": "success",
140
  "structured_text": {"full_text": "Full text"}
141
  }
142
  result = ca.get_llm_context_from_resume(extraction_result)
143
  self.assertEqual(result, "Full text")
144
+
145
  def test_error_status(self):
146
  """Test handling of error status."""
147
+
148
  extraction_result = {"status": "error"}
149
  result = ca.get_llm_context_from_resume(extraction_result)
150
  self.assertEqual(result, "")
151
+
152
  def test_missing_structured_text(self):
153
  """Test handling of missing structured_text."""
154
+
155
  extraction_result = {"status": "success"}
156
  result = ca.get_llm_context_from_resume(extraction_result)
157
  self.assertEqual(result, "")
 
159
 
160
  class TestExtractTextFromLinkedInPDF(unittest.TestCase):
161
  """Test cases for the extract_text_from_linkedin_pdf function."""
162
+
163
  def test_none_input(self):
164
  """Test handling of None input."""
165
+
166
  result = ca.extract_text_from_linkedin_pdf(None)
167
  self.assertEqual(result["status"], "error")
168
  self.assertIn("No PDF file provided", result["message"])
169
+
170
  @patch('PyPDF2.PdfReader')
171
  @patch('builtins.open')
172
  def test_successful_extraction(self, mock_open, mock_pdf_reader):
173
  """Test successful PDF text extraction with mocked PyPDF2."""
174
+
175
  # Create a temporary file
176
  with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp:
177
  tmp_path = tmp.name
178
+
179
  try:
180
  # Mock file reading
181
  mock_file = MagicMock()
182
  mock_file.read.return_value = b"fake pdf content"
183
  mock_open.return_value.__enter__.return_value = mock_file
184
+
185
  # Mock PDF reader and page
186
  mock_page = MagicMock()
187
+ mock_page.extract_text.return_value = "Contact Info\nJohn Doe\nSummary" + \
188
+ "\nDeveloper\nExperience\nCompany X"
189
+
190
  mock_reader_instance = MagicMock()
191
  mock_reader_instance.pages = [mock_page]
192
  mock_pdf_reader.return_value = mock_reader_instance
193
+
194
  # Test the function
195
  result = ca.extract_text_from_linkedin_pdf(tmp_path)
196
+
197
  self.assertEqual(result["status"], "success")
198
  self.assertIn("structured_text", result)
199
  self.assertIn("metadata", result)
200
  self.assertIn("contact_info", result["structured_text"]["sections"])
201
+
202
  finally:
203
  # Clean up
204
  if os.path.exists(tmp_path):
205
  os.remove(tmp_path)
206
+
207
  def test_nonexistent_file(self):
208
  """Test handling of non-existent file."""
209
+
210
  result = ca.extract_text_from_linkedin_pdf("/nonexistent/path.pdf")
211
  self.assertEqual(result["status"], "error")
212
  self.assertIn("Failed to extract text from PDF", result["message"])