Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 141 additions & 0 deletions Day-11/screener-integration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import json

import requests

try:
import brotli
except ImportError: # pragma: no cover - optional dependency
brotli = None

URL = "https://chartink.com/screener/process"

HEADERS = {
"accept": "*/*",
"accept-encoding": "gzip, deflate, br, zstd",
"accept-language": "en-GB,en-US;q=0.9,en;q=0.8",
"content-type": "application/json",
"origin": "https://chartink.com",
"priority": "u=1, i",
"referer": "https://chartink.com/screener/copy-rsi-above-55-and-breakout-615",
"sec-ch-ua": '"Not;A=Brand";v="8", "Chromium";v="150", "Google Chrome";v="150"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"macOS"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36",
"x-requested-with": "XMLHttpRequest",
"x-xsrf-token": "eyJpdiI6IkVhTE9nVThwZk1aY0ppQWFDMVFKOGc9PSIsInZhbHVlIjoiZ1MxQUdZL2NCYzJHWHFQelZJTElqSVFWWlBnclBZYzZ5YW9CdTRQRkRNOXZ0bmpxZHhnOWIzQ3piYXBGZkRQQVpIQU4rL2lnakFmT1YxVzJRWHRzUzlmYUJBMWtTZUxNVXc1aVg1a3M3czBwZTFmbzRQUXJvY3ZOY0gwSHZOV1AiLCJtYWMiOiJjNjhlZTJkZTg4ZmE4NDAzZDljOWQ2MjJhMjQxMzM4OGUxNzMzODU5NjM4MGVkODE4YWJmNTg2Zjg1YjAxNzJiIiwidGFnIjoiIn0=",
Comment on lines +12 to +28

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate file =="
git ls-files | grep -F 'Day-11/screener-integration.py' || true

echo "== file outline/size =="
wc -l Day-11/screener-integration.py
ast-grep outline Day-11/screener-integration.py || true

echo "== relevant source lines =="
sed -n '1,120p' Day-11/screener-integration.py | nl -ba

echo "== search encoding/response handling/search all script references =="
rg -n "accept-encoding|Response|br|brotli|zstd|content-encoding|response\.text|response\.json|gzip|deflate" Day-11/screener-integration.py || true

echo "== package hints =="
for f in requirements.txt pyproject.toml Pipfile setup.py setup.cfg; do
  [ -e "$f" ] && { echo "--- $f"; sed -n '1,200p' "$f"; }
done

Repository: iam-veeramalla/python-for-devops

Length of output: 1524


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== complete relevant source lines =="
sed -n '1,145p' Day-11/screener-integration.py

echo "== package hints =="
for f in requirements.txt pyproject.toml Pipfile setup.py setup.cfg; do
  if [ -e "$f" ]; then
    echo "--- $f"
    sed -n '1,200p' "$f"
  fi
done

echo "== Python dependency/runtime hints from checked files =="
python3 - <<'PY'
from pathlib import Path
for p in ["requirements.txt","pyproject.toml","Pipfile","setup.py","setup.cfg"]:
    if Path(p).exists():
        text = Path(p).read_text(errors="replace")
        print(f"\n--- {p}")
        for i,line in enumerate(text.splitlines(), 1):
            if "requests" in line.lower() or "brotli" in line.lower() or "zstandard" in line.lower() or "httpx" in line.lower():
                print(f"{i}: {line}")
PY

echo "== deterministic check: advertised encodings vs available decoders in Day-11 =="
python3 - <<'PY'
from pathlib import Path
src = Path("Day-11/screener-integration.py").read_text(errors="replace")
head = src[src.index("HEADERS = {"):src.index("}", src.index("HEADERS = {"))+1]
print("has zstd/zstandard import/decoder:", any(tok in src for tok in ["zstandard", "import zstd", "zstd."])
print("has brotli import/decoder:", "import brotmi" in src
PY

Repository: iam-veeramalla/python-for-devops

Length of output: 16873


🌐 Web query:

Python requests library content-encoding support gzip deflate brotli zstandard

💡 Result:

The Python Requests library provides automated decoding for several Content-Encoding types, delegating the underlying work to the urllib3 library [1][2]. Gzip and Deflate: Requests supports these transfer-encodings natively and decodes them automatically [2]. Brotli: Requests supports Brotli encoding automatically if a compatible Brotli library is installed in your environment [2]. Specifically, if either the 'brotli' or 'brotlicffi' package is available, Requests will include 'br' in the Accept-Encoding header and transparently handle the decoding of responses [1][3]. Zstandard (zstd): Requests does not have native support for Zstandard (zstd) decompression [4]. If the 'zstandard' library is installed, some third-party packages or system configurations may automatically include 'zstd' in the Accept-Encoding header, which can cause issues if your environment expects standard Requests behavior [4]. In such cases, users may need to manually uninstall the 'zstandard' package or explicitly override the Accept-Encoding header in their requests to exclude 'zstd' [4]. In summary, for gzip, deflate, and brotli, decompression is handled transparently, provided the necessary dependencies are present [2]. For other encodings like zstd, you may need to manage the headers or decompression manually [4].

Citations:


Do not advertise unsupported response encodings.

HEADERS["accept-encoding"] advertises zstd, but Day-11/screener-integration.py only conditionally supports Brotli and has no Zstandard decoder. Advertised encodings should be limited to codecs the intended runtime can decode; keep gzip, deflate if that is the supported baseline.

Proposed fix
-    "accept-encoding": "gzip, deflate, br, zstd",
+    "accept-encoding": "gzip, deflate",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
HEADERS = {
"accept": "*/*",
"accept-encoding": "gzip, deflate, br, zstd",
"accept-language": "en-GB,en-US;q=0.9,en;q=0.8",
"content-type": "application/json",
"origin": "https://chartink.com",
"priority": "u=1, i",
"referer": "https://chartink.com/screener/copy-rsi-above-55-and-breakout-615",
"sec-ch-ua": '"Not;A=Brand";v="8", "Chromium";v="150", "Google Chrome";v="150"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"macOS"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36",
"x-requested-with": "XMLHttpRequest",
"x-xsrf-token": "eyJpdiI6IkVhTE9nVThwZk1aY0ppQWFDMVFKOGc9PSIsInZhbHVlIjoiZ1MxQUdZL2NCYzJHWHFQelZJTElqSVFWWlBnclBZYzZ5YW9CdTRQRkRNOXZ0bmpxZHhnOWIzQ3piYXBGZkRQQVpIQU4rL2lnakFmT1YxVzJRWHRzUzlmYUJBMWtTZUxNVXc1aVg1a3M3czBwZTFmbzRQUXJvY3ZOY0gwSHZOV1AiLCJtYWMiOiJjNjhlZTJkZTg4ZmE4NDAzZDljOWQ2MjJhMjQxMzM4OGUxNzMzODU5NjM4MGVkODE4YWJmNTg2Zjg1YjAxNzJiIiwidGFnIjoiIn0=",
HEADERS = {
"accept": "*/*",
"accept-encoding": "gzip, deflate",
"accept-language": "en-GB,en-US;q=0.9,en;q=0.8",
"content-type": "application/json",
"origin": "https://chartink.com",
"priority": "u=1, i",
"referer": "https://chartink.com/screener/copy-rsi-above-55-and-breakout-615",
"sec-ch-ua": '"Not;A=Brand";v="8", "Chromium";v="150", "Google Chrome";v="150"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"macOS"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36",
"x-requested-with": "XMLHttpRequest",
"x-xsrf-token": "eyJpdiI6IkVhTE9nVThwZk1aY0ppQWFDMVFKOGc9PSIsInZhbHVlIjoiZ1MxQUdZL2NCYzJHWHFQelZJTElqSVFWWlBnclBZYzZ5YW9CdTRQRkRNOXZ0bmpxZHhnOWIzQ3piYXBGZkRQQVpIQU4rL2lnakFmT1YxVzJRWHRzUzlmYUJBMWtTZUxNVXc1aVg1a3M3czBwZTFmbzRQUXJvY3ZOY0gwSHZOV1AiLCJtYWMiOiJjNjhlZTJkZTg4ZmE4NDAzZDljOWQ2MjJhMjQxMzM4OGUxNzMzODU5NjM4MGVkODE4YWJmNTg2Zjg1YjAxNzJiIiwidGFnIjoiIn0=",
🧰 Tools
🪛 Betterleaks (1.7.0)

[high] 28-28: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Day-11/screener-integration.py` around lines 12 - 28, Update the
HEADERS["accept-encoding"] value to advertise only codecs supported by the
runtime; remove zstd and retain gzip, deflate, plus Brotli only if the existing
conditional decoding support is available.

}

cookie_header = (
"remember_web_59ba36addc2b2f9401580f014c7f58ea4e30989d=eyJpdiI6IkhDd05qM2pTT1JVZW0vdGVHOWNQYlE9PSIsInZhbHVlIjoiNWpJVlIzdW8vRnpWemJGWW80ZWVKelBQUmJqSUZiNy9MWW1HbXk5UEFTa2RWaEJFekNxY0F2bHRpc3M0S2hOR0JGQU5pbzZYNityTURhTGJrT25RcHVNQjR3N2dnNTNWRnhwV1o5QlNnT1ZVYlh4UWgrMWNuYlprM2VMR0tTZmoxczdRRXNFMnIzMndsaUp4MWp1bU00d0tKK3FyNnlhdDgyaytXdmZhUm91NGtLa25JcDYwYkIzTCs5M0Y0VDZnUk92ZWdVQytya0JIdkx1RGlsS1hZdzlUMEJ5RGJXSjZqb0Y3YytwK2V3VT0iLCJtYWMiOiJhOGZiOGY1ZDFiYmExNDRhNmVhMjRmZmExN2FmOGI1Y2VjMDYwZDNkNzZkOGMyOGIzYmM0OWU3M2VkZGEzZWY3IiwidGFnIjoiIn0%3D; _cc_id=ddd4893ce0c7883fd0816bb00b1dd02a; FCCDCF=%5Bnull%2Cnull%2Cnull%2Cnull%2Cnull%2Cnull%2C%5B%5B32%2C%22%5B%5C%226f1b27a0-7d11-4a14-98ae-03a35fed3e2a%5C%22%2C%5B1784555417%2C262000000%5D%5D%22%5D%5D%5D; FCNEC=%5B%5B%22AKsRol-TAHbJACJY4lTrE5ZSlvrKAxjPJXn5e-ns2BOn-gqwuibhr6NbHGZUaZzRF80Ca7kNMBb7QAhsRqSehMMwoudMOCcEK5KcwrhEfRWcCXflfJ6qWQ5mePeAXNlA69Fav4cxcIwmIYxtne0C09Q3gSkT2v11bg%3D%3D%22%5D%5D; __utma=102564947.1968319544.1784554512.1784685434.1784685434.1; __utmz=102564947.1784685434.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); _gid=GA1.2.1711244705.1785667224; _ga=GA1.1.1968319544.1784554512; XSRF-TOKEN=eyJpdiI6IkVhTE9nVThwZk1aY0ppQWFDMVFKOGc9PSIsInZhbHVlIjoiZ1MxQUdZL2NCYzJHWHFQelZJTElqSVFWWlBnclBZYzZ5YW9CdTRQRkRNOXZ0bmpxZHhnOWIzQ3piYXBGZkRQQVpIQU4rL2lnakFmT1YxVzJRWHRzUzlmYUJBMWtTZUxNVXc1aVg1a3M3czBwZTFmbzRQUXJvY3ZOY0gwSHZOV1AiLCJtYWMiOiJjNjhlZTJkZTg4ZmE4NDAzZDljOWQ2MjJhMjQxMzM4OGUxNzMzODU5NjM4MGVkODE4YWJmNTg2Zjg1YjAxNzJiIiwidGFnIjoiIn0%3D; ci_session=eyJpdiI6IkY1c09MOXdNc2JPcTZSUlRKNUNSS0E9PSIsInZhbHVlIjoiYjI0dG84dXNpTzV2czladlhSWC9qZmdEa0Ixa3JxTTRXTmU4QStEdUZTNmU5UURyYmpqbkk5VjREb0tYbUxTcE5NcEdXa09pdTdCQVQ1Qy9wMkIzNVgvQlMwU1Z6eEZHbmJDbXRBek1vREQ3RHF4VGs1U2hpMFJYaHlsNmdTZ2giLCJtYWMiOiIyNzZiYzMzNGRjOTlkYTJmNjZkN2Q5YzYyYWRmMTUyMGZhMWYwMDA1ZTQ3M2FhYmYxNzEwZmI5NjAzNWY5NjE4IiwidGFnIjoiIn0%3D; __gads=ID=a475dc11d13edfcf:T=1784555440:RT=1785667724:S=ALNI_MYui5MgqrqdpMh-ReKIEte6_hI-uA; __gpi=UID=000014cd24fad536:T=1784555440:RT=1785667724:S=ALNI_MZGgCFV-utYaaRCbqopFGIu-JkQow; __eoi=ID=262f680056f8b3e7:T=1784555440:RT=1785667724:S=AA-Afja56EFTSdPZv4hb308AWKUH; _ga_7P3KPC3ZPP=GS2.1.s1785665055$o7$g1$t1785667725$j33$l0$h0"
)

HEADERS["cookie"] = cookie_header
Comment on lines +28 to +35

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Remove the committed session credentials.

Line 28 embeds an XSRF token. Lines 31-35 embed remember_web, ci_session, and related browser cookies. An attacker can replay an unexpired authenticated session against ChartInk.

Revoke the exposed sessions and tokens. Remove these values from the repository and its history. Load required credentials from a local secret store or environment variables.

🧰 Tools
🪛 Betterleaks (1.7.0)

[high] 28-28: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 32-32: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Day-11/screener-integration.py` around lines 28 - 35, Remove the hardcoded
XSRF token and browser cookies from the header definitions, including
remember_web, ci_session, and related authentication values. Load any required
credentials through environment variables or a local secret store instead, and
rotate or revoke all exposed sessions and tokens and purge them from repository
history.

Source: Linters/SAST tools


COOKIES = {}
for raw_cookie in cookie_header.split(";"):
if "=" in raw_cookie:
key, value = raw_cookie.split("=", 1)
COOKIES[key.strip()] = value.strip()

PAYLOADS = {
"RSIAbove50": {
"scan_clause": "( {cash} ( weekly close >= 52 and daily ema( close,5 ) > daily ema( close,26 ) and daily ema( close,13 ) > daily ema( close,26 ) and daily close > 1 day ago close * 1.03 and daily volume > daily sma( volume,20 ) * 1.0 and daily ema( close,5 ) > daily ema( close,13 ) and daily high = daily max( 260 , daily high ) * 1 and 1 day ago close > 2 days ago close * 0.98 and daily rsi( 14 ) > 55 ) )",
"debug_clause": "groupcount( 1 where weekly close >= 52),groupcount( 1 where daily ema( close,5 ) > daily ema( close,26 )),groupcount( 1 where daily ema( close,13 ) > daily ema( close,26 )),groupcount( 1 where daily close > 1 day ago close * 1.03),groupcount( 1 where daily volume > daily sma( volume,20 ) * 1.0),groupcount( 1 where daily ema( close,5 ) > daily ema( close,13 )),groupcount( 1 where daily high = daily max( 260 , daily high ) * 1),groupcount( 1 where 1 day ago close > 2 days ago close * 0.98),groupcount( 1 where daily rsi( 14 ) > 55)",
"column_clause": " Daily Close as 'scan-column-default-close', Daily \"close - 1 candle ago close / 1 candle ago close * 100\" as 'scan-column-default-percent-change', filternumber( daily close > 1 day ago close,1) as 'default-percent-change-conditional-filters-color', Daily Volume as 'scan-column-default-volume'",
},
"ShortTermBreakouts": {
"scan_clause": "( {cash} ( daily max( 5 , daily close ) > 6 days ago max( 120 , daily close ) * 1.05 and daily volume > daily sma( volume,5 ) and daily close > 1 day ago close ) )",
"debug_clause": "groupcount( 1 where daily max( 5 , daily close ) > 6 days ago max( 120 , daily close ) * 1.05),groupcount( 1 where daily volume > daily sma( volume,5 )),groupcount( 1 where daily close > 1 day ago close)",
"column_clause": " Daily Close as 'scan-column-default-close', Daily \"close - 1 candle ago close / 1 candle ago close * 100\" as 'scan-column-default-percent-change', filternumber( daily \"close - 1 candle ago close / 1 candle ago close * 100\" > 0,1) as 'default-percent-change-conditional-filters-color', Daily Volume as 'scan-column-default-volume'",
},
"52wHighBreakouts": {
"scan_clause":"( {cash} ( daily close > 1 day ago max( 240 , daily high ) ) )","debug_clause":"groupcount( 1 where daily close > 1 day ago max( 240 , daily high ))","column_clause":" Daily Close as 'scan-column-default-close', Daily \"close - 1 candle ago close / 1 candle ago close * 100\" as 'scan-column-default-percent-change', filternumber( daily close > 1 day ago close,1) as 'default-percent-change-conditional-filters-color', Daily Volume as 'scan-column-default-volume'"
},
"Dr J VIP daily Breakout scanner": {
"scan_clause":"( {cash} ( ( {cash} ( daily volume > 10000 and monthly close > 100 and( {cash} ( daily close >= 1 day ago max( 10 , daily high ) * 1.02 or daily close >= 1 day ago max( 20 , daily high ) * 1.02 or daily close >= 1 day ago max( 30 , daily high ) * 1.02 or daily close >= 1 day ago max( 40 , daily high ) * 1.02 or daily close >= 1 day ago max( 50 , daily high ) * 1.02 or daily close >= 1 day ago max( 60 , daily high ) * 1.02 or daily close >= 1 day ago max( 70 , daily high ) * 1.02 or daily close >= 1 day ago max( 80 , daily high ) * 1.02 or daily close >= 1 day ago max( 90 , daily high ) * 1.02 or daily close >= 1 day ago max( 100 , daily high ) * 1.02 or daily close >= 1 day ago max( 110 , daily high ) * 1.02 or daily close >= 1 day ago max( 120 , daily high ) * 1.02 or daily close >= 1 day ago max( 130 , daily high ) * 1.02 or daily close >= 1 day ago max( 140 , daily high ) * 1.02 or daily close >= 1 day ago max( 150 , daily high ) * 1.02 or daily close >= 1 day ago max( 160 , daily high ) * 1.02 or daily close >= 1 day ago max( 170 , daily high ) * 1.02 or daily close >= 1 day ago max( 180 , daily high ) * 1.02 or daily close >= 1 day ago max( 190 , daily high ) * 1.02 or daily close >= 1 day ago max( 200 , daily high ) * 1.02 ) ) and yearly debt equity ratio < 1 and quarterly foreign institutional investors percentage > 0.5 and market cap > 500 and quarterly mutual funds or uti percentage > 0.5 ) ) ) )","debug_clause":"groupcount( 1 where daily volume > 10000),groupcount( 1 where monthly close > 100),groupcount( 1 where daily close >= 1 day ago max( 10 , daily high ) * 1.02),groupcount( 1 where daily close >= 1 day ago max( 20 , daily high ) * 1.02),groupcount( 1 where daily close >= 1 day ago max( 30 , daily high ) * 1.02),groupcount( 1 where daily close >= 1 day ago max( 40 , daily high ) * 1.02),groupcount( 1 where daily close >= 1 day ago max( 50 , daily high ) * 1.02),groupcount( 1 where daily close >= 1 day ago max( 60 , daily high ) * 1.02),groupcount( 1 where daily close >= 1 day ago max( 70 , daily high ) * 1.02),groupcount( 1 where daily close >= 1 day ago max( 80 , daily high ) * 1.02),groupcount( 1 where daily close >= 1 day ago max( 90 , daily high ) * 1.02),groupcount( 1 where daily close >= 1 day ago max( 100 , daily high ) * 1.02),groupcount( 1 where daily close >= 1 day ago max( 110 , daily high ) * 1.02),groupcount( 1 where daily close >= 1 day ago max( 120 , daily high ) * 1.02),groupcount( 1 where daily close >= 1 day ago max( 130 , daily high ) * 1.02),groupcount( 1 where daily close >= 1 day ago max( 140 , daily high ) * 1.02),groupcount( 1 where daily close >= 1 day ago max( 150 , daily high ) * 1.02),groupcount( 1 where daily close >= 1 day ago max( 160 , daily high ) * 1.02),groupcount( 1 where daily close >= 1 day ago max( 170 , daily high ) * 1.02),groupcount( 1 where daily close >= 1 day ago max( 180 , daily high ) * 1.02),groupcount( 1 where daily close >= 1 day ago max( 190 , daily high ) * 1.02),groupcount( 1 where daily close >= 1 day ago max( 200 , daily high ) * 1.02),groupcount( 1 where yearly debt equity ratio < 1),groupcount( 1 where quarterly foreign institutional investors percentage > 0.5),groupcount( 1 where market cap > 500),groupcount( 1 where quarterly mutual funds or uti percentage > 0.5)","column_clause":" Daily Close as 'scan-column-default-close', Daily \"close - 1 candle ago close / 1 candle ago close * 100\" as 'scan-column-default-percent-change', filternumber( daily close > 1 day ago close,1) as 'default-percent-change-conditional-filters-color', Daily Volume as 'scan-column-default-volume'"
},
"Volume Shockers":{
"scan_clause":"( {cash} ( daily volume > daily sma( volume,20 ) * 5 ) )","debug_clause":"groupcount( 1 where daily volume > daily sma( volume,20 ) * 5)","column_clause":" Daily Close as 'scan-column-default-close', Daily \"close - 1 candle ago close / 1 candle ago close * 100\" as 'scan-column-default-percent-change', filternumber( daily close > 1 day ago close,1) as 'default-percent-change-conditional-filters-color', Daily Volume as 'scan-column-default-volume'"
},
"15min Breakout":{"scan_clause":"( {cash} ( ( {cash} ( [0] 15 minute close > [0] 15 minute max( 6 , [-1] 15 minute high ) or [0] 15 minute close < [0] 15 minute min( 6 , [-1] 15 minute low ) ) ) and( {cash} ( [0] 15 minute close > [0] 15 minute supertrend( 9,2 ) or [0] 15 minute close > [0] 15 minute supertrend( 9,2 ) and [ -1 ] 15 minute close <= [ -1 ] 15 minute supertrend( 9,2 ) ) ) and( {cash} ( [0] 15 minute macd line( 26,12,9 ) > [0] 15 minute macd signal( 26,12,9 ) and daily volume > 300000 and daily close > 500 ) ) ) )","debug_clause":"groupcount( 1 where [0] 15 minute close > [0] 15 minute max( 6 , [-1] 15 minute high )),groupcount( 1 where [0] 15 minute close < [0] 15 minute min( 6 , [-1] 15 minute low )),groupcount( 1 where [0] 15 minute close > [0] 15 minute supertrend( 9,2 )),groupcount( 1 where [0] 15 minute close > [0] 15 minute supertrend( 9,2 ) and [ -1 ] 15 minute close <= [ -1 ] 15 minute supertrend( 9,2 )),groupcount( 1 where [0] 15 minute macd line( 26,12,9 ) > [0] 15 minute macd signal( 26,12,9 )),groupcount( 1 where daily volume > 300000),groupcount( 1 where daily close > 500)","column_clause":" Daily Close as 'scan-column-default-close', Daily \"close - 1 candle ago close / 1 candle ago close * 100\" as 'scan-column-default-percent-change', filternumber( daily close > 1 day ago close,1) as 'default-percent-change-conditional-filters-color', Daily Volume as 'scan-column-default-volume'"
},
"Potential Breakouts":{"scan_clause":"( {cash} ( daily close * 1.05 > daily max( 200 , daily high ) and daily max( 30 , daily high ) <= 30 days ago max( 8 , daily high ) and daily volume > daily sma( daily volume , 50 ) and daily close > 90 ) )","debug_clause":"groupcount( 1 where daily close * 1.05 > daily max( 200 , daily high )),groupcount( 1 where daily max( 30 , daily high ) <= 30 days ago max( 8 , daily high )),groupcount( 1 where daily volume > daily sma( daily volume , 50 )),groupcount( 1 where daily close > 90)","column_clause":" Daily Close as 'scan-column-default-close', Daily \"close - 1 candle ago close / 1 candle ago close * 100\" as 'scan-column-default-percent-change', filternumber( daily close > 1 day ago close,1) as 'default-percent-change-conditional-filters-color', Daily Volume as 'scan-column-default-volume'"
}

}

aggregated_rows = {}

for tag, payload in PAYLOADS.items():
response = requests.post(URL, headers=HEADERS, cookies=COOKIES, json=payload, timeout=30)
print(f"\nTag: {tag} | Status code: {response.status_code}")
Comment on lines +72 to +74

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Locate file:"
fd -a 'screener-integration.py' . || true

file="$(fd 'screener-integration.py' . | head -n1 || true)"
if [ -n "${file:-}" ]; then
  echo "File: $file"
  wc -l "$file"
  echo "--- outline ---"
  ast-grep outline "$file" || true
  echo "--- relevant lines 1-140 ---"
  sed -n '1,140p' "$file" | nl -ba
fi

echo "Search for exception handling around requests.post:"
rg -n "requests\.post|RequestException|except .*Exception|PAYLOADS|for tag" . || true

echo "Git diff stat/name:"
git diff --stat || true
git diff -- "$file" | sed -n '1,220p' || true

Repository: iam-veeramalla/python-for-devops

Length of output: 1574


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="$(fd 'screener-integration.py' . | head -n1 || true)"
if [ -n "${file:-}" ]; then
  python3 - <<'PY' "$file"
import ast, sys
path=sys.argv[1]
with open(path, 'rb') as f:
    tree=ast.parse(f.read(), filename=path, type_comments=True)
print("top-level statements:", len(tree.body))
for node in ast.walk(tree):
    if isinstance(node, ast.For) and isinstance(node.iter, ast.Attribute) and node.iter.attr == "items":
        line=node.lineno
        starts=[start.lineno for start in [node.body[0], node.orelse[0]] if hasattr(start,'lineno')]
        print(f"For at line {line} body starts at line {node.body[0].lineno}, orelse starts at line {node.orelse[0].lineno if node.orelse else None}")
        # determine indentation for first statement in orelse if any
        stmts=[]
        for i,body in enumerate(["for"]):
            pass
        for child in node.body+node.orelse:
            if isinstance(child, ast.Call) and isinstance(child.func, ast.Attribute):
                print(f"child call {ast.get_source_segment(open(path), child)!r} at line {child.lineno}")
            if isinstance(child, ast.Try):
                print(f"TRY at line {child.lineno}")
PY
fi

Repository: iam-veeramalla/python-for-devops

Length of output: 195


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="./Day-11/screener-integration.py"
echo "--- file size and imports/header ---"
wc -l "$file"
head -n 90 "$file" | awk '{printf "%4d\t%s\n", NR, $0}'

echo "--- search exception/request handling ---"
grep -nE "requests\.post|RequestException|except\s+.*Exception|try:|continue|break|for\s+tag\s+in\s+PAYLOADS" "$file" || true

echo "--- static indentation/source around loop ---"
python3 - <<'PY'
from pathlib import Path
p=Path("Day-11/screener-integration.py")
source=p.read_text().splitlines()
for i,line in enumerate(source[:95],1):
    if "for tag" in line or "requests.post" in line or i in range(70,90):
        print(f"{i:4}: [{line[:80]}]")
PY

Repository: iam-veeramalla/python-for-devops

Length of output: 16246


Handle request failures for each payload.

The per-payload requests.post() call is before the parsing try block. If the request raises requests.RequestException, the remaining payloads do not run and no partial ranked output is printed. Wrap only the request in requests.RequestException, report the failed tag, and continue with the remaining payloads.

Proposed fix
 for tag, payload in PAYLOADS.items():
-    response = requests.post(URL, headers=HEADERS, cookies=COOKIES, json=payload, timeout=30)
+    try:
+        response = requests.post(URL, headers=HEADERS, cookies=COOKIES, json=payload, timeout=30)
+    except requests.RequestException as exc:
+        print(f"Unable to request {tag}: {exc}")
+        continue
     print(f"\nTag: {tag} | Status code: {response.status_code}")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for tag, payload in PAYLOADS.items():
response = requests.post(URL, headers=HEADERS, cookies=COOKIES, json=payload, timeout=30)
print(f"\nTag: {tag} | Status code: {response.status_code}")
for tag, payload in PAYLOADS.items():
try:
response = requests.post(URL, headers=HEADERS, cookies=COOKIES, json=payload, timeout=30)
except requests.RequestException as exc:
print(f"Unable to request {tag}: {exc}")
continue
print(f"\nTag: {tag} | Status code: {response.status_code}")
🧰 Tools
🪛 ast-grep (0.45.0)

[warning] 72-72: Request-controlled URL passed to requests; validate against an allowlist to prevent SSRF.
Context: requests.post(URL, headers=HEADERS, cookies=COOKIES, json=payload, timeout=30)
Note: [CWE-918] Server-Side Request Forgery (SSRF).

(ssrf-requests)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Day-11/screener-integration.py` around lines 72 - 74, Handle failures in the
per-payload requests.post call within the loop over PAYLOADS by catching
requests.RequestException around only that request, reporting the associated
tag, and continuing to the next payload so later requests and partial ranked
output still run.


try:
content_encoding = response.headers.get("content-encoding", "").lower()
decoded_body = response.text or ""

if not decoded_body and brotli is not None and "br" in content_encoding:
decoded_body = brotli.decompress(response.content).decode("utf-8", errors="replace")
elif not decoded_body:
decoded_body = response.content.decode("utf-8", errors="replace")

data = json.loads(decoded_body)
rows = data.get("data", [])
if not rows:
print(f"No matching records found for {tag}.")
continue

for item in rows:
code = item.get("nsecode", "")
name = item.get("name", "")
key = (code, name)

if key not in aggregated_rows:
aggregated_rows[key] = {
"code": code,
"name": name,
"close": item.get("scan-column-default-close", ""),
"change": item.get("scan-column-default-percent-change", ""),
"volume": item.get("scan-column-default-volume", ""),
"tags": [tag],
}
elif tag not in aggregated_rows[key]["tags"]:
aggregated_rows[key]["tags"].append(tag)
except (ValueError, json.JSONDecodeError, AttributeError) as exc:
print(f"Unable to parse response for {tag}: {exc}")
print(decoded_body[:4000] if "decoded_body" in locals() else response.text[:4000])

print("\n SCRIPT: MULTI-PAYLOAD SCREENER RESULTS")
print("\nFormatted table:")
if not aggregated_rows:
print("No matching records found.")
else:
headers = ["CODE", "NAME", "TAGS", "CLOSE", "CHANGE %", "VOLUME"]
ranked_rows = sorted(
aggregated_rows.values(),
key=lambda item: (-len(item["tags"]), item["code"], item["name"]),
)
max_tag_count = max((len(row["tags"]) for row in ranked_rows), default=0)
shortlisted_rows = [row for row in ranked_rows if len(row["tags"]) == max_tag_count]
selected_rows = shortlisted_rows[:5]
Comment on lines +121 to +123

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Select the first five ranked rows.

Lines 121-123 discard every row below the highest tag count. If one stock has the most tags, the table prints only that stock even when other ranked matches exist.

Select the first five rows from ranked_rows.

Proposed fix
-    max_tag_count = max((len(row["tags"]) for row in ranked_rows), default=0)
-    shortlisted_rows = [row for row in ranked_rows if len(row["tags"]) == max_tag_count]
-    selected_rows = shortlisted_rows[:5]
+    selected_rows = ranked_rows[:5]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
max_tag_count = max((len(row["tags"]) for row in ranked_rows), default=0)
shortlisted_rows = [row for row in ranked_rows if len(row["tags"]) == max_tag_count]
selected_rows = shortlisted_rows[:5]
selected_rows = ranked_rows[:5]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Day-11/screener-integration.py` around lines 121 - 123, Update the
row-selection logic after ranked_rows to take the first five entries directly
from ranked_rows, removing the max_tag_count and shortlisted_rows filtering so
all ranked matches retain their ranking.


rows_display = [
[
row["code"],
row["name"],
", ".join(row["tags"]),
row["close"],
row["change"],
row["volume"],
]
for row in selected_rows
]

col_widths = [max(len(str(row[i])) for row in [headers] + rows_display) for i in range(len(headers))]
print(" | ".join(header.ljust(col_widths[i]) for i, header in enumerate(headers)))
print("-+-".join("-" * width for width in col_widths))
for row in rows_display:
print(" | ".join(str(value).ljust(col_widths[i]) for i, value in enumerate(row)))
17 changes: 17 additions & 0 deletions Day-11/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
student_properties= {
"name":"abhi",
"class":"12th"
}

students_info=[
{
"name":"nishka",
"class":"12th"
},
{
"name":"kiyana",
"class":"12th"
}]

print (student_properties ["name"])
print (students_info[0]["name"])
13 changes: 13 additions & 0 deletions Day-12/fileoperations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
def updatefileProperties (filePath,key,value):
with open(filePath,"r") as serverConf:
lines = serverConf.readlines();

with open(filePath,"w") as serverConf:
for line in lines:
if key in line:
serverConf.write(key+"="+value+"\n")
Comment on lines +7 to +8

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Match the configuration key exactly.

key in line also matches comments and longer keys. For example, MAX_CONNECTIONS matches # MAX_CONNECTIONS and MAX_CONNECTIONS_LIMIT=.... Line 8 can then overwrite unrelated configuration. Compare the parsed key before writing.

Proposed fix
-            if key in line:
+            key_part, separator, _ = line.partition("=")
+            if separator and key_part.strip() == key:
                 serverConf.write(key+"="+value+"\n")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if key in line:
serverConf.write(key+"="+value+"\n")
key_part, separator, _ = line.partition("=")
if separator and key_part.strip() == key:
serverConf.write(key+"="+value+"\n")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Day-12/fileoperations.py` around lines 7 - 8, Update the configuration
replacement logic around the key-matching condition in the file operation flow
to parse each line’s configuration key and compare it exactly with key. Ignore
comments and longer key names such as MAX_CONNECTIONS_LIMIT, and only write the
replacement when the parsed key matches; preserve unrelated lines unchanged.

else:
serverConf.write(line)
Comment on lines +5 to +10

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== repo files matching fileoperations.py =="
fd -a 'fileoperations\.py$' . || true

echo "== target file contents with line numbers =="
if [ -f Day-12/fileoperations.py ]; then
  cat -n Day-12/fileoperations.py
fi

echo "== references to update/create/write config functions =="
rg -n "def |open\\(|write\\(|update|create|conf" Day-12/fileoperations.py . 2>/dev/null | head -200 || true

echo "== relevant imports/usages from nearby tracked files =="
git ls-files Day-12 | xargs -r -n1 sh -c 'echo "--- $0"; sed -n "1,160p" "$0"' 2>/dev/null | head -300

Repository: iam-veeramalla/python-for-devops

Length of output: 14944


Write the configuration atomically.

open(filePath, "w") truncates server.conf before the rewrite loop starts. If the process is interrupted or a write fails, the function leaves the target empty or partially written. Write the updated content to a temporary file in the same directory, then replace server.conf with os.replace; preserve the original file permissions if they matter.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Day-12/fileoperations.py` around lines 5 - 10, Update the file-writing logic
around the open call to build the complete updated configuration in a temporary
file located in the same directory as filePath, then atomically replace the
target using os.replace only after the write succeeds. Ensure temporary-file
cleanup on failure and preserve the existing file permissions when required.



updatefileProperties("server.conf","MAX_CONNECTIONS","200")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Files:"
git ls-files | sed -n '1,120p'

echo
echo "Day-12 candidates:"
fd -a . Day-12 2>/dev/null | sed 's#^\./##' | sed -n '1,120p'

echo
if [ -f Day-12/fileoperations.py ]; then
  echo "Day-12/fileoperations.py outline:"
  ast-grep outline Day-12/fileoperations.py || true
  echo
  echo "Day-12/fileoperations.py contents:"
  cat -n Day-12/fileoperations.py
fi

echo
if [ -f Day-12/fileoperations.py ]; then
  echo "Read/write usages in Day-12/fileoperations.py:"
  python3 - <<'PY'
from pathlib import Path
p=Path('Day-12/fileoperations.py')
text=p.read_text()
for i,line in enumerate(text.splitlines(),1):
    if 'updatefileProperties' in line or 'open(' in line or 'readlines' in line or 'readline' in line or 'write' in line or 'read(' in line:
        print(f'{i}: {line}')
PY
fi

echo
echo "server.conf file:"
if [ -f Day-12/server.conf ]; then
 cat -n Day-12/server.conf
else
 echo "Day-12/server.conf not found"
fi

echo
echo "Python path resolution probe:"
python3 - <<'PY'
from pathlib import Path
for d in ["repo_root", "Day-12", "/tmp"]:
    print(d, "->", Path(d).resolve(), "Day-12/server.conf exists from cwd?", (Path(d).resolve()/"Day-12"/"server.conf").exists())
    print(d, "->", Path("server.conf").resolve(), "server.conf exists from cwd?", Path("server.conf").resolve().exists())
PY

Repository: iam-veeramalla/python-for-devops

Length of output: 4741


Resolve server.conf relative to __file__.

updatefileProperties("server.conf", ...) uses the process working directory, while the repository file is Day-12/server.conf. Running python Day-12/fileoperations.py from the repository root makes open() look for server.conf in the repository root instead of Day-12, so the call fails before the property update.

Proposed fix
+from pathlib import Path
+
-updatefileProperties("server.conf","MAX_CONNECTIONS","200")
+updatefileProperties(
+    Path(__file__).resolve().with_name("server.conf"),
+    "MAX_CONNECTIONS",
+    "200",
+)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
updatefileProperties("server.conf","MAX_CONNECTIONS","200")
from pathlib import Path
updatefileProperties(
Path(__file__).resolve().with_name("server.conf"),
"MAX_CONNECTIONS",
"200",
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Day-12/fileoperations.py` at line 13, Update the call to updatefileProperties
in fileoperations.py to construct the server.conf path relative to __file__
rather than the process working directory, preserving the existing
MAX_CONNECTIONS and "200" arguments.