Skip to content

Commit bc28781

Browse files
committed
chg: Update everything
1 parent 0fca7f3 commit bc28781

File tree

7 files changed

+452
-328
lines changed

7 files changed

+452
-328
lines changed

.github/dependabot.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# To get started with Dependabot version updates, you'll need to specify which
2+
# package ecosystems to update and where the package manifests are located.
3+
# Please see the documentation for all configuration options:
4+
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5+
6+
version: 2
7+
updates:
8+
- package-ecosystem: "pip"
9+
directory: "/"
10+
schedule:
11+
interval: "daily"
12+
13+
- package-ecosystem: "github-actions"
14+
directory: "/"
15+
schedule:
16+
# Check for updates to GitHub Actions every weekday
17+
interval: "daily"

.github/workflows/mypy.yml

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,32 @@
1-
name: Python application
1+
name: Python application - MyPy
22

3-
on: [push]
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
48

59
jobs:
610
build:
711

812
runs-on: ubuntu-latest
13+
strategy:
14+
matrix:
15+
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
16+
name: Python ${{ matrix.python-version }} sample
917

1018
steps:
11-
- uses: actions/checkout@v1
12-
- name: Set up Python 3.8
13-
uses: actions/setup-python@v1
19+
- uses: actions/checkout@v4
20+
- name: Set up Python
21+
uses: actions/setup-python@v5
1422
with:
15-
python-version: 3.8
16-
- name: Install dependencies
23+
python-version: ${{matrix.python-version}}
24+
25+
- name: Install poetry
1726
run: |
1827
python -m pip install --upgrade pip poetry
1928
poetry install
20-
- name: Test typing with mypy
29+
30+
- name: Test with MyPy
2131
run: |
2232
poetry run mypy .

.github/workflows/release.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
on:
2+
release:
3+
types:
4+
- published
5+
6+
name: release
7+
8+
jobs:
9+
pypi-publish:
10+
name: Upload release to PyPI
11+
runs-on: ubuntu-latest
12+
environment:
13+
name: pypi
14+
url: https://pypi.org/p/pyipasnhistory
15+
permissions:
16+
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
17+
steps:
18+
- uses: actions/checkout@v4
19+
with:
20+
fetch-depth: 0
21+
- name: Install Poetry
22+
run: python -m pip install --upgrade pip poetry
23+
- name: Build artifacts
24+
run: poetry build
25+
- name: Publish package distributions to PyPI
26+
uses: pypa/gh-action-pypi-publish@release/v1

.pre-commit-config.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# See https://pre-commit.com for more information
2+
# See https://pre-commit.com/hooks.html for more hooks
3+
exclude: "tests/data"
4+
repos:
5+
- repo: https://github.com/pre-commit/pre-commit-hooks
6+
rev: v5.0.0
7+
hooks:
8+
- id: trailing-whitespace
9+
- id: end-of-file-fixer
10+
- id: check-yaml
11+
- id: check-added-large-files
12+
- repo: https://github.com/asottile/pyupgrade
13+
rev: v3.19.0
14+
hooks:
15+
- id: pyupgrade
16+
args: [--py38-plus]

poetry.lock

Lines changed: 338 additions & 292 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyipasnhistory/api.py

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,73 @@
11
#!/usr/bin/env python3
2-
# -*- coding: utf-8 -*-
2+
3+
from __future__ import annotations
34

45
import json
56
import requests
67

7-
from typing import Dict, Any, Optional
8+
from importlib.metadata import version
9+
from typing import Dict, Any, Optional, List
810
from urllib.parse import urljoin, urlparse
911

1012
import ipaddress
1113

14+
from urllib3.util import Retry
15+
from requests.adapters import HTTPAdapter
16+
1217

1318
class IPASNHistory():
1419

15-
def __init__(self, root_url: str='https://ipasnhistory.circl.lu/'):
20+
def __init__(self, root_url: str='https://ipasnhistory.circl.lu/', useragent: str | None=None) -> None:
1621
self.root_url = root_url
1722
if not urlparse(self.root_url).scheme:
1823
self.root_url = 'http://' + self.root_url
1924
if not self.root_url.endswith('/'):
2025
self.root_url += '/'
2126
self.session = requests.session()
27+
self.session.headers['user-agent'] = useragent if useragent else f'PyIPASNHIstory / {version("pyipasnhistory")}'
28+
retries = Retry(total=5, backoff_factor=0.1, status_forcelist=[500, 502, 503, 504])
29+
self.session.mount('http://', HTTPAdapter(max_retries=retries))
2230

2331
@property
24-
def is_up(self):
25-
r = self.session.head(self.root_url)
32+
def is_up(self) -> bool:
33+
'''Test if the given instance is accessible'''
34+
try:
35+
r = self.session.head(self.root_url)
36+
except requests.exceptions.ConnectionError:
37+
return False
2638
return r.status_code == 200
2739

2840
def meta(self):
2941
'''Get meta information from the remote instance'''
3042
r = requests.get(urljoin(self.root_url, 'meta'))
3143
return r.json()
3244

33-
def mass_cache(self, list_to_cache: list):
45+
def mass_cache(self, list_to_cache: list[dict[str, Any]]):
3446
'''Cache a list of IP queries. The next call on the same IPs will be very quick.'''
3547
to_query = []
3648
for entry in list_to_cache:
3749
if 'precision_delta' in entry:
3850
entry['precision_delta'] = json.dumps(entry.pop('precision_delta'))
3951
to_query.append(entry)
4052

41-
r = self.session.post(urljoin(self.root_url, 'mass_cache'), data=json.dumps(to_query))
53+
r = self.session.post(urljoin(self.root_url, 'mass_cache'), json=to_query)
4254
return r.json()
4355

44-
def mass_query(self, list_to_query: list):
56+
def mass_query(self, list_to_query: list[dict[str, Any]]) -> dict[str, Any]:
4557
'''Query a list of IPs.'''
4658
to_query = []
4759
for entry in list_to_query:
4860
if 'precision_delta' in entry:
4961
entry['precision_delta'] = json.dumps(entry.pop('precision_delta'))
5062
to_query.append(entry)
51-
r = self.session.post(urljoin(self.root_url, 'mass_query'), data=json.dumps(to_query))
63+
r = self.session.post(urljoin(self.root_url, 'mass_query'), json=to_query)
5264
return r.json()
5365

54-
def asn_meta(self, asn: Optional[int]=None, source: Optional[str]=None, address_family: str='v4',
55-
date: Optional[str]=None, first: Optional[str]=None, last: Optional[str]=None,
56-
precision_delta: Optional[Dict]=None):
66+
def asn_meta(self, asn: int | None=None, source: str | None=None, address_family: str='v4',
67+
date: str | None=None, first: str | None=None, last: str | None=None,
68+
precision_delta: dict | None=None):
5769
'''Get all the prefixes annonced by an AS'''
58-
to_query: Dict[str, Any] = {'address_family': address_family}
70+
to_query: dict[str, Any] = {'address_family': address_family}
5971
if source:
6072
to_query['source'] = source
6173
if asn:
@@ -69,10 +81,10 @@ def asn_meta(self, asn: Optional[int]=None, source: Optional[str]=None, address_
6981
if precision_delta:
7082
to_query['precision_delta'] = json.dumps(precision_delta)
7183

72-
r = self.session.post(urljoin(self.root_url, 'asn_meta'), data=json.dumps(to_query))
84+
r = self.session.post(urljoin(self.root_url, 'asn_meta'), json=to_query)
7385
return r.json()
7486

75-
def _aggregate_details(self, details: dict):
87+
def _aggregate_details(self, details: dict) -> list:
7688
'''Aggregare the response when the asn/prefix tuple is the same over a period of time.'''
7789
to_return = []
7890
current = None
@@ -91,9 +103,9 @@ def _aggregate_details(self, details: dict):
91103
to_return.append(current)
92104
return to_return
93105

94-
def query(self, ip: str, source: Optional[str]=None, address_family: Optional[str]=None,
95-
date: Optional[str]=None, first: Optional[str]=None, last: Optional[str]=None,
96-
precision_delta: Optional[Dict]=None, aggregate: bool=False):
106+
def query(self, ip: str, source: str | None=None, address_family: str | None=None,
107+
date: str | None=None, first: str | None=None, last: str | None=None,
108+
precision_delta: dict | None=None, aggregate: bool=False):
97109
'''Launch a query.
98110
99111
:param ip: IP to lookup

pyproject.toml

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "pyipasnhistory"
3-
version = "2.1.2"
3+
version = "2.1.3"
44
description = "Python client for IP ASN History"
55
authors = ["Raphaël Vinot <raphael.vinot@circl.lu>"]
66
license = "AGPL"
@@ -19,28 +19,25 @@ classifiers = [
1919
'Intended Audience :: Telecommunications Industry',
2020
'Intended Audience :: Information Technology',
2121
'Programming Language :: Python :: 3',
22-
'Programming Language :: Python :: 3.8',
2322
'Topic :: Security',
2423
'Topic :: Internet',
2524
]
2625

27-
include = ['README.md']
28-
2926
[tool.poetry.scripts]
3027
ipasnhistory = "pyipasnhistory:main"
3128

3229
[tool.poetry.dependencies]
33-
python = "^3.8"
34-
requests = "^2.28.1"
35-
Sphinx = { version = "^5.3.0", optional = true }
30+
python = "^3.9"
31+
requests = "^2.32.3"
32+
Sphinx = { version = "^8.1.3", python = ">=3.10", optional = true }
3633

3734
[tool.poetry.dev-dependencies]
38-
mypy = "^0.991"
39-
types-requests = "^2.28.11.7"
35+
mypy = "^1.13.0"
36+
types-requests = "^2.32.0.20241016"
4037

4138
[tool.poetry.extras]
4239
docs = ["Sphinx"]
4340

4441
[build-system]
45-
requires = ["poetry-core>=1.0.0"]
42+
requires = ["poetry-core"]
4643
build-backend = "poetry.core.masonry.api"

0 commit comments

Comments
 (0)