From f36602e2830687cdb7db835b2c855a30a2d79d8f Mon Sep 17 00:00:00 2001 From: dhirukumar Date: Mon, 17 Nov 2025 19:37:28 +0530 Subject: [PATCH 1/9] Add type hints to utils.py files --- backend/apps/common/utils.py | 46 ++++++++++++++++++-------------- backend/apps/github/utils.py | 27 ++++++++++--------- backend/apps/slack/utils.py | 51 ++++++++++++++++++++++++------------ 3 files changed, 75 insertions(+), 49 deletions(-) diff --git a/backend/apps/common/utils.py b/backend/apps/common/utils.py index d5f6a9e49c..42b0c13192 100644 --- a/backend/apps/common/utils.py +++ b/backend/apps/common/utils.py @@ -4,6 +4,7 @@ import re from datetime import UTC, datetime +from typing import TYPE_CHECKING from urllib.parse import urlparse from django.conf import settings @@ -12,6 +13,9 @@ from django.utils.text import slugify as django_slugify from humanize import intword, naturaltime +if TYPE_CHECKING: + from django.http import HttpRequest + def convert_to_camel_case(text: str) -> str: """Convert a string to camelCase. @@ -23,11 +27,11 @@ def convert_to_camel_case(text: str) -> str: str: The converted string in camelCase. """ - parts = text.split("_") - offset = 1 if text.startswith("_") else 0 - head = parts[offset : offset + 1] or [text] + parts: list[str] = text.split("_") + offset: int = 1 if text.startswith("_") else 0 + head: list[str] = parts[offset : offset + 1] or [text] - segments = [f"_{head[0]}" if offset else head[0]] + segments: list[str] = [f"_{head[0]}" if offset else head[0]] segments.extend(word.capitalize() for word in parts[offset + 1 :]) return "".join(segments) @@ -46,11 +50,11 @@ def convert_to_snake_case(text: str) -> str: return re.sub(r"(? str | None: +def clean_url(url: str | None) -> str | None: """Clean a URL by removing whitespace and trailing punctuation. Args: - url (str): Raw URL string. + url (str | None): Raw URL string. Returns: str | None: Cleaned URL string or None if empty. @@ -78,14 +82,14 @@ def get_absolute_url(path: str) -> str: def get_nest_user_agent() -> str: """Return the user agent string for the Nest application. - Returns + Returns: str: The user agent string. """ return settings.APP_NAME.replace(" ", "-").lower() -def get_user_ip_address(request) -> str: +def get_user_ip_address(request: HttpRequest) -> str: """Retrieve the user's IP address from the request. Args: @@ -98,8 +102,10 @@ def get_user_ip_address(request) -> str: if settings.IS_LOCAL_ENVIRONMENT: return settings.PUBLIC_IP_ADDRESS - x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR") - return x_forwarded_for.split(",")[0] if x_forwarded_for else request.META.get("REMOTE_ADDR") + x_forwarded_for: str | None = request.META.get("HTTP_X_FORWARDED_FOR") + if x_forwarded_for: + return x_forwarded_for.split(",")[0] + return request.META.get("REMOTE_ADDR", "") def join_values(fields: list, delimiter: str = " ") -> str: @@ -116,18 +122,18 @@ def join_values(fields: list, delimiter: str = " ") -> str: return delimiter.join(field for field in fields if field) -def natural_date(value: int | str) -> str: +def natural_date(value: int | str | datetime) -> str: """Convert a date or timestamp into a human-readable format. Args: - value (str or int or datetime): The date or timestamp to convert. + value (str | int | datetime): The date or timestamp to convert. Returns: str: The humanized date string. """ if isinstance(value, str): - dt = datetime.strptime(value, "%Y-%m-%d").replace(tzinfo=UTC) + dt: datetime = datetime.strptime(value, "%Y-%m-%d").replace(tzinfo=UTC) elif isinstance(value, int): dt = datetime.fromtimestamp(value, tz=UTC) else: @@ -136,18 +142,18 @@ def natural_date(value: int | str) -> str: return naturaltime(dt) -def natural_number(value: int, unit=None) -> str: +def natural_number(value: int, unit: str | None = None) -> str: """Convert a number into a human-readable format. Args: value (int): The number to convert. - unit (str, optional): The unit to append. + unit (str | None, optional): The unit to append. Returns: str: The humanized number string. """ - number = intword(value) + number: str = intword(value) return f"{number} {unit}{pluralize(value)}" if unit else number @@ -155,8 +161,8 @@ def round_down(value: int, base: int) -> int: """Round down the stats to the nearest base. Args: - value: The value to round down. - base: The base to round down to. + value (int): The value to round down. + base (int): The base to round down to. Returns: int: The rounded down value. @@ -193,11 +199,11 @@ def truncate(text: str, limit: int, truncate: str = "...") -> str: return Truncator(text).chars(limit, truncate=truncate) -def validate_url(url: str) -> bool: +def validate_url(url: str | None) -> bool: """Validate that a URL has proper scheme and netloc. Args: - url (str): URL string to validate. + url (str | None): URL string to validate. Returns: bool: True if URL is valid, False otherwise. diff --git a/backend/apps/github/utils.py b/backend/apps/github/utils.py index 647c4fb811..813b2d203c 100644 --- a/backend/apps/github/utils.py +++ b/backend/apps/github/utils.py @@ -33,12 +33,12 @@ def check_owasp_site_repository(key: str) -> bool: ) -def check_funding_policy_compliance(platform: str, target: str) -> bool: +def check_funding_policy_compliance(platform: str, target: str | None) -> bool: """Check OWASP funding policy compliance. Args: platform (str): The funding platform (e.g., 'github', 'custom'). - target (str): The funding target. + target (str | None): The funding target. Returns: bool: True if the funding policy is compliant, False otherwise. @@ -50,8 +50,8 @@ def check_funding_policy_compliance(platform: str, target: str) -> bool: if platform == "github": return target.lower() == "owasp" if platform == "custom": - location = urlparse(target).netloc.lower() - owasp_org = "owasp.org" + location: str = urlparse(target).netloc.lower() + owasp_org: str = "owasp.org" return location == owasp_org or location.endswith(f".{owasp_org}") return False @@ -66,17 +66,19 @@ def get_repository_file_content( Args: url (str): The URL of the file. - timeout (int, optional): The request timeout in seconds. + timeout (float | None, optional): The request timeout in seconds. Returns: - str: The content of the file, or None if the request fails. + str: The content of the file, or empty string if the request fails. """ try: - return requests.get(url, timeout=timeout).text + response: requests.Response = requests.get(url, timeout=timeout) except RequestException as e: logger.exception("Failed to fetch file", extra={"URL": url, "error": str(e)}) return "" + else: + return response.text def get_repository_path(url: str) -> str | None: @@ -86,7 +88,8 @@ def get_repository_path(url: str) -> str | None: url (str): The repository URL. Returns: - str: The repository path in the format 'owner/repository_name', or None if parsing fails. + str | None: The repository path in the format 'owner/repository_name', + or None if parsing fails. """ match = GITHUB_REPOSITORY_RE.search(url.split("#")[0]) @@ -101,19 +104,19 @@ def normalize_url(url: str, *, check_path: bool = False) -> str | None: check_path (bool, optional): Whether to check if the URL has a path. Returns: - str: The normalized URL, or None if the URL is invalid. + str | None: The normalized URL, or None if the URL is invalid. """ parsed_url = urlparse(url) if not parsed_url.netloc or (check_path and not parsed_url.path): return None - http_prefix = "http://" # NOSONAR - https_prefix = "https://" + http_prefix: str = "http://" # NOSONAR + https_prefix: str = "https://" if not parsed_url.scheme: url = f"{https_prefix}{url}" - normalized_url = ( + normalized_url: str = ( f"{https_prefix}{url[len(http_prefix) :]}" if url.startswith(http_prefix) else url ) diff --git a/backend/apps/slack/utils.py b/backend/apps/slack/utils.py index 66c42c0e80..769b23dae1 100644 --- a/backend/apps/slack/utils.py +++ b/backend/apps/slack/utils.py @@ -6,7 +6,7 @@ import re from functools import lru_cache from html import escape as escape_html -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any from urllib.parse import urljoin if TYPE_CHECKING: # pragma: no cover @@ -22,7 +22,7 @@ logger: logging.Logger = logging.getLogger(__name__) -def escape(content) -> str: +def escape(content: str) -> str: """Escape HTML content. Args: @@ -35,8 +35,24 @@ def escape(content) -> str: return escape_html(content, quote=False) +def format_links_for_slack(text: str) -> str: + """Convert Markdown links to Slack markdown link format. + + Args: + text (str): The input text that may include Markdown links. + + Returns: + str: Text with Markdown links converted to Slack markdown links. + + """ + if not text: + return text + markdown_link_pattern = re.compile(r"\[([^\]]+)\]\((https?://[^\s)]+)\)") + return markdown_link_pattern.sub(r"<\2|\1>", text) + + @lru_cache -def get_gsoc_projects(year: int) -> list: +def get_gsoc_projects(year: int) -> list[dict[str, Any]]: """Get GSoC projects. Args: @@ -66,18 +82,19 @@ def get_news_data(limit: int = 10, timeout: float | None = 30) -> list[dict[str, Args: limit (int, optional): The maximum number of news items to fetch. + timeout (int, optional): The request timeout in seconds. Returns: list: A list of dictionaries containing news data (author, title, and URL). """ - response = requests.get(OWASP_NEWS_URL, timeout=timeout) + response: requests.Response = requests.get(OWASP_NEWS_URL, timeout=timeout) tree = html.fromstring(response.content) h2_tags = tree.xpath("//h2") - items_total = 0 - items = [] + items_total: int = 0 + items: list[dict[str, str]] = [] for h2 in h2_tags: if anchor := h2.xpath(".//a[@href]"): author_tag = h2.xpath("./following-sibling::p[@class='author']") @@ -97,7 +114,7 @@ def get_news_data(limit: int = 10, timeout: float | None = 30) -> list[dict[str, @lru_cache -def get_staff_data(timeout: float | None = 30) -> list | None: +def get_staff_data(timeout: float | None = 30) -> list[dict[str, Any]] | None: """Get staff data. Args: @@ -107,7 +124,7 @@ def get_staff_data(timeout: float | None = 30) -> list | None: list or None: A sorted list of staff data dictionaries, or None if an error occurs. """ - file_path = "https://raw.githubusercontent.com/OWASP/owasp.github.io/main/_data/staff.yml" + file_path: str = "https://raw.githubusercontent.com/OWASP/owasp.github.io/main/_data/staff.yml" try: return sorted( yaml.safe_load( @@ -127,10 +144,10 @@ def get_sponsors_data(limit: int = 10) -> QuerySet | None: """Get sponsors data. Args: - limit (int, optional): The maximum number of sponsors to fetch. + limit: The maximum number of sponsors to fetch. Returns: - QuerySet or None: A queryset of sponsors, or None if an error occurs. + A queryset of sponsors, or None if an error occurs. """ from apps.owasp.models.sponsor import Sponsor @@ -147,10 +164,10 @@ def get_posts_data(limit: int = 5) -> QuerySet | None: """Get posts data. Args: - limit (int, optional): The maximum number of posts to fetch. + limit (int, optional): The maximum number of sponsors to fetch. Returns: - QuerySet or None: A queryset of recent posts, or None if an error occurs. + QuerySet or None: A queryset of sponsors, or None if an error occurs. """ from apps.owasp.models.post import Post @@ -162,7 +179,7 @@ def get_posts_data(limit: int = 5) -> QuerySet | None: return None -def get_text(blocks: tuple) -> str: +def get_text(blocks: tuple[dict[str, Any], ...]) -> str: """Convert blocks to plain text. Args: @@ -172,7 +189,7 @@ def get_text(blocks: tuple) -> str: str: The plain text representation of the blocks. """ - text = [] + text: list[str] = [] for block in blocks: match block.get("type"): @@ -219,11 +236,11 @@ def strip_markdown(text: str) -> str: """Strip markdown formatting. Args: - text (str): The text with markdown formatting. + text: The text with markdown formatting. Returns: - str: The text with markdown formatting removed. + The text with markdown formatting removed. """ - slack_link_pattern = re.compile(r"<(https?://[^|]+)\|([^>]+)>") + slack_link_pattern: re.Pattern[str] = re.compile(r"<(https?://[^|]+)\|([^>]+)>") return slack_link_pattern.sub(r"\2 (\1)", text).replace("*", "") From 08648c3fbb694f84984fea64c7fca5824d58a6ff Mon Sep 17 00:00:00 2001 From: dhirukumar Date: Tue, 18 Nov 2025 23:27:34 +0530 Subject: [PATCH 2/9] fix: added type hints to utility functions across common, github, and slack apps --- backend/apps/common/utils.py | 8 ++++---- backend/apps/github/utils.py | 4 ++-- backend/apps/slack/utils.py | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/backend/apps/common/utils.py b/backend/apps/common/utils.py index 42b0c13192..78b7768b6b 100644 --- a/backend/apps/common/utils.py +++ b/backend/apps/common/utils.py @@ -27,9 +27,9 @@ def convert_to_camel_case(text: str) -> str: str: The converted string in camelCase. """ - parts: list[str] = text.split("_") - offset: int = 1 if text.startswith("_") else 0 - head: list[str] = parts[offset : offset + 1] or [text] + parts = text.split("_") + offset = 1 if text.startswith("_") else 0 + head = parts[offset : offset + 1] or [text] segments: list[str] = [f"_{head[0]}" if offset else head[0]] segments.extend(word.capitalize() for word in parts[offset + 1 :]) @@ -147,7 +147,7 @@ def natural_number(value: int, unit: str | None = None) -> str: Args: value (int): The number to convert. - unit (str | None, optional): The unit to append. + unit (str , optional): The unit to append. Returns: str: The humanized number string. diff --git a/backend/apps/github/utils.py b/backend/apps/github/utils.py index 813b2d203c..50e3ca362e 100644 --- a/backend/apps/github/utils.py +++ b/backend/apps/github/utils.py @@ -38,7 +38,7 @@ def check_funding_policy_compliance(platform: str, target: str | None) -> bool: Args: platform (str): The funding platform (e.g., 'github', 'custom'). - target (str | None): The funding target. + target (str, optional): The funding target. Returns: bool: True if the funding policy is compliant, False otherwise. @@ -66,7 +66,7 @@ def get_repository_file_content( Args: url (str): The URL of the file. - timeout (float | None, optional): The request timeout in seconds. + timeout (float, optional): The request timeout in seconds. Returns: str: The content of the file, or empty string if the request fails. diff --git a/backend/apps/slack/utils.py b/backend/apps/slack/utils.py index 769b23dae1..4e74a2bb21 100644 --- a/backend/apps/slack/utils.py +++ b/backend/apps/slack/utils.py @@ -144,7 +144,7 @@ def get_sponsors_data(limit: int = 10) -> QuerySet | None: """Get sponsors data. Args: - limit: The maximum number of sponsors to fetch. + limit(int, optional): The maximum number of sponsors to fetch. Returns: A queryset of sponsors, or None if an error occurs. @@ -164,7 +164,7 @@ def get_posts_data(limit: int = 5) -> QuerySet | None: """Get posts data. Args: - limit (int, optional): The maximum number of sponsors to fetch. + limit (int, optional): The maximum number of posts to fetch. Returns: QuerySet or None: A queryset of sponsors, or None if an error occurs. @@ -236,7 +236,7 @@ def strip_markdown(text: str) -> str: """Strip markdown formatting. Args: - text: The text with markdown formatting. + text(str): The text with markdown formatting. Returns: The text with markdown formatting removed. From e232859b8e9cab9351bb9c369a0cdf92cfe9c027 Mon Sep 17 00:00:00 2001 From: dhirukumar Date: Wed, 19 Nov 2025 20:41:52 +0530 Subject: [PATCH 3/9] Add type hints to utils.py files (common, github, slack) --- backend/apps/common/utils.py | 6 +++--- backend/apps/slack/utils.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/apps/common/utils.py b/backend/apps/common/utils.py index 0ab627f89e..12c6a5013b 100644 --- a/backend/apps/common/utils.py +++ b/backend/apps/common/utils.py @@ -32,7 +32,7 @@ def convert_to_camel_case(text: str) -> str: offset = 1 if text.startswith("_") else 0 head = parts[offset : offset + 1] or [text] - segments: list[str] = [f"_{head[0]}" if offset else head[0]] + segments = [f"_{head[0]}" if offset else head[0]] segments.extend(word.capitalize() for word in parts[offset + 1 :]) return "".join(segments) @@ -165,13 +165,13 @@ def natural_number(value: int, unit: str | None = None) -> str: Args: value (int): The number to convert. - unit (str , optional): The unit to append. + unit (str,optional): The unit to append. Returns: str: The humanized number string. """ - number: str = intword(value) + number = intword(value) return f"{number} {unit}{pluralize(value)}" if unit else number diff --git a/backend/apps/slack/utils.py b/backend/apps/slack/utils.py index b7b321542f..a5b6836bb4 100644 --- a/backend/apps/slack/utils.py +++ b/backend/apps/slack/utils.py @@ -168,7 +168,7 @@ def get_posts_data(limit: int = 5) -> QuerySet | None: limit (int, optional): The maximum number of posts to fetch. Returns: - QuerySet or None: A queryset of sponsors, or None if an error occurs. + QuerySet or None: A queryset of recent posts, or None if an error occurs. """ from apps.owasp.models.post import Post From 6a68656c832919503d00fdcecacadf07224d4b98 Mon Sep 17 00:00:00 2001 From: dhirukumar Date: Wed, 19 Nov 2025 23:08:40 +0530 Subject: [PATCH 4/9] make all changes according to issue and the suggistationfrom rudransh-shrivastava --- backend/apps/common/utils.py | 14 ++++++-------- backend/apps/github/utils.py | 14 +++++++------- backend/apps/slack/utils.py | 4 ++-- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/backend/apps/common/utils.py b/backend/apps/common/utils.py index 12c6a5013b..4cda7a73d6 100644 --- a/backend/apps/common/utils.py +++ b/backend/apps/common/utils.py @@ -55,7 +55,7 @@ def clean_url(url: str | None) -> str | None: """Clean a URL by removing whitespace and trailing punctuation. Args: - url (str | None): Raw URL string. + url (str | optional): Raw URL string. Returns: str | None: Cleaned URL string or None if empty. @@ -103,10 +103,8 @@ def get_user_ip_address(request: HttpRequest) -> str: if settings.IS_LOCAL_ENVIRONMENT: return settings.PUBLIC_IP_ADDRESS - x_forwarded_for: str | None = request.META.get("HTTP_X_FORWARDED_FOR") - if x_forwarded_for: - return x_forwarded_for.split(",")[0] - return request.META.get("REMOTE_ADDR", "") + x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR") + return x_forwarded_for.split(",")[0] if x_forwarded_for else request.META.get("REMOTE_ADDR") def is_valid_json(content: str) -> bool: @@ -151,7 +149,7 @@ def natural_date(value: int | str | datetime) -> str: """ if isinstance(value, str): - dt: datetime = datetime.strptime(value, "%Y-%m-%d").replace(tzinfo=UTC) + dt = datetime.strptime(value, "%Y-%m-%d").replace(tzinfo=UTC) elif isinstance(value, int): dt = datetime.fromtimestamp(value, tz=UTC) else: @@ -165,7 +163,7 @@ def natural_number(value: int, unit: str | None = None) -> str: Args: value (int): The number to convert. - unit (str,optional): The unit to append. + unit (str, optional): The unit to append. Returns: str: The humanized number string. @@ -221,7 +219,7 @@ def validate_url(url: str | None) -> bool: """Validate that a URL has proper scheme and netloc. Args: - url (str | None): URL string to validate. + url (str | optional): URL string to validate. Returns: bool: True if URL is valid, False otherwise. diff --git a/backend/apps/github/utils.py b/backend/apps/github/utils.py index 50e3ca362e..9d2eea722d 100644 --- a/backend/apps/github/utils.py +++ b/backend/apps/github/utils.py @@ -50,8 +50,8 @@ def check_funding_policy_compliance(platform: str, target: str | None) -> bool: if platform == "github": return target.lower() == "owasp" if platform == "custom": - location: str = urlparse(target).netloc.lower() - owasp_org: str = "owasp.org" + location = urlparse(target).netloc.lower() + owasp_org = "owasp.org" return location == owasp_org or location.endswith(f".{owasp_org}") return False @@ -88,7 +88,7 @@ def get_repository_path(url: str) -> str | None: url (str): The repository URL. Returns: - str | None: The repository path in the format 'owner/repository_name', + str : The repository path in the format 'owner/repository_name', or None if parsing fails. """ @@ -104,19 +104,19 @@ def normalize_url(url: str, *, check_path: bool = False) -> str | None: check_path (bool, optional): Whether to check if the URL has a path. Returns: - str | None: The normalized URL, or None if the URL is invalid. + str : The normalized URL, or None if the URL is invalid. """ parsed_url = urlparse(url) if not parsed_url.netloc or (check_path and not parsed_url.path): return None - http_prefix: str = "http://" # NOSONAR - https_prefix: str = "https://" + http_prefix = "http://" # NOSONAR + https_prefix = "https://" if not parsed_url.scheme: url = f"{https_prefix}{url}" - normalized_url: str = ( + normalized_url = ( f"{https_prefix}{url[len(http_prefix) :]}" if url.startswith(http_prefix) else url ) diff --git a/backend/apps/slack/utils.py b/backend/apps/slack/utils.py index a5b6836bb4..bf168447c7 100644 --- a/backend/apps/slack/utils.py +++ b/backend/apps/slack/utils.py @@ -145,7 +145,7 @@ def get_sponsors_data(limit: int = 10) -> QuerySet | None: """Get sponsors data. Args: - limit(int, optional): The maximum number of sponsors to fetch. + limit (int, optional): The maximum number of sponsors to fetch. Returns: A queryset of sponsors, or None if an error occurs. @@ -237,7 +237,7 @@ def strip_markdown(text: str) -> str: """Strip markdown formatting. Args: - text(str): The text with markdown formatting. + text (str): The text with markdown formatting. Returns: The text with markdown formatting removed. From 51012fa89bee317d1f5094bd0870cf25b96e543e Mon Sep 17 00:00:00 2001 From: Rudransh Shrivastava Date: Sat, 22 Nov 2025 00:39:45 +0530 Subject: [PATCH 5/9] Update code --- backend/apps/common/utils.py | 6 +++--- backend/apps/github/utils.py | 10 ++++------ backend/apps/slack/utils.py | 33 ++++++++++++++++----------------- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/backend/apps/common/utils.py b/backend/apps/common/utils.py index 4cda7a73d6..1929939294 100644 --- a/backend/apps/common/utils.py +++ b/backend/apps/common/utils.py @@ -55,7 +55,7 @@ def clean_url(url: str | None) -> str | None: """Clean a URL by removing whitespace and trailing punctuation. Args: - url (str | optional): Raw URL string. + url (str, optional): Raw URL string. Returns: str | None: Cleaned URL string or None if empty. @@ -142,7 +142,7 @@ def natural_date(value: int | str | datetime) -> str: """Convert a date or timestamp into a human-readable format. Args: - value (str | int | datetime): The date or timestamp to convert. + value (int | str | datetime): The date or timestamp to convert. Returns: str: The humanized date string. @@ -219,7 +219,7 @@ def validate_url(url: str | None) -> bool: """Validate that a URL has proper scheme and netloc. Args: - url (str | optional): URL string to validate. + url (str, optional): URL string to validate. Returns: bool: True if URL is valid, False otherwise. diff --git a/backend/apps/github/utils.py b/backend/apps/github/utils.py index 9d2eea722d..f404dad3b1 100644 --- a/backend/apps/github/utils.py +++ b/backend/apps/github/utils.py @@ -73,12 +73,10 @@ def get_repository_file_content( """ try: - response: requests.Response = requests.get(url, timeout=timeout) + return requests.get(url, timeout=timeout).text except RequestException as e: logger.exception("Failed to fetch file", extra={"URL": url, "error": str(e)}) return "" - else: - return response.text def get_repository_path(url: str) -> str | None: @@ -88,8 +86,8 @@ def get_repository_path(url: str) -> str | None: url (str): The repository URL. Returns: - str : The repository path in the format 'owner/repository_name', - or None if parsing fails. + str | None: The repository path in the format 'owner/repository_name', + or None if parsing fails. """ match = GITHUB_REPOSITORY_RE.search(url.split("#")[0]) @@ -104,7 +102,7 @@ def normalize_url(url: str, *, check_path: bool = False) -> str | None: check_path (bool, optional): Whether to check if the URL has a path. Returns: - str : The normalized URL, or None if the URL is invalid. + str | None: The normalized URL, or None if the URL is invalid. """ parsed_url = urlparse(url) diff --git a/backend/apps/slack/utils.py b/backend/apps/slack/utils.py index bf168447c7..43b4b1c624 100644 --- a/backend/apps/slack/utils.py +++ b/backend/apps/slack/utils.py @@ -6,7 +6,7 @@ import re from functools import lru_cache from html import escape as escape_html -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING from urllib.parse import urljoin if TYPE_CHECKING: # pragma: no cover @@ -53,7 +53,7 @@ def format_links_for_slack(text: str) -> str: @lru_cache -def get_gsoc_projects(year: int) -> list[dict[str, Any]]: +def get_gsoc_projects(year: int) -> list: """Get GSoC projects. Args: @@ -83,19 +83,18 @@ def get_news_data(limit: int = 10, timeout: float | None = 30) -> list[dict[str, Args: limit (int, optional): The maximum number of news items to fetch. - - timeout (int, optional): The request timeout in seconds. + timeout (float, optional): The request timeout in seconds. Returns: list: A list of dictionaries containing news data (author, title, and URL). """ - response: requests.Response = requests.get(OWASP_NEWS_URL, timeout=timeout) + response = requests.get(OWASP_NEWS_URL, timeout=timeout) tree = html.fromstring(response.content) h2_tags = tree.xpath("//h2") - items_total: int = 0 - items: list[dict[str, str]] = [] + items_total = 0 + items = [] for h2 in h2_tags: if anchor := h2.xpath(".//a[@href]"): author_tag = h2.xpath("./following-sibling::p[@class='author']") @@ -115,17 +114,17 @@ def get_news_data(limit: int = 10, timeout: float | None = 30) -> list[dict[str, @lru_cache -def get_staff_data(timeout: float | None = 30) -> list[dict[str, Any]] | None: +def get_staff_data(timeout: float | None = 30) -> list | None: """Get staff data. Args: - timeout (int, optional): The request timeout in seconds. + timeout (float, optional): The request timeout in seconds. Returns: - list or None: A sorted list of staff data dictionaries, or None if an error occurs. + list | None: A sorted list of staff data dictionaries, or None if an error occurs. """ - file_path: str = "https://raw.githubusercontent.com/OWASP/owasp.github.io/main/_data/staff.yml" + file_path = "https://raw.githubusercontent.com/OWASP/owasp.github.io/main/_data/staff.yml" try: return sorted( yaml.safe_load( @@ -148,7 +147,7 @@ def get_sponsors_data(limit: int = 10) -> QuerySet | None: limit (int, optional): The maximum number of sponsors to fetch. Returns: - A queryset of sponsors, or None if an error occurs. + QuerySet | None: A queryset of sponsors, or None if an error occurs. """ from apps.owasp.models.sponsor import Sponsor @@ -168,7 +167,7 @@ def get_posts_data(limit: int = 5) -> QuerySet | None: limit (int, optional): The maximum number of posts to fetch. Returns: - QuerySet or None: A queryset of recent posts, or None if an error occurs. + QuerySet | None: A queryset of recent posts, or None if an error occurs. """ from apps.owasp.models.post import Post @@ -180,7 +179,7 @@ def get_posts_data(limit: int = 5) -> QuerySet | None: return None -def get_text(blocks: tuple[dict[str, Any], ...]) -> str: +def get_text(blocks: tuple) -> str: """Convert blocks to plain text. Args: @@ -190,7 +189,7 @@ def get_text(blocks: tuple[dict[str, Any], ...]) -> str: str: The plain text representation of the blocks. """ - text: list[str] = [] + text = [] for block in blocks: match block.get("type"): @@ -240,8 +239,8 @@ def strip_markdown(text: str) -> str: text (str): The text with markdown formatting. Returns: - The text with markdown formatting removed. + str: The text with markdown formatting removed. """ - slack_link_pattern: re.Pattern[str] = re.compile(r"<(https?://[^|]+)\|([^>]+)>") + slack_link_pattern = re.compile(r"<(https?://[^|]+)\|([^>]+)>") return slack_link_pattern.sub(r"\2 (\1)", text).replace("*", "") From 4738646d21bd638046e611d7a96aac00da9a8fac Mon Sep 17 00:00:00 2001 From: Rudransh Shrivastava Date: Sat, 22 Nov 2025 00:55:05 +0530 Subject: [PATCH 6/9] Update code --- backend/apps/common/utils.py | 2 +- backend/apps/github/utils.py | 4 ++-- backend/apps/slack/utils.py | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/apps/common/utils.py b/backend/apps/common/utils.py index 1929939294..ffb721bb96 100644 --- a/backend/apps/common/utils.py +++ b/backend/apps/common/utils.py @@ -142,7 +142,7 @@ def natural_date(value: int | str | datetime) -> str: """Convert a date or timestamp into a human-readable format. Args: - value (int | str | datetime): The date or timestamp to convert. + value (int or str or datetime): The date or timestamp to convert. Returns: str: The humanized date string. diff --git a/backend/apps/github/utils.py b/backend/apps/github/utils.py index f404dad3b1..37473f164e 100644 --- a/backend/apps/github/utils.py +++ b/backend/apps/github/utils.py @@ -86,7 +86,7 @@ def get_repository_path(url: str) -> str | None: url (str): The repository URL. Returns: - str | None: The repository path in the format 'owner/repository_name', + str or None: The repository path in the format 'owner/repository_name', or None if parsing fails. """ @@ -102,7 +102,7 @@ def normalize_url(url: str, *, check_path: bool = False) -> str | None: check_path (bool, optional): Whether to check if the URL has a path. Returns: - str | None: The normalized URL, or None if the URL is invalid. + str or None: The normalized URL, or None if the URL is invalid. """ parsed_url = urlparse(url) diff --git a/backend/apps/slack/utils.py b/backend/apps/slack/utils.py index 43b4b1c624..606a0ec07b 100644 --- a/backend/apps/slack/utils.py +++ b/backend/apps/slack/utils.py @@ -121,7 +121,7 @@ def get_staff_data(timeout: float | None = 30) -> list | None: timeout (float, optional): The request timeout in seconds. Returns: - list | None: A sorted list of staff data dictionaries, or None if an error occurs. + list or None: A sorted list of staff data dictionaries, or None if an error occurs. """ file_path = "https://raw.githubusercontent.com/OWASP/owasp.github.io/main/_data/staff.yml" @@ -147,7 +147,7 @@ def get_sponsors_data(limit: int = 10) -> QuerySet | None: limit (int, optional): The maximum number of sponsors to fetch. Returns: - QuerySet | None: A queryset of sponsors, or None if an error occurs. + QuerySet or None: A queryset of sponsors, or None if an error occurs. """ from apps.owasp.models.sponsor import Sponsor @@ -167,7 +167,7 @@ def get_posts_data(limit: int = 5) -> QuerySet | None: limit (int, optional): The maximum number of posts to fetch. Returns: - QuerySet | None: A queryset of recent posts, or None if an error occurs. + QuerySet or None: A queryset of recent posts, or None if an error occurs. """ from apps.owasp.models.post import Post From 6bb2d83e38ecc50b6c9667205b4cf41164e194e3 Mon Sep 17 00:00:00 2001 From: Arkadii Yakovets Date: Fri, 21 Nov 2025 11:33:35 -0800 Subject: [PATCH 7/9] Update code --- backend/apps/github/utils.py | 4 ++-- backend/apps/slack/utils.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/apps/github/utils.py b/backend/apps/github/utils.py index 37473f164e..3f94b32288 100644 --- a/backend/apps/github/utils.py +++ b/backend/apps/github/utils.py @@ -60,13 +60,13 @@ def check_funding_policy_compliance(platform: str, target: str | None) -> bool: def get_repository_file_content( url: str, *, - timeout: float | None = 30, + timeout: int | None = 30, ) -> str: """Get the content of a file from a repository. Args: url (str): The URL of the file. - timeout (float, optional): The request timeout in seconds. + timeout (int, optional): The request timeout in seconds. Returns: str: The content of the file, or empty string if the request fails. diff --git a/backend/apps/slack/utils.py b/backend/apps/slack/utils.py index 606a0ec07b..f1806c6401 100644 --- a/backend/apps/slack/utils.py +++ b/backend/apps/slack/utils.py @@ -78,12 +78,12 @@ def get_gsoc_projects(year: int) -> list: @lru_cache -def get_news_data(limit: int = 10, timeout: float | None = 30) -> list[dict[str, str]]: +def get_news_data(limit: int = 10, timeout: int | None = 30) -> list[dict[str, str]]: """Get news data. Args: limit (int, optional): The maximum number of news items to fetch. - timeout (float, optional): The request timeout in seconds. + timeout (int, optional): The request timeout in seconds. Returns: list: A list of dictionaries containing news data (author, title, and URL). @@ -114,11 +114,11 @@ def get_news_data(limit: int = 10, timeout: float | None = 30) -> list[dict[str, @lru_cache -def get_staff_data(timeout: float | None = 30) -> list | None: +def get_staff_data(timeout: int | None = 30) -> list | None: """Get staff data. Args: - timeout (float, optional): The request timeout in seconds. + timeout (int, optional): The request timeout in seconds. Returns: list or None: A sorted list of staff data dictionaries, or None if an error occurs. From 064c9829d0e041b4539d356a0f97a5164dd2926e Mon Sep 17 00:00:00 2001 From: dhirukumar Date: Sat, 22 Nov 2025 11:03:57 +0530 Subject: [PATCH 8/9] Fix timeout type annotation to match requests library --- backend/apps/github/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/apps/github/utils.py b/backend/apps/github/utils.py index 3f94b32288..d001f5bb46 100644 --- a/backend/apps/github/utils.py +++ b/backend/apps/github/utils.py @@ -60,7 +60,7 @@ def check_funding_policy_compliance(platform: str, target: str | None) -> bool: def get_repository_file_content( url: str, *, - timeout: int | None = 30, + timeout: float | tuple[float, float] | None = 30 ) -> str: """Get the content of a file from a repository. From 0cb6c6adcf9ad50e7476fa0623cbb7143b84b6a6 Mon Sep 17 00:00:00 2001 From: Arkadii Yakovets Date: Sat, 22 Nov 2025 09:34:35 -0800 Subject: [PATCH 9/9] Update code --- backend/apps/github/utils.py | 10 +++------- backend/apps/slack/utils.py | 8 ++++---- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/backend/apps/github/utils.py b/backend/apps/github/utils.py index d001f5bb46..cc8c331ef1 100644 --- a/backend/apps/github/utils.py +++ b/backend/apps/github/utils.py @@ -57,16 +57,12 @@ def check_funding_policy_compliance(platform: str, target: str | None) -> bool: return False -def get_repository_file_content( - url: str, - *, - timeout: float | tuple[float, float] | None = 30 -) -> str: +def get_repository_file_content(url: str, *, timeout: float | None = 30) -> str: """Get the content of a file from a repository. Args: url (str): The URL of the file. - timeout (int, optional): The request timeout in seconds. + timeout (float, optional): The request timeout in seconds. Returns: str: The content of the file, or empty string if the request fails. @@ -102,7 +98,7 @@ def normalize_url(url: str, *, check_path: bool = False) -> str | None: check_path (bool, optional): Whether to check if the URL has a path. Returns: - str or None: The normalized URL, or None if the URL is invalid. + str | None: The normalized URL, or None if the URL is invalid. """ parsed_url = urlparse(url) diff --git a/backend/apps/slack/utils.py b/backend/apps/slack/utils.py index f1806c6401..606a0ec07b 100644 --- a/backend/apps/slack/utils.py +++ b/backend/apps/slack/utils.py @@ -78,12 +78,12 @@ def get_gsoc_projects(year: int) -> list: @lru_cache -def get_news_data(limit: int = 10, timeout: int | None = 30) -> list[dict[str, str]]: +def get_news_data(limit: int = 10, timeout: float | None = 30) -> list[dict[str, str]]: """Get news data. Args: limit (int, optional): The maximum number of news items to fetch. - timeout (int, optional): The request timeout in seconds. + timeout (float, optional): The request timeout in seconds. Returns: list: A list of dictionaries containing news data (author, title, and URL). @@ -114,11 +114,11 @@ def get_news_data(limit: int = 10, timeout: int | None = 30) -> list[dict[str, s @lru_cache -def get_staff_data(timeout: int | None = 30) -> list | None: +def get_staff_data(timeout: float | None = 30) -> list | None: """Get staff data. Args: - timeout (int, optional): The request timeout in seconds. + timeout (float, optional): The request timeout in seconds. Returns: list or None: A sorted list of staff data dictionaries, or None if an error occurs.