# pyterrier-alpha
Alpha channel of features for [PyTerrier](https://github.com/terrier-org/pyterrier).
Features in ths package are under development and intend to be merged with the main package or split into a separate package when stable.
<details>
<summary>Table of Contents</summary>
- [Getting Started](#gettingstarted)
- [`pta.validate`](#ptavalidate)
- [`pta.DataFrameBuilder`](#ptadataframebuilder)
- [`pta.Artifact`](#ptaartifact)
- [`pta.io`](#ptaio)
</details>
## Getting Started
```bash
pip install pyterrier-alpha
```
Import `pyterrier_alpha` alongside `pyterrier`:
```python
import pyterrier as pt
import pyterrier_alpha as pta
```
## pta.validate
It's a good idea to check the input to a transformer to make sure its compatible before you start using it.
`pta.validate` provides functions for this.
```python
def MyTransformer(pt.Transformer):
def transform(self, inp: pd.DataFrame):
# e.g., expects a query frame with query_vec
pta.validate.query_frame(inp, extra_columns=['query_vec'])
# raises an error if the specification doesn't match
```
| Function | Must have column(s) | Must NOT have column(s) |
|----------|---------------------|-------------------------|
| `pta.validate.query_frame(inp, extra_columns=...)` | qid + `extra_columns` | docno |
| `pta.validate.document_frame(inp, extra_columns=...)` | docno + `extra_columns` | qid |
| `pta.validate.result_frame(inp, extra_columns=...)` | qid + docno + `extra_columns` | |
| `pta.validate.columns(inp, includes=..., excludes=...)` | `includes` | `excludes` |
**Iterable validation**
Available in: `pyterrier-alpha >= 0.6.0`
For indexing pipelines that accept iterators, it checks the fields of the first element. You need
to first wrap `inp` in `pta.utils.peekable()` for this to work.
```python
import pyterrier_alpha as pta
my_iterator = [{'docno': 'doc1'}, {'docno': 'doc2'}, {'docno': 'doc3'}]
my_iterator = pta.utils.peekable(my_iterator)
pta.validate.columns_iter(my_iterator, includes=['docno']) # passes
pta.validate.columns_iter(my_iterator, includes=['docno', 'toks']) # raises error
```
<details>
<summary>Advanced Usage (click to expand)</summary>
Sometimes a transformer has multiple acceptable input specifications, e.g., if
it can act as either a retriever (with a query input) or re-ranker (with a result input).
In this case, you can specify multiple possible configurations in a `with pta.validate.any(inpt) as v:` block:
```python
def MyTransformer(pt.Transformer):
def transform(self, inp: pd.DataFrame):
# e.g., expects a query frame with query_vec
with pta.validate.any(inp) as v:
v.query_frame(extra_columns=['query'], mode='retrieve')
v.result_frame(extra_columns=['query', 'text'], mode='rerank')
# raises an error if ALL specifications do not match
# v.mode is set to the FIRST specification that matches
if v.mode == 'retrieve':
...
if v.mode == 'rerank':
...
```
</details>
## pta.DataFrameBuilder
A common pattern in `Transformer` implementation builds up an intermediate representation of the output DataFrame,
but this can be a bit clunky, as shown below:
```python
def MyTransformer(pt.Transformer):
def transform(self, inp: pd.DataFrame):
result = {
'qid': [],
'query': [],
'docno': [],
'score': [],
}
for qid, query in zip(inp['qid'], inp['query']):
docnos, scores = self.some_function(qid, query)
result['qid'].append([qid] * len(docnos))
result['query'].append([query] * len(docnos))
result['docno'].append(docnos)
result['score'].append(scores)
result = pd.DataFrame({
'qid': np.concatenate(result['qid']),
'query': np.concatenate(result['query']),
'docno': np.concatenate(result['docno']),
'score': np.concatenate(result['score']),
})
return result
```
`pta.DataFrameBuilder` simplifies the process of building a DataFrame by removing lots of the boilerplate.
It also automatically handles various types and ensures that all columns end up with the same length.
The above example can be rewritten with `pta.DataFrameBuilder` as follows:
```python
def MyTransformer(pt.Transformer):
def transform(self, inp: pd.DataFrame):
result = pta.DataFrameBuilder(['qid', 'query', 'docno', 'score'])
for qid, query in zip(inp['qid'], inp['query']):
docnos, scores = self.some_function(qid, query)
result.extend({
'qid': qid, # automatically repeats to the length of this batch
'query': query, # ditto
'docno': docnos,
'score': scores,
})
return result.to_df()
```
## pta.Artifact
Available in: `pyterrier-alpha >= 0.2.0`
An artifact is a component stored on disk, such as an index.
Artifacts usually act as factories for transformers that use them. For example, an index artifact
may provide a `.retriever()` method that returns a transformer that searches the index.
You can use `pta.Artifact.load('path/to/artifact')` to load an artifact. The function automatically
identfies the artifact's type and initializes it:
```python
index = pta.Artifact.load('path/to/msmarco-passage.pisa')
# PisaIndex('path/to/msmarco-passage.pisa')
index.bm25() # returns a BM25 PisaRetriever for the index
```
You can also save and load artifacts from HuggingFace Hub:
```python
# uploads the artifact to HuggingFace Hub
index.to_hf('username/repo')
# loads an artifact from HuggingFace Hub
pta.Artifact.from_hf('username/repo')
```
## pta.io
Available in: `pyterrier-alpha >= 0.2.0`
`pta.io` includes extra input/output utilities:
**Files/downloads/streaming:**
- `pta.io.open_or_download_stream(path_or_url: str)` Returns a stream of `path_or_url`, depending on whether it is a URL
or local file path.
- `pta.io.download_stream(url: str)` Returns a stream of `url`.
- `pta.io.download(url: str, path: str)` Downloads `url` to `path`.
- `pta.io.finalized_directory(path: str)` A context manager that returns a temporary directory. The directory is moved to `path`
on successful completion of the context manager, or deleted if an exception is raised during executation.
- `pta.io.finalized_open(path: str)` A context manager that returns a temporary file. The file is moved to `path` on successful
completion of the context manager, or deleted if an exception is raised during executation.
**Hashing/security:**
- `pta.io.path_is_under_base(path: str, base: str) -> bool` tests whether `path` refers to a path under `base`. This
is helpful to avoid tarbombing.
- `pta.io.HashWriter(writer: io.IOBase)` is a wrapper around a `io.IOBase` that keeps track of the hash (default SHA256)
as it is being written to (accessible as the `.hash` property).
- `pta.io.HashReader(reader: io.IOBase, expected: Optional[str])` is a wrapper around a `io.IOBase` that keeps track of
the hash (default SHA256) as it is being read from (accessible as the `.hash` property or the `.hexdigest()` method).
If `expected` is provided, an error is thrown when the reader is closed if the `.hexdigest()` does not match this value.
- `pta.io.TqdmReader(reader: io.IOBase, total: int, desc: str)` is a wrapper around a `io.IOBase` that shows a tqdm
progress bar as the reader is being read.
**Misc:**
- `pta.io.byte_count_to_human_readable(byte_count: float) -> str` returns a human-readable version of a
byte count, e.g., 4547 bytes -> "4.4 KB". Supports units from B to TB
- `pta.io.entry_points(group: str) -> Tuple[EntryPoint, ...]` is an implementation of
[`importlib.metadata.entry_points(group)`](https://docs.python.org/3/library/importlib.metadata.html#entry-points)
that supports python<=3.12.
- ~~`pta.io.pyterrier_home() -> str` returns the PyTerrier home directory.~~ **Moved to PyTerrier Core in 0.11.0**
## pta.RBO
Available in: `pyterrier-alpha >= 0.3.0`
`pta.RBO` provides a `ir_measures`-compatible implementation of [Rank Biased Overlap (RBO)](https://dl.acm.org/doi/10.1145/1852102.1852106).
RBO is a rank-baised correlation measure. In other words, it measures how similar two ranked lists are with one another, giving
higher priority to the top of the list. The priority is adjusted using the `p` parameter, as discussed below. Note that RBO
ignores the qrels; it only compares the current ranking with another one.
`pta.RBO` takes two parameters:
- `other` (DataFrame): The ranked list that you want to compare against
- `p` (float): the "persistence" parameter in the range of (0, 1), which adjusts how much priority is given to the top of
the list. Common values include 0.9 (gives the most priority to top 10 ranks) and 0.99 (top 100).
You can use `pta.RBO` in `pt.Experiment` as follows:
```python
import pyterrier as pt
import pyterrier_alpha as pta
from ir_measures import *
pt.init()
# define your pipeline(s), dataset, etc.
...
# get the "other" list to compare against e.g.,
other = baseline(dataset.get_topics())
# or
other = pt.io.read_results('some_result_file.res')
pt.Experiment(
[pipeline],
dataset.get_topics(),
dataset.get_qrels(),
[nDCG@10, pta.RBO(other, p=0.9), pta.RBO(other, p=0.99)]
)
```
## pta.transformer_repr
Available in: `pyterrier-alpha >= 0.4.0`
`pta.transformer_repr` provides a drop-in repr implementation for a Transformer's `__repr__`, assuming it adheres to
a few basic requirements. Namely, it should be able to be constructed using the fields it has of the same name and not
take `*args` or `**kwargs` in the constructor. For example:
```python
class MyTransformer(pt.Transformer):
def __init__(self, a, b=5, *, other=None):
self.a = a
self.b = b
self.other = other
def transform(self, inp):
...
__repr__ = pta.transformer_repr
repr(MyTransformer("hello"))
# MyTransformer("hello")
repr(MyTransformer("hello", "world"))
# MyTransformer("hello", "world")
repr(MyTransformer("hello", other=5))
# MyTransformer("hello", other=5)
```
## pta.utils.peekable
Available in: `pyterrier-alpha >= 0.6.0`
`pta.utils.peekable` returns an iterator that you can peek ahead into without advancing it.
It's most commonly used with `pta.validate.columns_iter()` to peek into the first element for validation.
```python
import pyterrier_alpha as pta
my_iterator = [{'docno': 'doc1'}, {'docno': 'doc2'}, {'docno': 'doc3'}]
my_iterator = pta.utils.peekable(my_iterator)
my_iterator.peek()
{'docno': 'doc1'}
my_iterator.peek()
{'docno': 'doc1'}
next(my_iterator)
{'docno': 'doc1'}
next(my_iterator)
{'docno': 'doc2'}
my_iterator.peek()
{'docno': 'doc3'}
```
Raw data
{
"_id": null,
"home_page": null,
"name": "pyterrier-alpha",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.6",
"maintainer_email": "Sean MacAvaney <sean.macavaney@glasgow.ac.uk>",
"keywords": null,
"author": null,
"author_email": "Sean MacAvaney <sean.macavaney@glasgow.ac.uk>",
"download_url": "https://files.pythonhosted.org/packages/6d/03/f0a4581afc1f62559ca21acfd9bbfced79e89d3ae144b1069f06d04c0a39/pyterrier_alpha-0.12.0.tar.gz",
"platform": null,
"description": "# pyterrier-alpha\n\nAlpha channel of features for [PyTerrier](https://github.com/terrier-org/pyterrier).\n\nFeatures in ths package are under development and intend to be merged with the main package or split into a separate package when stable.\n\n<details>\n\n<summary>Table of Contents</summary>\n\n - [Getting Started](#gettingstarted)\n - [`pta.validate`](#ptavalidate)\n - [`pta.DataFrameBuilder`](#ptadataframebuilder)\n - [`pta.Artifact`](#ptaartifact)\n - [`pta.io`](#ptaio)\n\n</details>\n\n## Getting Started\n\n```bash\npip install pyterrier-alpha\n```\n\nImport `pyterrier_alpha` alongside `pyterrier`:\n\n```python\nimport pyterrier as pt\nimport pyterrier_alpha as pta\n```\n\n## pta.validate\n\nIt's a good idea to check the input to a transformer to make sure its compatible before you start using it.\n`pta.validate` provides functions for this.\n\n```python\ndef MyTransformer(pt.Transformer):\n def transform(self, inp: pd.DataFrame):\n # e.g., expects a query frame with query_vec\n pta.validate.query_frame(inp, extra_columns=['query_vec'])\n # raises an error if the specification doesn't match\n```\n\n| Function | Must have column(s) | Must NOT have column(s) |\n|----------|---------------------|-------------------------|\n| `pta.validate.query_frame(inp, extra_columns=...)` | qid + `extra_columns` | docno |\n| `pta.validate.document_frame(inp, extra_columns=...)` | docno + `extra_columns` | qid |\n| `pta.validate.result_frame(inp, extra_columns=...)` | qid + docno + `extra_columns` | |\n| `pta.validate.columns(inp, includes=..., excludes=...)` | `includes` | `excludes` |\n\n\n**Iterable validation**\n\nAvailable in: `pyterrier-alpha >= 0.6.0`\n\nFor indexing pipelines that accept iterators, it checks the fields of the first element. You need\nto first wrap `inp` in `pta.utils.peekable()` for this to work.\n\n```python\nimport pyterrier_alpha as pta\nmy_iterator = [{'docno': 'doc1'}, {'docno': 'doc2'}, {'docno': 'doc3'}]\nmy_iterator = pta.utils.peekable(my_iterator)\npta.validate.columns_iter(my_iterator, includes=['docno']) # passes\npta.validate.columns_iter(my_iterator, includes=['docno', 'toks']) # raises error\n```\n\n<details>\n\n<summary>Advanced Usage (click to expand)</summary>\n\nSometimes a transformer has multiple acceptable input specifications, e.g., if\nit can act as either a retriever (with a query input) or re-ranker (with a result input).\nIn this case, you can specify multiple possible configurations in a `with pta.validate.any(inpt) as v:` block:\n\n```python\ndef MyTransformer(pt.Transformer):\n def transform(self, inp: pd.DataFrame):\n # e.g., expects a query frame with query_vec\n with pta.validate.any(inp) as v:\n v.query_frame(extra_columns=['query'], mode='retrieve')\n v.result_frame(extra_columns=['query', 'text'], mode='rerank')\n # raises an error if ALL specifications do not match\n # v.mode is set to the FIRST specification that matches\n if v.mode == 'retrieve':\n ...\n if v.mode == 'rerank':\n ...\n```\n\n</details>\n\n## pta.DataFrameBuilder\n\nA common pattern in `Transformer` implementation builds up an intermediate representation of the output DataFrame,\nbut this can be a bit clunky, as shown below:\n\n```python\ndef MyTransformer(pt.Transformer):\n def transform(self, inp: pd.DataFrame):\n result = {\n 'qid': [],\n 'query': [],\n 'docno': [],\n 'score': [],\n }\n for qid, query in zip(inp['qid'], inp['query']):\n docnos, scores = self.some_function(qid, query)\n result['qid'].append([qid] * len(docnos))\n result['query'].append([query] * len(docnos))\n result['docno'].append(docnos)\n result['score'].append(scores)\n result = pd.DataFrame({\n 'qid': np.concatenate(result['qid']),\n 'query': np.concatenate(result['query']),\n 'docno': np.concatenate(result['docno']),\n 'score': np.concatenate(result['score']),\n })\n return result\n```\n\n`pta.DataFrameBuilder` simplifies the process of building a DataFrame by removing lots of the boilerplate.\nIt also automatically handles various types and ensures that all columns end up with the same length.\nThe above example can be rewritten with `pta.DataFrameBuilder` as follows:\n\n```python\ndef MyTransformer(pt.Transformer):\n def transform(self, inp: pd.DataFrame):\n result = pta.DataFrameBuilder(['qid', 'query', 'docno', 'score'])\n for qid, query in zip(inp['qid'], inp['query']):\n docnos, scores = self.some_function(qid, query)\n result.extend({\n 'qid': qid, # automatically repeats to the length of this batch\n 'query': query, # ditto\n 'docno': docnos,\n 'score': scores,\n })\n return result.to_df()\n```\n\n\n## pta.Artifact\n\nAvailable in: `pyterrier-alpha >= 0.2.0`\n\nAn artifact is a component stored on disk, such as an index.\n\nArtifacts usually act as factories for transformers that use them. For example, an index artifact\nmay provide a `.retriever()` method that returns a transformer that searches the index.\n\nYou can use `pta.Artifact.load('path/to/artifact')` to load an artifact. The function automatically\nidentfies the artifact's type and initializes it:\n\n```python\nindex = pta.Artifact.load('path/to/msmarco-passage.pisa')\n# PisaIndex('path/to/msmarco-passage.pisa')\nindex.bm25() # returns a BM25 PisaRetriever for the index\n```\n\nYou can also save and load artifacts from HuggingFace Hub:\n\n```python\n# uploads the artifact to HuggingFace Hub\nindex.to_hf('username/repo')\n\n# loads an artifact from HuggingFace Hub\npta.Artifact.from_hf('username/repo')\n```\n\n## pta.io\n\nAvailable in: `pyterrier-alpha >= 0.2.0`\n\n`pta.io` includes extra input/output utilities:\n\n**Files/downloads/streaming:**\n\n - `pta.io.open_or_download_stream(path_or_url: str)` Returns a stream of `path_or_url`, depending on whether it is a URL\n or local file path.\n - `pta.io.download_stream(url: str)` Returns a stream of `url`.\n - `pta.io.download(url: str, path: str)` Downloads `url` to `path`.\n - `pta.io.finalized_directory(path: str)` A context manager that returns a temporary directory. The directory is moved to `path`\n on successful completion of the context manager, or deleted if an exception is raised during executation.\n - `pta.io.finalized_open(path: str)` A context manager that returns a temporary file. The file is moved to `path` on successful\n completion of the context manager, or deleted if an exception is raised during executation.\n\n**Hashing/security:**\n\n - `pta.io.path_is_under_base(path: str, base: str) -> bool` tests whether `path` refers to a path under `base`. This\n is helpful to avoid tarbombing.\n - `pta.io.HashWriter(writer: io.IOBase)` is a wrapper around a `io.IOBase` that keeps track of the hash (default SHA256)\n as it is being written to (accessible as the `.hash` property).\n - `pta.io.HashReader(reader: io.IOBase, expected: Optional[str])` is a wrapper around a `io.IOBase` that keeps track of\n the hash (default SHA256) as it is being read from (accessible as the `.hash` property or the `.hexdigest()` method).\n If `expected` is provided, an error is thrown when the reader is closed if the `.hexdigest()` does not match this value.\n - `pta.io.TqdmReader(reader: io.IOBase, total: int, desc: str)` is a wrapper around a `io.IOBase` that shows a tqdm\n progress bar as the reader is being read.\n\n**Misc:**\n\n - `pta.io.byte_count_to_human_readable(byte_count: float) -> str` returns a human-readable version of a\n byte count, e.g., 4547 bytes -> \"4.4 KB\". Supports units from B to TB\n - `pta.io.entry_points(group: str) -> Tuple[EntryPoint, ...]` is an implementation of\n [`importlib.metadata.entry_points(group)`](https://docs.python.org/3/library/importlib.metadata.html#entry-points)\n that supports python<=3.12.\n - ~~`pta.io.pyterrier_home() -> str` returns the PyTerrier home directory.~~ **Moved to PyTerrier Core in 0.11.0**\n\n\n## pta.RBO\n\nAvailable in: `pyterrier-alpha >= 0.3.0`\n\n`pta.RBO` provides a `ir_measures`-compatible implementation of [Rank Biased Overlap (RBO)](https://dl.acm.org/doi/10.1145/1852102.1852106).\nRBO is a rank-baised correlation measure. In other words, it measures how similar two ranked lists are with one another, giving\nhigher priority to the top of the list. The priority is adjusted using the `p` parameter, as discussed below. Note that RBO\nignores the qrels; it only compares the current ranking with another one.\n\n`pta.RBO` takes two parameters:\n - `other` (DataFrame): The ranked list that you want to compare against\n - `p` (float): the \"persistence\" parameter in the range of (0, 1), which adjusts how much priority is given to the top of\n the list. Common values include 0.9 (gives the most priority to top 10 ranks) and 0.99 (top 100).\n\nYou can use `pta.RBO` in `pt.Experiment` as follows:\n\n```python\nimport pyterrier as pt\nimport pyterrier_alpha as pta\nfrom ir_measures import *\npt.init()\n\n# define your pipeline(s), dataset, etc.\n... \n\n# get the \"other\" list to compare against e.g.,\nother = baseline(dataset.get_topics())\n# or\nother = pt.io.read_results('some_result_file.res')\n\npt.Experiment(\n [pipeline],\n dataset.get_topics(),\n dataset.get_qrels(),\n [nDCG@10, pta.RBO(other, p=0.9), pta.RBO(other, p=0.99)]\n)\n```\n\n## pta.transformer_repr\n\nAvailable in: `pyterrier-alpha >= 0.4.0`\n\n`pta.transformer_repr` provides a drop-in repr implementation for a Transformer's `__repr__`, assuming it adheres to\na few basic requirements. Namely, it should be able to be constructed using the fields it has of the same name and not\ntake `*args` or `**kwargs` in the constructor. For example:\n\n```python\nclass MyTransformer(pt.Transformer):\n def __init__(self, a, b=5, *, other=None):\n self.a = a\n self.b = b\n self.other = other\n\n def transform(self, inp):\n ...\n\n __repr__ = pta.transformer_repr\n\nrepr(MyTransformer(\"hello\"))\n# MyTransformer(\"hello\")\nrepr(MyTransformer(\"hello\", \"world\"))\n# MyTransformer(\"hello\", \"world\")\nrepr(MyTransformer(\"hello\", other=5))\n# MyTransformer(\"hello\", other=5)\n```\n\n## pta.utils.peekable\n\nAvailable in: `pyterrier-alpha >= 0.6.0`\n\n`pta.utils.peekable` returns an iterator that you can peek ahead into without advancing it.\n\nIt's most commonly used with `pta.validate.columns_iter()` to peek into the first element for validation.\n\n```python\nimport pyterrier_alpha as pta\nmy_iterator = [{'docno': 'doc1'}, {'docno': 'doc2'}, {'docno': 'doc3'}]\nmy_iterator = pta.utils.peekable(my_iterator)\nmy_iterator.peek()\n{'docno': 'doc1'}\nmy_iterator.peek()\n{'docno': 'doc1'}\nnext(my_iterator)\n{'docno': 'doc1'}\nnext(my_iterator)\n{'docno': 'doc2'}\nmy_iterator.peek()\n{'docno': 'doc3'}\n```\n",
"bugtrack_url": null,
"license": null,
"summary": "Alpha channel of features for PyTerrier",
"version": "0.12.0",
"project_urls": {
"Bug Tracker": "https://github.com/seanmacavaney/pyterrier-alpha/issues",
"Repository": "https://github.com/seanmacavaney/pyterrier-alpha"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "01e8ae5bb60df577e1b155f79c2a8deb6cbbf814b4ec8ed39000336b8ee9afe0",
"md5": "732abf3f64bdbcb07dcf0132265633a4",
"sha256": "6d1ad675de04063bf96075a7da5e24cad47d55282099931fee52002d03cd1383"
},
"downloads": -1,
"filename": "pyterrier_alpha-0.12.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "732abf3f64bdbcb07dcf0132265633a4",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6",
"size": 31167,
"upload_time": "2024-12-11T04:28:55",
"upload_time_iso_8601": "2024-12-11T04:28:55.226546Z",
"url": "https://files.pythonhosted.org/packages/01/e8/ae5bb60df577e1b155f79c2a8deb6cbbf814b4ec8ed39000336b8ee9afe0/pyterrier_alpha-0.12.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "6d03f0a4581afc1f62559ca21acfd9bbfced79e89d3ae144b1069f06d04c0a39",
"md5": "c489e128b5a37a467484a108f0b4e6e7",
"sha256": "c43cd581f6efaa7e69779e4b8d4d15a1a39eb6090810eaec3ddeeb8b017712e1"
},
"downloads": -1,
"filename": "pyterrier_alpha-0.12.0.tar.gz",
"has_sig": false,
"md5_digest": "c489e128b5a37a467484a108f0b4e6e7",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 29352,
"upload_time": "2024-12-11T04:28:56",
"upload_time_iso_8601": "2024-12-11T04:28:56.624857Z",
"url": "https://files.pythonhosted.org/packages/6d/03/f0a4581afc1f62559ca21acfd9bbfced79e89d3ae144b1069f06d04c0a39/pyterrier_alpha-0.12.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-12-11 04:28:56",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "seanmacavaney",
"github_project": "pyterrier-alpha",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [
{
"name": "python-terrier",
"specs": []
},
{
"name": "colaburl",
"specs": []
}
],
"lcname": "pyterrier-alpha"
}