diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c0813d4..2be7ebb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,10 +10,6 @@ on: tags: - "v*" -env: - PYTHON_VERSION: "3.8" - POETRY_VERSION: "1.5" - jobs: lint: name: Lint @@ -53,9 +49,9 @@ jobs: - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python }} - - run: pip install poetry==${{ env.POETRY_VERSION }} - - run: poetry install - - run: poetry run python -m pytest + - name: Install uv + uses: astral-sh/setup-uv@v2 + - run: uv run pytest env: AXIOM_URL: ${{ secrets[matrix.url] }} AXIOM_TOKEN: ${{ secrets[matrix.token] }} @@ -69,8 +65,13 @@ jobs: - test-integration steps: - uses: actions/checkout@v4 + - name: Install uv + uses: astral-sh/setup-uv@v2 - uses: actions/setup-python@v5 with: - python-version: ${{ env.PYTHON_VERSION }} - - run: pip install poetry==${{ env.POETRY_VERSION }} - - run: poetry publish --build -u __token__ -p "${{ secrets.PYPI_TOKEN }}" + python-version-file: "pyproject.toml" + - run: uv build + - run: uvx twine upload dist/* + env: + TWINE_USERNAME: "__token__" + TWINE_PASSWORD: "${{ secrets.PYPI_TOKEN }}" diff --git a/.gitignore b/.gitignore index 62f14c5..5a9e10f 100644 --- a/.gitignore +++ b/.gitignore @@ -140,3 +140,6 @@ poetry.lock # Direnv /.envrc /.direnv + +# UV lockfiles +uv.lock diff --git a/README.md b/README.md index 14446e0..8d6dfa7 100644 --- a/README.md +++ b/README.md @@ -49,19 +49,19 @@ Otherwise create a personal token in [the Axiom settings](https://cloud.axiom.co You can also configure the client using options passed to the client constructor: ```py -import axiom +import axiom_py -client = axiom.Client("", "") +client = axiom_py.Client("", "") ``` Create and use a client like this: ```py -import axiom +import axiom_py import rfc3339 from datetime import datetime,timedelta -client = axiom.Client() +client = axiom_py.Client() time = datetime.utcnow() - timedelta(hours=1) time_formatted = rfc3339.format(time) @@ -75,15 +75,12 @@ client.ingest_events( client.query(r"['my-dataset'] | where foo == 'bar' | limit 100") ``` -for more examples, check out the [examples](examples) directory. +for more examples, check out `examples.py`. ## Contributing -This project uses [Poetry](https://python-poetry.org) for dependecy management -and packaging, so make sure that this is installed (see [Poetry Installation](https://python-poetry.org/docs/#installation)). - -Run `poetry install` to install dependencies and `poetry shell` to activate a -virtual environment. +This project uses [uv](https://docs.astral.sh/uv) for dependency management +and packaging, so make sure that this is installed. ## License diff --git a/examples.py b/examples.py new file mode 100644 index 0000000..3bd321c --- /dev/null +++ b/examples.py @@ -0,0 +1,31 @@ +from axiom_py import Client, DatasetCreateRequest + + +def main(): + client = Client() + dataset_name = "my-dataset" + + # List datasets + res = client.datasets.get_list() + for dataset in res: + print(dataset.name) + + # Create a dataset + client.datasets.create( + DatasetCreateRequest(name=dataset_name, description="A description.") + ) + + # Ingest events + client.ingest_events(dataset_name, [{"foo": "bar"}]) + + # Query events + res = client.query(f"['{dataset_name}'] | where status == 500") + for match in res.matches: + print(match.data) + + # Delete the dataset + client.datasets.delete(dataset_name) + + +if __name__ == "__main__": + main() diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index ec14f59..0000000 --- a/examples/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Examples - -## Usage - -```shell -export AXIOM_TOKEN="..." -python -``` - - -## Examples - -- [ingest.py](ingest.py) - Ingest events into Axiom -- [query.py](query.py) - Query a dataset as part of the request -- [query_legacy.py](query_legacy.py) - Query a dataset using the legacy query method -- [create_dateset.py](create_dataset.py) - Create a new dataset -- [list_datasets.py](list_datasets.py) - Retrieve a list of all datasets -- [delete_dataset.py](delete_dataset.py) - Delete a dataset -- diff --git a/examples/create_dataset.py b/examples/create_dataset.py deleted file mode 100644 index d5de57b..0000000 --- a/examples/create_dataset.py +++ /dev/null @@ -1,9 +0,0 @@ -from axiom import Client, DatasetCreateRequest - - -def create_dataset(dataset_name): - client = Client() - res = client.datasets.create( - DatasetCreateRequest(name=dataset_name, description="") - ) - print(f"created dataset: {res.id}") diff --git a/examples/delete_dataset.py b/examples/delete_dataset.py deleted file mode 100644 index da98736..0000000 --- a/examples/delete_dataset.py +++ /dev/null @@ -1,7 +0,0 @@ -from axiom import Client - - -def delete_dataset(dataset_name): - client = Client() - client.datasets.delete(dataset_name) - print("deleted dataset: my-dateset") diff --git a/examples/ingest.py b/examples/ingest.py deleted file mode 100644 index b7e27b4..0000000 --- a/examples/ingest.py +++ /dev/null @@ -1,8 +0,0 @@ -from axiom import Client - - -def ingest(dataset_name): - client = Client() - res = client.ingest_events(dataset_name, [{"foo": "bar"}]) - print(f"Ingested {len(res.ingested)} events with { - len(res.failures)} failures") diff --git a/examples/list_datasets.py b/examples/list_datasets.py deleted file mode 100644 index 47fdc8d..0000000 --- a/examples/list_datasets.py +++ /dev/null @@ -1,8 +0,0 @@ -from axiom import Client - - -def list_datasets(): - client = Client() - res = client.datasets.get_list() - for dataset in res: - print(f"found dataset: {dataset.name}") diff --git a/examples/main.py b/examples/main.py deleted file mode 100644 index 6e551a4..0000000 --- a/examples/main.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -from create_dataset import create_dataset -from delete_dataset import delete_dataset -from list_datasets import list_datasets -from ingest import ingest -from query import query -from query_legacy import queryLegacy - - -def main(): - dataset_name = "my-dataset" - # create a new dataset - create_dataset(dataset_name) - list_datasets() - # ingest some data - ingest(dataset_name) - # query the ingested data - query(dataset_name) - queryLegacy(dataset_name) - # finally, delete the dataset - delete_dataset(dataset_name) - - -if __name__ == "__main__": - main() diff --git a/examples/pyproject.toml b/examples/pyproject.toml deleted file mode 100644 index 989e5cf..0000000 --- a/examples/pyproject.toml +++ /dev/null @@ -1,19 +0,0 @@ -[tool.poetry] -name = "axiom-py-examples" -version = "0.1" -description = "Axiom API Python bindings examples." -authors = ["Axiom, Inc."] -license = "MIT" - -[tool.poetry.dependencies] -python = "^3.8" -axiom-py = { path = "../" } - - -[tool.poetry.dev-dependencies] -pylint = "^2.7.2" - - -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" diff --git a/examples/query.py b/examples/query.py deleted file mode 100644 index a266a8d..0000000 --- a/examples/query.py +++ /dev/null @@ -1,10 +0,0 @@ -from axiom import Client - - -def query(dataset_name): - aplQuery = f"['{dataset_name}'] | where status == 500" - - client = Client() - res = client.query(aplQuery) - for match in res.matches: - print(match.data) diff --git a/examples/query_legacy.py b/examples/query_legacy.py deleted file mode 100644 index f89c721..0000000 --- a/examples/query_legacy.py +++ /dev/null @@ -1,19 +0,0 @@ -from axiom import Client, QueryLegacy, QueryOptions, QueryKind -from datetime import datetime, timedelta - - -def queryLegacy(dataset_name): - endTime = datetime.now() - startTime = endTime - timedelta(days=1) - query = QueryLegacy(startTime=startTime, endTime=endTime) - - client = Client() - res = client.query_legacy( - dataset_name, query, QueryOptions(saveAsKind=QueryKind.ANALYTICS) - ) - if res.matches is None or len(res.matches) == 0: - print("No matches found") - return - - for match in res.matches: - print(match.data) diff --git a/pyproject.toml b/pyproject.toml index 771ba03..b27ecbf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,34 +1,36 @@ -[tool.poetry] +[project] name = "axiom-py" version = "0.5.0" -description = "Axiom API Python bindings." -authors = ["Axiom, Inc."] -license = "MIT" -packages = [ - { include = "axiom" }, +description = "Official bindings for the Axiom API" +readme = "README.md" +requires-python = ">=3.8" +dependencies = [ + "requests>=2.32.3", + "requests-toolbelt>=1.0.0", + "ujson>=5.10.0", + "dacite>=1.8.1", + "pyhumps>=3.8.0", + "ndjson>=0.3.1", ] +license = { file = "LICENSE" } -[tool.poetry.dependencies] -# urllib 3 has a breaking change in 2.0.0 -urllib3 = "<3.0.0" -python = "^3.8" -requests = "^2.30.0" -requests-toolbelt = ">= 0.9.1, <1.1.0" -ujson = "^5.2.0" -dacite = "^1.6.0" -pyhumps = ">=1.6.1,<4.0.0" -ndjson = "^0.3.1" -rfc3339 = "^6.2" -iso8601 = ">=1.0.2,<3.0.0" - -[tool.poetry.dev-dependencies] -pytest = "^8.2.1" -responses = "^0.25.0" -ruff = "^0.6.4" +[project.urls] +Homepage = "https://axiom.co" +Repository = "https://github.com/axiomhq/axiom-py.git" +Issues = "https://github.com/axiomhq/axiom-py/issues" [build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" +requires = ["hatchling"] +build-backend = "hatchling.build" [tool.ruff] line-length = 79 # PEP 8 + +[tool.uv] +dev-dependencies = [ + "ruff>=0.6.4", + "pytest>=8.3.2", + "responses>=0.25.3", + "rfc3339>=6.2", + "iso8601>=1.0.2", +] diff --git a/axiom/__init__.py b/src/axiom_py/__init__.py similarity index 100% rename from axiom/__init__.py rename to src/axiom_py/__init__.py diff --git a/axiom/annotations.py b/src/axiom_py/annotations.py similarity index 100% rename from axiom/annotations.py rename to src/axiom_py/annotations.py diff --git a/axiom/client.py b/src/axiom_py/client.py similarity index 100% rename from axiom/client.py rename to src/axiom_py/client.py diff --git a/axiom/datasets.py b/src/axiom_py/datasets.py similarity index 100% rename from axiom/datasets.py rename to src/axiom_py/datasets.py diff --git a/axiom/logging.py b/src/axiom_py/logging.py similarity index 100% rename from axiom/logging.py rename to src/axiom_py/logging.py diff --git a/axiom/query/__init__.py b/src/axiom_py/query/__init__.py similarity index 100% rename from axiom/query/__init__.py rename to src/axiom_py/query/__init__.py diff --git a/axiom/query/aggregation.py b/src/axiom_py/query/aggregation.py similarity index 100% rename from axiom/query/aggregation.py rename to src/axiom_py/query/aggregation.py diff --git a/axiom/query/filter.py b/src/axiom_py/query/filter.py similarity index 100% rename from axiom/query/filter.py rename to src/axiom_py/query/filter.py diff --git a/axiom/query/options.py b/src/axiom_py/query/options.py similarity index 100% rename from axiom/query/options.py rename to src/axiom_py/query/options.py diff --git a/axiom/query/query.py b/src/axiom_py/query/query.py similarity index 100% rename from axiom/query/query.py rename to src/axiom_py/query/query.py diff --git a/axiom/query/result.py b/src/axiom_py/query/result.py similarity index 100% rename from axiom/query/result.py rename to src/axiom_py/query/result.py diff --git a/axiom/users.py b/src/axiom_py/users.py similarity index 100% rename from axiom/users.py rename to src/axiom_py/users.py diff --git a/axiom/util.py b/src/axiom_py/util.py similarity index 100% rename from axiom/util.py rename to src/axiom_py/util.py diff --git a/axiom/version.py b/src/axiom_py/version.py similarity index 100% rename from axiom/version.py rename to src/axiom_py/version.py diff --git a/tests/test_annotations.py b/tests/test_annotations.py index bddbe8e..75492a9 100644 --- a/tests/test_annotations.py +++ b/tests/test_annotations.py @@ -5,7 +5,7 @@ import unittest from logging import getLogger from .helpers import get_random_name -from axiom import ( +from axiom_py import ( Client, DatasetCreateRequest, AnnotationCreateRequest, diff --git a/tests/test_client.py b/tests/test_client.py index 5f13b77..1425bb3 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -10,7 +10,7 @@ from datetime import datetime, timedelta from .helpers import get_random_name from requests.exceptions import HTTPError -from axiom import ( +from axiom_py import ( Client, AplOptions, AplResultFormat, @@ -20,7 +20,7 @@ WrongQueryKindException, DatasetCreateRequest, ) -from axiom.query import ( +from axiom_py.query import ( QueryLegacy, QueryOptions, QueryKind, diff --git a/tests/test_datasets.py b/tests/test_datasets.py index 03d3007..ebe504a 100644 --- a/tests/test_datasets.py +++ b/tests/test_datasets.py @@ -8,7 +8,7 @@ from requests.exceptions import HTTPError from datetime import timedelta from .helpers import get_random_name -from axiom import ( +from axiom_py import ( Client, DatasetCreateRequest, DatasetUpdateRequest, diff --git a/tests/test_logger.py b/tests/test_logger.py index 7559ad4..b8c6f55 100644 --- a/tests/test_logger.py +++ b/tests/test_logger.py @@ -4,8 +4,8 @@ import logging import unittest from .helpers import get_random_name -from axiom import Client, DatasetCreateRequest -from axiom.logging import AxiomHandler +from axiom_py import Client, DatasetCreateRequest +from axiom_py.logging import AxiomHandler class TestLogger(unittest.TestCase):