diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml new file mode 100644 index 0000000..dbaedd4 --- /dev/null +++ b/.github/workflows/python-publish.yml @@ -0,0 +1,39 @@ +# This workflow will upload a Python Package using Twine when a release is created +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Upload Python Package + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + deploy: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install build + - name: Build package + run: python -m build + - name: Publish package + uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} \ No newline at end of file diff --git a/fscraper/exceptions.py b/fscraper/exceptions.py new file mode 100644 index 0000000..a162a9d --- /dev/null +++ b/fscraper/exceptions.py @@ -0,0 +1,6 @@ +class CodeNotFoundException(Exception): + """Raised when the code was not listed""" + + def __init__(self, code, message): + self.code = code + self.message = message diff --git a/fscraper/yfscraper.py b/fscraper/yfscraper.py index 8cab33f..434a66c 100644 --- a/fscraper/yfscraper.py +++ b/fscraper/yfscraper.py @@ -6,6 +6,7 @@ from bs4 import BeautifulSoup from lxml import etree from .xpath_table import yahoo_xpath +from .exceptions import CodeNotFoundException class YahooFinanceScraper(object): @@ -104,6 +105,10 @@ def __construct_price_dataframe(self, params): headers=scraper_headers).text price_json = json.loads(html) + if 'error' in price_json['chart']: + raise CodeNotFoundException(self.code, json.loads(html)[ + 'chart']['error']['description']) + df['date'] = price_json['chart']['result'][0]['timestamp'] df['open'] = price_json['chart']['result'][0]['indicators']['quote'][0]['open'] df['high'] = price_json['chart']['result'][0]['indicators']['quote'][0]['high'] @@ -119,7 +124,6 @@ def __construct_price_dataframe(self, params): 'dividends'] = item['amount'] except KeyError as e: df['dividends'] = np.nan - pass df['date'] = df['date'].apply(lambda d: datetime.fromtimestamp( int(d)).strftime("%Y-%m-%d %H:%M:%S")) diff --git a/setup.py b/setup.py index f6e3350..5c39ede 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setup( name='fscraper', - version='1.0.4', + version='1.0.5', description='Financial Data Web Scraper', long_description=long_description, long_description_content_type='text/markdown', diff --git a/tests.py b/tests.py new file mode 100644 index 0000000..c1fb5e6 --- /dev/null +++ b/tests.py @@ -0,0 +1,21 @@ +import unittest +import fscraper as fs +from fscraper.exceptions import CodeNotFoundException + + +class TestMethods(unittest.TestCase): + + def test_nonexist_code(self): + """Test delisted code in Yahoo !Finance""" + code = '8369.T' # Delisted code + + yf = fs.YahooFinanceScraper(code=code) + try: + yf.get_stock_price2(start='2023-12-15') + except CodeNotFoundException as e: + self.assertEqual( + e.message, "No data found, symbol may be delisted") + + +if __name__ == '__main__': + unittest.main()