Skip to content

Commit

Permalink
chg: Update everything
Browse files Browse the repository at this point in the history
  • Loading branch information
Rafiot committed Nov 26, 2024
1 parent 0fca7f3 commit bc28781
Show file tree
Hide file tree
Showing 7 changed files with 452 additions and 328 deletions.
17 changes: 17 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "daily"

- package-ecosystem: "github-actions"
directory: "/"
schedule:
# Check for updates to GitHub Actions every weekday
interval: "daily"
26 changes: 18 additions & 8 deletions .github/workflows/mypy.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
name: Python application
name: Python application - MyPy

on: [push]
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build:

runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
name: Python ${{ matrix.python-version }} sample

steps:
- uses: actions/checkout@v1
- name: Set up Python 3.8
uses: actions/setup-python@v1
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.8
- name: Install dependencies
python-version: ${{matrix.python-version}}

- name: Install poetry
run: |
python -m pip install --upgrade pip poetry
poetry install
- name: Test typing with mypy
- name: Test with MyPy
run: |
poetry run mypy .
26 changes: 26 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
on:
release:
types:
- published

name: release

jobs:
pypi-publish:
name: Upload release to PyPI
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/pyipasnhistory
permissions:
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Poetry
run: python -m pip install --upgrade pip poetry
- name: Build artifacts
run: poetry build
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
16 changes: 16 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
exclude: "tests/data"
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- repo: https://github.com/asottile/pyupgrade
rev: v3.19.0
hooks:
- id: pyupgrade
args: [--py38-plus]
630 changes: 338 additions & 292 deletions poetry.lock

Large diffs are not rendered by default.

48 changes: 30 additions & 18 deletions pyipasnhistory/api.py
Original file line number Diff line number Diff line change
@@ -1,61 +1,73 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from __future__ import annotations

import json
import requests

from typing import Dict, Any, Optional
from importlib.metadata import version
from typing import Dict, Any, Optional, List
from urllib.parse import urljoin, urlparse

import ipaddress

from urllib3.util import Retry
from requests.adapters import HTTPAdapter


class IPASNHistory():

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

@property
def is_up(self):
r = self.session.head(self.root_url)
def is_up(self) -> bool:
'''Test if the given instance is accessible'''
try:
r = self.session.head(self.root_url)
except requests.exceptions.ConnectionError:
return False
return r.status_code == 200

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

def mass_cache(self, list_to_cache: list):
def mass_cache(self, list_to_cache: list[dict[str, Any]]):
'''Cache a list of IP queries. The next call on the same IPs will be very quick.'''
to_query = []
for entry in list_to_cache:
if 'precision_delta' in entry:
entry['precision_delta'] = json.dumps(entry.pop('precision_delta'))
to_query.append(entry)

r = self.session.post(urljoin(self.root_url, 'mass_cache'), data=json.dumps(to_query))
r = self.session.post(urljoin(self.root_url, 'mass_cache'), json=to_query)
return r.json()

def mass_query(self, list_to_query: list):
def mass_query(self, list_to_query: list[dict[str, Any]]) -> dict[str, Any]:
'''Query a list of IPs.'''
to_query = []
for entry in list_to_query:
if 'precision_delta' in entry:
entry['precision_delta'] = json.dumps(entry.pop('precision_delta'))
to_query.append(entry)
r = self.session.post(urljoin(self.root_url, 'mass_query'), data=json.dumps(to_query))
r = self.session.post(urljoin(self.root_url, 'mass_query'), json=to_query)
return r.json()

def asn_meta(self, asn: Optional[int]=None, source: Optional[str]=None, address_family: str='v4',
date: Optional[str]=None, first: Optional[str]=None, last: Optional[str]=None,
precision_delta: Optional[Dict]=None):
def asn_meta(self, asn: int | None=None, source: str | None=None, address_family: str='v4',
date: str | None=None, first: str | None=None, last: str | None=None,
precision_delta: dict | None=None):
'''Get all the prefixes annonced by an AS'''
to_query: Dict[str, Any] = {'address_family': address_family}
to_query: dict[str, Any] = {'address_family': address_family}
if source:
to_query['source'] = source
if asn:
Expand All @@ -69,10 +81,10 @@ def asn_meta(self, asn: Optional[int]=None, source: Optional[str]=None, address_
if precision_delta:
to_query['precision_delta'] = json.dumps(precision_delta)

r = self.session.post(urljoin(self.root_url, 'asn_meta'), data=json.dumps(to_query))
r = self.session.post(urljoin(self.root_url, 'asn_meta'), json=to_query)
return r.json()

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

def query(self, ip: str, source: Optional[str]=None, address_family: Optional[str]=None,
date: Optional[str]=None, first: Optional[str]=None, last: Optional[str]=None,
precision_delta: Optional[Dict]=None, aggregate: bool=False):
def query(self, ip: str, source: str | None=None, address_family: str | None=None,
date: str | None=None, first: str | None=None, last: str | None=None,
precision_delta: dict | None=None, aggregate: bool=False):
'''Launch a query.
:param ip: IP to lookup
Expand Down
17 changes: 7 additions & 10 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "pyipasnhistory"
version = "2.1.2"
version = "2.1.3"
description = "Python client for IP ASN History"
authors = ["Raphaël Vinot <raphael.vinot@circl.lu>"]
license = "AGPL"
Expand All @@ -19,28 +19,25 @@ classifiers = [
'Intended Audience :: Telecommunications Industry',
'Intended Audience :: Information Technology',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.8',
'Topic :: Security',
'Topic :: Internet',
]

include = ['README.md']

[tool.poetry.scripts]
ipasnhistory = "pyipasnhistory:main"

[tool.poetry.dependencies]
python = "^3.8"
requests = "^2.28.1"
Sphinx = { version = "^5.3.0", optional = true }
python = "^3.9"
requests = "^2.32.3"
Sphinx = { version = "^8.1.3", python = ">=3.10", optional = true }

[tool.poetry.dev-dependencies]
mypy = "^0.991"
types-requests = "^2.28.11.7"
mypy = "^1.13.0"
types-requests = "^2.32.0.20241016"

[tool.poetry.extras]
docs = ["Sphinx"]

[build-system]
requires = ["poetry-core>=1.0.0"]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

0 comments on commit bc28781

Please sign in to comment.