diff --git a/.flake8 b/.flake8
deleted file mode 100644
index da0f1a7..0000000
--- a/.flake8
+++ /dev/null
@@ -1,4 +0,0 @@
-[flake8]
-max-line-length = 88
-extend-ignore = E203
-exclude = __pycache__,build,dist,notes
diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml
index 9d181f1..6cab2c6 100644
--- a/.github/workflows/integration-test.yml
+++ b/.github/workflows/integration-test.yml
@@ -2,37 +2,28 @@
name: trading-ig integration test
on:
- schedule:
- - cron: '25 2 * * 1-4'
+# schedule:
+# - cron: '25 2 * * 1-4'
workflow_dispatch:
jobs:
build:
- if: github.repository == 'ig-python/trading-ig'
+ # if: github.repository == 'ig-python/trading-ig'
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
- - name: Set up Python 3.10
- uses: actions/setup-python@v5
+ - uses: actions/checkout@v6
+
+ - name: Install uv and setup Python
+ uses: astral-sh/setup-uv@v7
with:
+ version: "0.11.6"
python-version: "3.10"
- - name: Install Poetry
- uses: abatilo/actions-poetry@v4
- with:
- poetry-version: "latest"
- - name: Setup a local virtual environment
- run: |
- poetry config virtualenvs.create true --local
- poetry config virtualenvs.in-project true --local
- - uses: actions/cache@v3
- name: Define a cache for the virtual environment based on the dependencies lock file
- with:
- path: ./.venv
- key: venv-${{ hashFiles('poetry.lock') }}
+
- name: Install dependencies
run: |
- poetry install --extras "pandas munch tenacity"
+ uv sync --all-extras --dev
+
- name: Integration test with pytest
env:
IG_SERVICE_USERNAME: ${{ secrets.IG_SERVICE_USERNAME }}
@@ -41,10 +32,11 @@ jobs:
IG_SERVICE_ACC_TYPE: ${{ secrets.IG_SERVICE_ACC_TYPE }}
IG_SERVICE_ACC_NUMBER: ${{ secrets.IG_SERVICE_ACC_NUMBER_1 }}
run: |
- poetry run coverage run -m --source=trading_ig pytest --log-cli-level=DEBUG --log-format="%(asctime)s %(levelname)s %(message)s" --log-date-format="%Y-%m-%d %H:%M:%S"
- poetry run coverage report
+ uv run coverage run -m --source=trading_ig pytest --log-cli-level=DEBUG --log-format="%(asctime)s %(levelname)s %(message)s" --log-date-format="%Y-%m-%d %H:%M:%S"
+ uv run coverage report
+
- name: Coveralls
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
- poetry run coveralls --service=github
+ uv run coveralls --service=github
diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml
index eba0be8..078d817 100644
--- a/.github/workflows/python-publish.yml
+++ b/.github/workflows/python-publish.yml
@@ -10,19 +10,25 @@ jobs:
runs-on: ubuntu-latest
+ environment:
+ name: pypi
+
+ permissions:
+ id-token: write
+ contents: read
+
steps:
- - uses: actions/checkout@v4
- - name: Set up Python
- uses: actions/setup-python@v5
+ - name: Checkout
+ uses: actions/checkout@v6
+
+ - name: Install uv and Python
+ uses: astral-sh/setup-uv@v7
with:
+ version: "0.11.6"
python-version: "3.10"
- - name: Install Poetry
- uses: abatilo/actions-poetry@v3
- with:
- poetry-version: "latest"
- - name: Build and publish
- env:
- PYPI_USERNAME: __token__
- PYPI_PASSWORD: ${{ secrets.PYPI_TOKEN }}
- run: |
- poetry publish -u $PYPI_USERNAME -p $PYPI_PASSWORD --build
+
+ - name: Build
+ run: uv build
+
+ - name: Publish
+ run: uv publish
diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml
index 6ca19bc..48b0d30 100644
--- a/.github/workflows/unit-test.yml
+++ b/.github/workflows/unit-test.yml
@@ -17,31 +17,26 @@ jobs:
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
- - name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v5
+ - name: Install uv and setup Python
+ uses: astral-sh/setup-uv@v7
with:
+ version: "0.11.6"
python-version: ${{ matrix.python-version }}
- - name: Install Poetry
- uses: abatilo/actions-poetry@v3
- with:
- poetry-version: "latest"
-
- name: Install dependencies
run: |
- poetry install --extras "pandas munch tenacity"
+ uv sync --all-extras --dev
- - name: Prettify with black
- uses: psf/black@stable
- with:
- version: "23.3.0"
+ - name: Check code prettiness with ruff
+ run: |
+ uv run ruff format --check
- - name: Lint with flake8
+ - name: Lint with ruff
run: |
- poetry run flake8 trading_ig docs sample tests
+ uv run ruff check trading_ig docs sample tests
- name: Unit tests with pytest
run: |
- poetry run pytest --ignore=tests/test_integration.py
+ uv run pytest --ignore=tests/test_integration.py
diff --git a/README.rst b/README.rst
index a84e655..6fd0c7f 100644
--- a/README.rst
+++ b/README.rst
@@ -62,33 +62,13 @@ For full details, see `pyproject.toml `_.
-
-Adding to an existing Poetry project::
-
- $ poetry add trading-ig
-
-With all the optional dependencies::
-
- $ poetry add trading-ig[pandas,munch,tenacity]
-
-Cloning the project with Poetry::
-
- $ git clone https://github.com/ig-python/trading-ig
- $ cd trading-ig
- $ poetry install
-
-And with all optional dependencies::
-
- $ poetry install --extras "pandas munch tenacity"
-
Installing with pip::
$ pip install trading-ig
-And with all optional dependencies::
+Installing with all optional dependencies::
- $ pip install trading-ig pandas munch tenacity
+ $ pip install "trading-ig[pandas, munch, tenacity]"
What if I need help?
--------------------
diff --git a/docs/source/faq.rst b/docs/source/faq.rst
index 83eb47e..b2486a1 100644
--- a/docs/source/faq.rst
+++ b/docs/source/faq.rst
@@ -77,7 +77,7 @@ exceeded one of the limits.
You can query the limits associated with either a LIVE or DEMO API key after logging on by calling::
-IGService.get_client_apps()
+ IGService.get_client_apps()
This is the rate used when a new IGService object is created with the use_rate_limiter kwarg set as True.
@@ -212,33 +212,33 @@ solutions:
How do I check my PR will pass CI checks?
-----------------------------------------
This project uses some automated continuous integration (CI) processes whenever
-any code is committed, or if someone creates a PR. There are unit tests, code
-formatting with ``black``, and linting with ``flake8``. In addition, an
-integration test gets executed every night. The integration test takes a long
-time due to the :ref:`rate limits`. Before making a PR, please make
-sure the tests pass - PRs will be rejected if they do not. For code formatting::
+any code is committed, or if someone creates a PR. There are unit tests, and code
+formatting and linting with ``ruff``. In addition, an integration test gets
+executed every night. The integration test takes a long time due to the
+:ref:`rate limits`. Before making a PR, please make sure the tests
+pass - PRs will be rejected if they do not. For code formatting::
- $ poetry run black .
+ $ uv run ruff format
and for linting::
- $ poetry run flake8 trading_ig docs sample tests
+ $ uv run ruff check trading_ig docs sample tests
for unit tests::
- $ poetry run pytest --ignore=tests/test_integration.py
+ $ uv run pytest --ignore=tests/test_integration.py
for integration tests::
- $ poetry run pytest tests/test_integration.py
+ $ uv run pytest tests/test_integration.py
for unit and integration tests::
- $ poetry run pytest
+ $ uv run pytest
for all tests, including one *really* long running one that tests v3 sessions::
- $ poetry run pytest --runslow
+ $ uv run pytest --runslow
.. _v2_or_v3_sessions:
@@ -332,10 +332,12 @@ An issue without all this information may be ignored and/or closed without respo
What happened to ``setup.py`` and ``requirements.txt``?
-------------------------------------------------------------
-Early versions of this project used the standard ``setup.py`` config, with a ``requirements.txt`` file describing
-dependencies. `Poetry `_
-support was added with version 0.0.10 (July 2021). The old style config was removed with version 0.0.14
+Early versions of this project used the standard ``setup.py`` config, with a
+``requirements.txt`` file describing dependencies. `Poetry `_
+support was added with version 0.0.10 (July 2021).The old style config was
+removed with version 0.0.14.
+We switched to `uv `_ in April 2026.
.. _why-is-pandas-an-optional-dependency-in-pyproject-toml:
.. _optional-dependencies:
diff --git a/docs/source/quickstart.rst b/docs/source/quickstart.rst
index cb86312..b5f456a 100644
--- a/docs/source/quickstart.rst
+++ b/docs/source/quickstart.rst
@@ -4,34 +4,13 @@ Quickstart
Installation
------------
-This project uses `Poetry `_.
-
-Adding to an existing Poetry project::
-
- $ poetry add trading-ig
-
-With all the optional dependencies::
-
- $ poetry add trading-ig[pandas,munch,tenacity]
-
-Cloning the project with Poetry::
-
- $ git clone https://github.com/ig-python/trading-ig
- $ cd trading-ig
- $ poetry install
-
-And with all optional dependencies::
-
- $ poetry install --extras "pandas munch tenacity"
-
Installing with pip::
$ pip install trading-ig
-And with all optional dependencies::
-
- $ pip install trading-ig pandas munch tenacity
+Installing with all optional dependencies::
+ $ pip install "trading-ig[pandas, munch, tenacity]"
Configuration
-------------
diff --git a/pyproject.toml b/pyproject.toml
index 517ef25..f7b15a5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,15 +1,26 @@
-[tool.poetry]
+[build-system]
+requires = ["uv_build>=0.11.6,<0.12.0"]
+build-backend = "uv_build"
+
+[project]
name = "trading-ig"
version = "0.0.23"
description = "A lightweight Python wrapper for the IG Markets API"
-authors = ["Femto Trader ", "Andy Geach "]
-maintainers = ["Andy Geach "]
-license = "BSD-3-Clause"
+authors = [
+ { name = "Femto Trader", email = "femto.trader@gmail.com" },
+ { name = "Andy Geach", email = "andy@bugorfeature.net" },
+]
+requires-python = ">=3.10,<4"
readme = "README.rst"
-homepage = "https://github.com/ig-python/trading-ig"
-repository = "https://github.com/ig-python/trading-ig"
-documentation = "https://trading-ig.readthedocs.io/"
-keywords = ["trading", "spread betting", "CFDs"]
+license = "BSD-3-Clause"
+maintainers = [
+ { name = "Andy Geach", email = "andy@bugorfeature.net" }
+]
+keywords = [
+ "trading",
+ "spread betting",
+ "CFDs",
+]
classifiers = [
"Development Status :: 3 - Alpha",
"Environment :: Console",
@@ -18,47 +29,44 @@ classifiers = [
"Operating System :: OS Independent",
"Programming Language :: Cython",
"Programming Language :: Python",
- "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
+ "Programming Language :: Python :: 3.13",
+ "Programming Language :: Python :: 3.14",
"Topic :: Scientific/Engineering",
"Topic :: Software Development :: Libraries",
- "License :: OSI Approved :: BSD License",
+]
+dependencies = [
+ "requests>=2.24,<3",
+ "pycryptodome>=3.9,<4",
+ "requests-cache>=0.5,<0.6",
+ "six>=1.15,<2",
+ "lightstreamer-client-lib==1.0.3",
]
-[tool.poetry.dependencies]
-python = "^3.9"
-requests = "^2.24"
-pycryptodome = "^3.9"
-requests-cache = "^0.5"
-six = "^1.15"
-lightstreamer-client-lib = "^1.0.3"
+[project.optional-dependencies]
+pandas = ["pandas>=2,<3"]
+munch = ["munch>=2.5,<3"]
+tenacity = ["tenacity>=8,<9"]
-pandas = {version = "^2", optional = true}
-munch = {version = "^2.5", optional = true}
-tenacity = {version = "^8", optional = true}
+[project.urls]
+Homepage = "https://github.com/ig-python/trading-ig"
+Repository = "https://github.com/ig-python/trading-ig"
+Documentation = "https://trading-ig.readthedocs.io/"
+Issues = "https://github.com/ig-python/trading-ig/issues"
-[tool.poetry.extras]
-pandas = ["pandas"]
-munch = ["munch"]
-tenacity = ["tenacity"]
-sphinx = ["sphinx"]
-docs = [
- "sphinx"
+[dependency-groups]
+dev = [
+ "ruff",
+ "pytest>=8,<9",
+ "responses>=0.25,<0.26",
+ "coveralls>=3,<4",
+ "sphinx",
+ "sphinx-rtd-theme",
]
-[tool.poetry.group.dev.dependencies]
-flake8 = "^7"
-pytest = "^8"
-responses = "^0.25"
-coveralls = "^3"
-sphinx-rtd-theme = {version = "^1.0.0", optional = true}
-black = "23.3.0"
-
-[tool.poetry.urls]
-"Issues" = "https://github.com/ig-python/trading-ig/issues"
-
-[build-system]
-requires = ["poetry-core>=2.0.0,<3.0.0"]
-build-backend = "poetry.core.masonry.api"
+[tool.uv.build-backend]
+module-name = "trading_ig"
+module-root = ""
diff --git a/sample/rest.ipynb b/sample/rest.ipynb
index 6783168..f9f06c2 100644
--- a/sample/rest.ipynb
+++ b/sample/rest.ipynb
@@ -33,7 +33,7 @@
"service.create_session()\n",
"\n",
"# creating a v3 session\n",
- "#service.create_session(version=\"3\")"
+ "# service.create_session(version=\"3\")"
]
},
{
@@ -78,7 +78,7 @@
" resolution=\"D\",\n",
" start_date=\"2024-01-01\",\n",
" end_date=\"2024-01-22\",\n",
- " format=service.flat_prices\n",
+ " format=service.flat_prices,\n",
")\n",
"\n",
"data[\"prices\"]"
@@ -103,10 +103,10 @@
"source": [
"from pathlib import Path\n",
"\n",
- "save_path = Path('~').expanduser() / \"prices.csv\"\n",
+ "save_path = Path(\"~\").expanduser() / \"prices.csv\"\n",
"print(f\"saving historic prices to {save_path}\")\n",
"\n",
- "data[\"prices\"].to_csv(save_path, date_format=\"%Y-%m-%dT%H:%M:%S%z\")\n"
+ "data[\"prices\"].to_csv(save_path, date_format=\"%Y-%m-%dT%H:%M:%S%z\")"
]
},
{
@@ -127,6 +127,7 @@
"outputs": [],
"source": [
"from datetime import datetime, timedelta\n",
+ "\n",
"to_date = datetime.now()\n",
"from_date = to_date - timedelta(days=7)\n",
"\n",
diff --git a/tests/test_activities.py b/tests/test_activities.py
index 88f564f..5a3e1d6 100644
--- a/tests/test_activities.py
+++ b/tests/test_activities.py
@@ -7,7 +7,6 @@
class TestActivities:
-
"""
unit tests for activities
"""
diff --git a/tests/test_historical_prices.py b/tests/test_historical_prices.py
index 8d098e9..0d139e8 100644
--- a/tests/test_historical_prices.py
+++ b/tests/test_historical_prices.py
@@ -125,9 +125,7 @@ def test_historical_prices_v3_num_points_bad_numpoints(self):
responses.GET,
"https://demo-api.ig.com/gateway/deal/prices/MT.D.GC.Month2.IP",
headers={"CST": "abc123", "X-SECURITY-TOKEN": "xyz987"},
- json={
- "errorCode": "Unable to convert value=3.14159 to type= Integer int"
- }, # noqa
+ json={"errorCode": "Unable to convert value=3.14159 to type= Integer int"}, # noqa
status=400,
)
@@ -420,9 +418,7 @@ def test_historical_prices_by_epic_and_num_points_bad_numpoints(self):
responses.GET,
"https://demo-api.ig.com/gateway/deal/prices/MT.D.GC.Month2.IP",
headers={"CST": "abc123", "X-SECURITY-TOKEN": "xyz987"},
- json={
- "errorCode": "Unable to convert value=3.14159 to type= Integer int"
- }, # noqa
+ json={"errorCode": "Unable to convert value=3.14159 to type= Integer int"}, # noqa
status=400,
)
diff --git a/tests/test_historical_prices_flat.py b/tests/test_historical_prices_flat.py
index 029105b..c1a5add 100644
--- a/tests/test_historical_prices_flat.py
+++ b/tests/test_historical_prices_flat.py
@@ -130,9 +130,7 @@ def test_historical_prices_v3_num_points_bad_numpoints(self):
responses.GET,
"https://demo-api.ig.com/gateway/deal/prices/MT.D.GC.Month2.IP",
headers={"CST": "abc123", "X-SECURITY-TOKEN": "xyz987"},
- json={
- "errorCode": "Unable to convert value=3.14159 to type= Integer int"
- }, # noqa
+ json={"errorCode": "Unable to convert value=3.14159 to type= Integer int"}, # noqa
status=400,
)
diff --git a/tests/test_positions.py b/tests/test_positions.py
index e69a0dc..e746992 100644
--- a/tests/test_positions.py
+++ b/tests/test_positions.py
@@ -5,7 +5,6 @@
class TestPositions:
-
"""
unit tests for position methods
"""
diff --git a/trading_ig/lightstreamer.py b/trading_ig/lightstreamer.py
index 65e2a97..0d6be9c 100644
--- a/trading_ig/lightstreamer.py
+++ b/trading_ig/lightstreamer.py
@@ -191,8 +191,7 @@ def connect(self):
if not notify and sys.platform.startswith("linux"):
log.warning(
- "systemd.daemon not available, "
- "no watchdog notifications will be sent."
+ "systemd.daemon not available, no watchdog notifications will be sent."
)
self._stream_connection = self._call(
diff --git a/trading_ig/rest.py b/trading_ig/rest.py
index aaf1236..692c3e4 100644
--- a/trading_ig/rest.py
+++ b/trading_ig/rest.py
@@ -359,10 +359,9 @@ def _get_session(self, session):
if session is None:
session = self.session # requests Session
else:
- assert isinstance(
- session, Session
- ), "session must be not %s" % type(
- session
+ assert isinstance(session, Session), (
+ "session must be not %s"
+ % type(session)
)
session = session
return session