Skip to content

Commit a1848e9

Browse files
committed
Fix lint errors
1 parent 593946c commit a1848e9

6 files changed

Lines changed: 65 additions & 36 deletions

File tree

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ jobs:
3838
- name: Set up Python
3939
uses: actions/setup-python@v5
4040
with:
41-
python-version: "3.9"
41+
python-version: "3.10"
4242

4343
- name: Install Poetry
4444
run: pip install poetry
@@ -52,7 +52,7 @@ jobs:
5252
run: |
5353
cd backend
5454
poetry run black --check src tests
55-
poetry run mypy src
55+
poetry run mypy src --install-types --non-interactive --ignore-missing-imports
5656
5757
- name: Run tests
5858
run: |

backend/src/llm/llm.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class LLM:
4747

4848
def __init__(self) -> None:
4949
self.llms = [
50-
ChatGroq(
50+
ChatGroq( # type: ignore[call-arg]
5151
temperature=0,
5252
groq_api_key=GROQ_API_KEY,
5353
model_name=model_name,
@@ -64,9 +64,10 @@ def extract_job_from_page_data(
6464
for idx, llm in enumerate(self.llms):
6565
try:
6666
chain = (
67-
PromptTemplate(template=EXTRACT_JOB_FROM_PAGE_DATA_TEMPLATE)
68-
| llm
69-
| PydanticOutputParser(pydantic_object=Job)
67+
PromptTemplate(
68+
template=EXTRACT_JOB_FROM_PAGE_DATA_TEMPLATE,
69+
input_variables=['page_data', 'source'],
70+
) | llm | PydanticOutputParser(pydantic_object=Job)
7071
)
7172
response: Job = chain.invoke(
7273
{
@@ -100,9 +101,10 @@ def extract_skills_from_resume(
100101
for llm in self.llms:
101102
try:
102103
return (
103-
PromptTemplate(template=EXTRACT_KEYWORDS_FROM_RESUME_TEMPLATE)
104-
| llm
105-
| JsonOutputParser()
104+
PromptTemplate(
105+
template=EXTRACT_KEYWORDS_FROM_RESUME_TEMPLATE,
106+
input_variables=['resume_data', 'roles']
107+
) | llm | JsonOutputParser()
106108
).invoke(
107109
{"resume_data": resume_data, "roles": "\n".join(preferred_roles)}
108110
)

backend/src/main.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from fastapi import FastAPI
99
from fastapi.middleware.cors import CORSMiddleware
1010
from fastapi.staticfiles import StaticFiles
11+
from sqlalchemy import Boolean, Column
1112
from sqlalchemy.orm import Session
1213

1314
from .constants import EXPIRE_JOBS_AFTER_DAYS, STATIC_DIR_PATH
@@ -43,7 +44,7 @@ def mark_jobs_inactive(db: Session) -> None:
4344
)
4445

4546
for job in old_jobs:
46-
job.is_active = False
47+
job.is_active = Column(Boolean, default=False)
4748
db.commit()
4849
print(f"{len(old_jobs)} jobs marked as inactive.")
4950
except Exception as e:
@@ -60,7 +61,7 @@ def expire_jobs(db: Session) -> None:
6061
for job in old_jobs:
6162
db.delete(job)
6263
db.commit()
63-
job_collection.delete(ids=[job.url for job in old_jobs])
64+
job_collection.delete(ids=[str(job.url) for job in old_jobs])
6465
print(f"{len(old_jobs)} jobs deleted.")
6566
except Exception as e:
6667
print(f"Error marking old jobs inactive: {e}")

backend/src/routers/auth.py

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
)
3333
import sqlalchemy
3434
import sqlalchemy.exc
35+
from sqlalchemy import Boolean, Column, Integer, String
3536
from sqlalchemy.orm import Session
3637

3738
from ..utils import get_normalized_locations_list_string, hash_password, verify_password
@@ -233,10 +234,10 @@ class Token(BaseModel):
233234

234235
def authenticate_user(username: str, password: str, db: Session) -> Optional[User]:
235236
"""Authenticate user with username and password"""
236-
user: User = db.query(User).filter(User.email == username).first()
237+
user = db.query(User).filter(User.email == username).first()
237238
if not user:
238239
return None
239-
if not verify_password(password, user.hashed_password):
240+
if not verify_password(password, str(user.hashed_password)):
240241
return None
241242
return user
242243

@@ -260,10 +261,11 @@ def create_access_token(
260261
response_description="User data for myself",
261262
)
262263
def get_myself(email: user_dependency, db: db_dependency):
263-
user: User = db.query(User).filter(User.email == email["email"]).first()
264+
user = db.query(User).filter(User.email == email["email"]).first()
264265
if not user:
265266
raise HTTPException(
266-
status_code=status.HTTP_401_UNAUTHORIZED, detail="User not authenticated"
267+
status_code=status.HTTP_401_UNAUTHORIZED,
268+
detail="User not authenticated"
267269
)
268270
return user
269271

@@ -276,7 +278,7 @@ def get_myself(email: user_dependency, db: db_dependency):
276278
response_description="User data for the the user with given email.",
277279
)
278280
def get_user(email: user_dependency, db: db_dependency, user_email: str):
279-
user: User = db.query(User).filter(User.email == user_email).first()
281+
user = db.query(User).filter(User.email == user_email).first()
280282
if not user:
281283
raise HTTPException(
282284
status_code=status.HTTP_404_NOT_FOUND, detail="User not found"
@@ -315,6 +317,11 @@ async def create_user(
315317
status_code=status.HTTP_400_BAD_REQUEST,
316318
detail="Only PDF files are supported for resumes",
317319
)
320+
if not resume.filename:
321+
raise HTTPException(
322+
status_code=status.HTTP_400_BAD_REQUEST,
323+
detail="Resume filename not specified",
324+
)
318325
try:
319326
# Save the file to the uploads directory
320327
resume_file_path = os.path.join(
@@ -355,7 +362,7 @@ async def create_user(
355362
is_admin=False,
356363
resume_url=(
357364
os.path.join("static", user_obj.email, resume.filename)
358-
if resume and not isinstance(resume, str)
365+
if resume and not isinstance(resume, str) and resume.filename is not None
359366
else None
360367
),
361368
resume_text=resume_text,
@@ -468,7 +475,11 @@ async def update_user(
468475
detail=json.loads(e.json()),
469476
)
470477

471-
user: User = db.query(User).filter(User.email == email["email"]).first()
478+
user = db.query(User).filter(User.email == email["email"]).first()
479+
if not user:
480+
raise HTTPException(
481+
status_code=status.HTTP_401_UNAUTHORIZED, detail="User not authenticated"
482+
)
472483
resume_text = None
473484
resume_file_path = None
474485

@@ -479,6 +490,11 @@ async def update_user(
479490
detail="Only PDF files are supported for resumes",
480491
)
481492
try:
493+
if not resume.filename:
494+
raise HTTPException(
495+
status_code=status.HTTP_400_BAD_REQUEST,
496+
detail="Resume filename not specified",
497+
)
482498
resume_file_path = os.path.join(
483499
STATIC_DIR_PATH, user.email, resume.filename
484500
)
@@ -504,32 +520,33 @@ async def update_user(
504520
)
505521

506522
try:
507-
user.full_name = user_obj.full_name or user.full_name
508-
user.experience_years = user_obj.experience_years or user.experience_years
523+
user.full_name = Column(String, default=user_obj.full_name) if user_obj.full_name is not None else user.full_name
524+
user.experience_years = Column(Integer, default=user_obj.experience_years) if user_obj.experience_years is not None else user.experience_years
509525
user.preferred_roles = (
510-
json.dumps(user_obj.preferred_roles)
526+
Column(String, default=json.dumps(user_obj.preferred_roles))
511527
if user_obj.preferred_roles
512528
else user.preferred_roles
513529
)
514530
user.preferred_locations = (
515-
json.dumps(user_obj.preferred_locations)
531+
Column(String, default=json.dumps(user_obj.preferred_locations))
516532
if user_obj.preferred_locations
517533
else user.preferred_locations
518534
)
519535
user.preferred_sources = (
520-
json.dumps(user_obj.preferred_sources)
536+
Column(String, default=json.dumps(user_obj.preferred_sources))
521537
if user_obj.preferred_sources
522538
else user.preferred_sources
523539
)
524540
user.receive_email_alerts = (
525-
user_obj.receive_email_alerts
541+
Column(Boolean, default=user_obj.receive_email_alerts)
526542
if user_obj.receive_email_alerts is not None
527543
else user.receive_email_alerts
528544
)
529545

530-
if resume and not isinstance(resume, str):
531-
user.resume_url = os.path.join("static", user.email, resume.filename)
532-
user.resume_text = resume_text
546+
if resume and not isinstance(resume, str) and resume.filename:
547+
user.resume_url = Column(String, default=os.path.join("static", user.email, resume.filename))
548+
if resume_text:
549+
user.resume_text = Column(String, default=resume_text)
533550

534551
db.commit()
535552
db.refresh(user)
@@ -555,5 +572,5 @@ def login_for_access_token(
555572
status_code=status.HTTP_401_UNAUTHORIZED,
556573
detail="Incorrect username or password",
557574
)
558-
access_token = create_access_token(email=user.email)
575+
access_token = create_access_token(email=str(user.email))
559576
return {"access_token": access_token, "token_type": "bearer", "user": user}

backend/src/routers/job.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,13 @@ def recommended_jobs(
8585
),
8686
):
8787
"""Get all recommended jobs for the user based on their resume keywords"""
88-
resume_text_json = (
89-
db.query(User.resume_text).filter(User.email == user["email"]).first()[0]
90-
)
88+
resume_text = db.query(User.resume_text).filter(User.email == user["email"]).first()
89+
if resume_text is None:
90+
raise HTTPException(
91+
status_code=status.HTTP_401_UNAUTHORIZED,
92+
detail=f"User not authenticated",
93+
)
94+
resume_text_json = resume_text[0]
9195
if not resume_text_json:
9296
return {"NULL": db.query(Job).filter(Job.is_active == True).all()}
9397

backend/src/scrapers/scraper_base.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,17 @@ def parse_job_details(self, url: str, location: str):
8888
headers = {"User-Agent": "Mozilla/5.0"}
8989
response = requests.get(url, headers=headers)
9090
soup = BeautifulSoup(response.text, "html.parser")
91-
page_data = soup.find("div", class_="top-card-layout__card").get_text(
92-
strip=True, separator=" "
93-
)
94-
page_data += soup.find(
91+
soup_find = soup.find("div", class_="top-card-layout__card")
92+
page_data = ""
93+
if soup_find:
94+
page_data += soup_find.get_text(
95+
strip=True, separator=" "
96+
)
97+
soup_find = soup.find(
9598
"div", class_="description__text description__text--rich"
96-
).get_text(strip=True, separator=" ")
99+
)
100+
if soup_find:
101+
page_data += soup_find.get_text(strip=True, separator=" ")
97102
company = self.parse_job_company(soup)
98103
job_details = {
99104
**self.infer_job_details(page_data, company, location),

0 commit comments

Comments
 (0)