nsepython 2.100__py3-none-any.whl → 2.101__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
nsepython/__init__.py CHANGED
@@ -1,3 +1,10 @@
1
1
  from .rahu import *
2
2
 
3
- __version__ = "0.1"
3
+ try:
4
+ from importlib.metadata import version as _pkg_version
5
+ __version__ = _pkg_version("nsepython")
6
+ except Exception:
7
+ # Not pip-installed (e.g. running straight from a git checkout with no
8
+ # installed dist) -- fall back to the last known release rather than
9
+ # raising PackageNotFoundError and breaking the import for everyone.
10
+ __version__ = "2.101"
nsepython/rahu.py CHANGED
@@ -597,24 +597,56 @@ def nse_quote(symbol,section=""):
597
597
  f"run/populated yet."
598
598
  )
599
599
 
600
- # Round 3: every other section value (e.g. the old 'metadata'/
601
- # 'industryInfo'/'info'/'priceInfo'/'securityInfo') used to fall through
600
+ # v2.101 fix: the Round-3 rationale above ("NSE's old API never accepted
601
+ # these section values") is true but beside the point -- this isn't
602
+ # about replicating the old query parameter, it's about reconstructing
603
+ # the equivalent DATA from the new no-section payload, exactly as the
604
+ # 'trade_info' branch above already does. nsepythonserver already does
605
+ # this for the remaining old quote-equity top-level keys (info/metadata/
606
+ # priceInfo/securityInfo/industryInfo); port that here too. Every one of
607
+ # these is a pure re-slice of the same GetQuoteApi?functionName=
608
+ # getSymbolData payload nse_quote(symbol, section="") already fetches --
609
+ # no new network call. 'preOpenMarket' is deliberately NOT included in
610
+ # this set: the branch above already serves it from a genuinely live,
611
+ # higher-fidelity endpoint (/api/market-data-pre-open) rather than this
612
+ # reshape's coarser approximation.
613
+ _equity_detail_sections = {
614
+ "info", "metadata", "priceInfo", "securityInfo", "industryInfo",
615
+ }
616
+ if section in _equity_detail_sections:
617
+ base_payload = nse_quote(symbol, section="")
618
+ if 'equityResponse' not in base_payload or not base_payload['equityResponse']:
619
+ # Index/derivative symbols have no cash-market EquityDetails
620
+ # shape to slice a section out of.
621
+ raise NSEEndpointError(
622
+ f"nse_quote({symbol!r}, section={section!r}): no equity "
623
+ f"'section' data exists for index/derivative symbols -- use "
624
+ f"nse_quote_derivatives(symbol) or nse_quote(symbol) (no "
625
+ f"section) instead."
626
+ )
627
+ if section == "industryInfo":
628
+ sec_info = base_payload['equityResponse'][0].get('secInfo', {}) or {}
629
+ return {
630
+ "macro": sec_info.get("macro"),
631
+ "sector": sec_info.get("sector"),
632
+ "industry": sec_info.get("industryInfo"),
633
+ "basicIndustry": sec_info.get("basicIndustry"),
634
+ }
635
+ reshaped = _reshape_equity_quote(base_payload)
636
+ return reshaped.get(section, {})
637
+
638
+ # Round 3: every other section value used to fall through
602
639
  # here and hit the dead /api/quote-equity&section=X route -- a ~5s
603
640
  # double-retry ending in a misleading HTTP 403, for a route that was
604
- # never real in the first place. Checked against unofficed.com's own
605
- # docs, the hi-imcodeman/stock-nse-india reference implementation, and
606
- # this project's full GitHub issue history: NSE's API never accepted
607
- # any section value beyond 'trade_info' -- those other names are just
608
- # top-level keys inside the un-sectioned response, already returned in
609
- # full by nse_quote(symbol) (section=""). Raise immediately and clearly
610
- # instead of a slow, confusing network round-trip to a route that was
611
- # never real.
641
+ # never real in the first place. Raise immediately and clearly instead
642
+ # of a slow, confusing network round-trip to a route that was never
643
+ # real.
612
644
  raise ValueError(
613
- f"nse_quote: unsupported section={section!r}; only '' (full quote), "
614
- f"'trade_info', and 'preOpenMarket' are supported -- NSE's old "
615
- f"quote-equity API never had other section values. section='' "
616
- f"already returns the full detail (metaData/secInfo/priceInfo/"
617
- f"orderBook/tradeInfo all together)."
645
+ f"nse_quote: unsupported section={section!r}; supported: '' (full "
646
+ f"quote), 'trade_info', 'preOpenMarket', and "
647
+ f"{sorted(_equity_detail_sections)}. section='' already returns the "
648
+ f"full detail (metaData/secInfo/priceInfo/orderBook/tradeInfo all "
649
+ f"together)."
618
650
  )
619
651
  def nse_expirydetails(payload, i=0, symbol=None):
620
652
  expiry_dates = []
@@ -1091,6 +1123,63 @@ def nse_optionchain_ltp(payload,strikePrice,optionType,inp=0,intent=""):
1091
1123
  "directly."
1092
1124
  )
1093
1125
 
1126
+ def _reshape_equity_quote(raw):
1127
+ """/api/quote-equity (nse_eq's old data source) is dead (confirmed live
1128
+ 403 Access Denied, Apache/WAF-style, not an Akamai JS challenge -- there
1129
+ is no cookie that fixes it). The live quote page itself now calls
1130
+ GetQuoteApi?functionName=getSymbolData instead, which carries nearly all
1131
+ the same information, just regrouped. We reshape it back into the old
1132
+ quote-equity top-level key names (info/metadata/priceInfo/securityInfo/
1133
+ tradeInfo) as closely as the new payload allows, so code written against
1134
+ the old shape (payload['priceInfo']['lastPrice'],
1135
+ payload['metadata']['pdSymbolPe'], etc.) keeps working. The full
1136
+ unmodified NextApi response is also kept under '_raw' for anyone who
1137
+ wants the new field names directly. Ported from nsepythonserver's
1138
+ identical helper (same live-verified field mapping)."""
1139
+ if not raw or 'equityResponse' not in raw or not raw['equityResponse']:
1140
+ return raw
1141
+ row = raw['equityResponse'][0]
1142
+ meta = row.get('metaData', {}) or {}
1143
+ sec = row.get('secInfo', {}) or {}
1144
+ trade = row.get('tradeInfo', {}) or {}
1145
+ price = row.get('priceInfo', {}) or {}
1146
+ order = row.get('orderBook', {}) or {}
1147
+
1148
+ reshaped = {
1149
+ 'info': {
1150
+ 'symbol': meta.get('symbol'),
1151
+ 'companyName': meta.get('companyName'),
1152
+ 'industry': sec.get('basicIndustry'),
1153
+ 'isin': meta.get('isinCode'),
1154
+ 'series': meta.get('series'),
1155
+ },
1156
+ 'metadata': {
1157
+ **meta,
1158
+ 'pdSectorPe': sec.get('pdSectorPe'),
1159
+ 'pdSymbolPe': sec.get('pdSymbolPe'),
1160
+ 'pdSectorInd': sec.get('pdSectorInd'),
1161
+ },
1162
+ 'priceInfo': {
1163
+ 'lastPrice': order.get('lastPrice', meta.get('closePrice')),
1164
+ 'change': meta.get('change'),
1165
+ 'pChange': meta.get('pChange'),
1166
+ 'previousClose': meta.get('previousClose'),
1167
+ 'open': meta.get('open'),
1168
+ 'close': meta.get('closePrice'),
1169
+ 'vwap': meta.get('averagePrice'),
1170
+ 'intraDayHighLow': {'min': meta.get('dayLow'), 'max': meta.get('dayHigh'),
1171
+ 'value': order.get('lastPrice', meta.get('closePrice'))},
1172
+ 'weekHighLow': {'min': price.get('yearLow'), 'max': price.get('yearHigh'),
1173
+ 'minDate': price.get('yearLowDt'), 'maxDate': price.get('yearHightDt')},
1174
+ },
1175
+ 'securityInfo': sec,
1176
+ 'tradeInfo': trade,
1177
+ 'preOpenMarket': {},
1178
+ '_raw': raw,
1179
+ }
1180
+ return reshaped
1181
+
1182
+
1094
1183
  def nse_eq(symbol):
1095
1184
  symbol = nsesymbolpurify(symbol)
1096
1185
  try:
@@ -1108,13 +1197,21 @@ def nse_eq(symbol):
1108
1197
  # same underlying data (just in a different JSON shape - data lives
1109
1198
  # under payload['equityResponse'][0] instead of payload['priceInfo']/
1110
1199
  # payload['info']) so we fall back to that instead of returning {}.
1200
+ #
1201
+ # v2.101 fix: the fallback used to return that raw NextApi payload
1202
+ # unreshaped, so old bracket-access code (payload['priceInfo']
1203
+ # ['lastPrice'], payload['metadata']['pdSectorPe'], etc. -- the exact
1204
+ # examples long documented on unofficed.com's Basic Functions page)
1205
+ # raised KeyError instead of working, a real regression introduced
1206
+ # by this same Akamai fallback. nsepythonserver already carried this
1207
+ # reshape; port it here too via _reshape_equity_quote() above.
1111
1208
  logging.warning(
1112
1209
  "nse_eq(%s): /api/quote-equity is retired; returning data from "
1113
1210
  "the newer NextApi quote endpoint instead (see nse_quote() - the "
1114
1211
  "JSON shape differs from the old quote-equity response).",
1115
1212
  symbol,
1116
1213
  )
1117
- payload = nse_quote(symbol)
1214
+ payload = _reshape_equity_quote(nse_quote(symbol))
1118
1215
  return payload
1119
1216
 
1120
1217
 
@@ -1140,6 +1237,16 @@ def nse_fno(symbol):
1140
1237
  symbol,
1141
1238
  )
1142
1239
  payload = nse_quote_derivatives(symbol)
1240
+ # v2.101 fix: the old quote-derivative response carried 'underlyingValue'
1241
+ # at the top level; the new flat getSymbolDerivativesData shape instead
1242
+ # repeats it inside EVERY entry of payload['data'] (same value on each),
1243
+ # so payload['underlyingValue'] (a documented, long-standing access
1244
+ # pattern) now raises KeyError. Promote it back to the top level from
1245
+ # the first entry without touching/removing the existing 'data' key.
1246
+ if 'underlyingValue' not in payload and payload.get('data'):
1247
+ first = payload['data'][0]
1248
+ if isinstance(first, dict) and 'underlyingValue' in first:
1249
+ payload['underlyingValue'] = first['underlyingValue']
1143
1250
  return payload
1144
1251
 
1145
1252
  def quote_equity(symbol):
@@ -2134,7 +2241,7 @@ _NSE_MCP_SERVERS = {
2134
2241
  "cmmkt": "https://mcp.nseindia.in/cmmkt/mcp",
2135
2242
  }
2136
2243
 
2137
- _NSE_MCP_CLIENT_VERSION = "2.98"
2244
+ _NSE_MCP_CLIENT_VERSION = "2.101"
2138
2245
 
2139
2246
  # Lightweight session-id cache, keyed by server URL, so repeated calls to the
2140
2247
  # same MCP server don't re-run the "initialize" handshake every time.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nsepython
3
- Version: 2.100
3
+ Version: 2.101
4
4
  Summary: Python library for NSE India APIs
5
5
  Home-page: https://github.com/aeron7/nsepython
6
6
  Author: Aeron7
@@ -0,0 +1,7 @@
1
+ nsepython/__init__.py,sha256=-f60TXCASPEAVtjuWEWaRIiHM5RnB2MkECBbUgHxJKU,394
2
+ nsepython/rahu.py,sha256=UKqMUe8PyHCVwM1vjnfzJr46_lXPCnL2Kqgmt9-J9FM,131441
3
+ nsepython-2.101.dist-info/licenses/LICENSE,sha256=VXapH-nuSz68DG5ScURElxHkl1lKk4MOK9cgZCSRDXs,34502
4
+ nsepython-2.101.dist-info/METADATA,sha256=REcoHhc7sqwr8IOJ3QWOxcUKP1cXbopNvxqzHUqsIdg,7534
5
+ nsepython-2.101.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
6
+ nsepython-2.101.dist-info/top_level.txt,sha256=-hTS08c-pS4rPpiuzLkamRsgHTq7t6BG0M5wnU-iPy4,10
7
+ nsepython-2.101.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- nsepython/__init__.py,sha256=_1YN_O25fj7GRUrOREinuxKiXiF0l4cs-Grzjec8mZg,41
2
- nsepython/rahu.py,sha256=fn_fApl5uw3sVtiSdzJHzfdC7tubdu9gI8-q1NL_KcQ,125978
3
- nsepython-2.100.dist-info/licenses/LICENSE,sha256=VXapH-nuSz68DG5ScURElxHkl1lKk4MOK9cgZCSRDXs,34502
4
- nsepython-2.100.dist-info/METADATA,sha256=qL-CuY5UNJsc6fUJgx7DC-ro314DP84secunyMNEi6E,7534
5
- nsepython-2.100.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
6
- nsepython-2.100.dist-info/top_level.txt,sha256=-hTS08c-pS4rPpiuzLkamRsgHTq7t6BG0M5wnU-iPy4,10
7
- nsepython-2.100.dist-info/RECORD,,