<jupyter_start><jupyter_text>AdapterSince 3.3 kloppy uses adapters to load data from external sources. kloppy is shipped with support for `http` and `s3`, but you can add your own adapters to support different external sources. S3kloppy uses `s3fs` to access files on s3. If preferred you can create a `s3fs.S3FileSystem` instance and pass it via `set_config`<jupyter_code>import s3fs

from kloppy import statsbomb
from kloppy.config import set_config

file_system = s3fs.S3FileSystem(anon=True)
set_config(
    'adapters.s3.s3fs',
    file_system
)

# This will fail because we don't have access to 'some-bucket'
dataset = statsbomb.load(
    event_data='s3://some-bucket/1234/events.json',
    lineup_data='s3://some-bucket/1234/lineup.json'
)<jupyter_output><empty_output><jupyter_text>Custom adapter - databaseIt's possible to create your own adapter. For example a database adapter.First create a table within a sqlite database to hold the file content.<jupyter_code>import sqlite3

# Setup a table
con = sqlite3.connect('database.db')

try:
    con.execute("CREATE TABLE files(match_id INT, file_type TEXT, data TEXT, UNIQUE(match_id, file_type))")
    con.commit()
except sqlite3.OperationalError:
    # already exists
    pass

# Load some open data into the database
import requests

def load_into_table(match_id):
    events_data = requests.get(f"https://raw.githubusercontent.com/statsbomb/open-data/master/data/events/{match_id}.json")
    con.execute("INSERT INTO files values(?, ?, ?)", (match_id, 'events', events_data.content))
    lineup_data = requests.get(f"https://raw.githubusercontent.com/statsbomb/open-data/master/data/lineups/{match_id}.json")
    con.execute("INSERT INTO files values(?, ?, ?)", (match_id, 'lineup', lineup_data.content))
    con.commit()<jupyter_output><empty_output><jupyter_text>Next load the data from two matches into the database<jupyter_code>load_into_table(9636)
load_into_table(9609)<jupyter_output><empty_output><jupyter_text>Define our database adapter. The adapter supports all urls starting with `db://`<jupyter_code>from typing import BinaryIO

from kloppy.infra.io.adapters import Adapter, adapters

class DBAdapter(Adapter):
    def __init__(self, con):
        self.con = con
        
    def supports(self, url: str):
        return url.startswith("db://")
    
    def read_to_stream(self, url: str, output: BinaryIO):
        match_id, file_type = url[5:].split("/")
        cursor = con.cursor()
        cursor.execute("SELECT data FROM files WHERE match_id = ? AND file_type = ?", (match_id, file_type))
        result = cursor.fetchone()
        output.write(result[0])

db_adapter = DBAdapter(con)

# When you rerun this code you might need to run: adapters.clear()
adapters.append(db_adapter)

set_config('cache', None)<jupyter_output><empty_output><jupyter_text>Use the adapter!<jupyter_code>dataset = statsbomb.load(
    event_data="db://9636/events",
    lineup_data="db://9636/lineup",
)
home_team, away_team = dataset.metadata.teams
print(f"Loaded from database: {home_team} - {away_team}")<jupyter_output>Loaded from database: Barcelona - Las Palmas
{'fraction_non_alphanumeric': 0.11335254562920269, 'fraction_numerical': 0.01408901697086135, 'mean_word_length': 4.8283582089552235, 'pattern_counts': {'":': 0, '<': 20, '<?xml version=': 0, '>': 20, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '467099', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 1057, 'n_tokens_neox': 1018, 'n_words': 260, 'path': 'docs/examples/adapter.ipynb', 'repo_name': 'pratikthanki/kloppy', 'size': '3123'}