pyrox-client 0.0.1__tar.gz → 0.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyrox_client-0.0.1 → pyrox_client-0.0.2}/PKG-INFO +7 -5
- pyrox_client-0.0.2/pyproject.toml +36 -0
- pyrox_client-0.0.2/src/pyrox/__init__.py +5 -0
- pyrox_client-0.0.2/src/pyrox/config.py +31 -0
- pyrox_client-0.0.2/src/pyrox/core.py +102 -0
- pyrox_client-0.0.2/src/pyrox/errors.py +60 -0
- pyrox_client-0.0.2/src/pyrox/manifest.py +174 -0
- pyrox_client-0.0.1/.idea/.gitignore +0 -3
- pyrox_client-0.0.1/.idea/.name +0 -1
- pyrox_client-0.0.1/.idea/inspectionProfiles/Project_Default.xml +0 -392
- pyrox_client-0.0.1/.idea/inspectionProfiles/profiles_settings.xml +0 -6
- pyrox_client-0.0.1/.idea/misc.xml +0 -4
- pyrox_client-0.0.1/.idea/modules.xml +0 -8
- pyrox_client-0.0.1/.idea/pyrox-client.iml +0 -8
- pyrox_client-0.0.1/.idea/workspace.xml +0 -191
- pyrox_client-0.0.1/main.py +0 -16
- pyrox_client-0.0.1/pyproject.toml +0 -23
- pyrox_client-0.0.1/src/dist/.gitignore +0 -1
- pyrox_client-0.0.1/src/pyrox/__init__.py +0 -1
- pyrox_client-0.0.1/src/pyrox/client.py +0 -49
- {pyrox_client-0.0.1 → pyrox_client-0.0.2}/README.md +0 -0
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyrox-client
|
|
3
|
-
Version: 0.0.
|
|
4
|
-
Summary: HYROX race data client
|
|
5
|
-
Project-URL: homepage, https://github.com/<you>/pyrox
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: HYROX race data client – retrieve full race results via Python
|
|
6
5
|
Author: Vlad Matei
|
|
7
6
|
License: MIT
|
|
8
7
|
Requires-Python: >=3.9
|
|
9
|
-
Requires-Dist: fastparquet>=
|
|
10
|
-
Requires-Dist:
|
|
8
|
+
Requires-Dist: fastparquet>=2024.5.0
|
|
9
|
+
Requires-Dist: fsspec>=2024.2.0
|
|
10
|
+
Requires-Dist: pandas>=2.2
|
|
11
|
+
Requires-Dist: platformdirs>=4.2.0
|
|
11
12
|
Requires-Dist: requests>=2.31
|
|
13
|
+
Requires-Dist: s3fs>=2024.2.0
|
|
12
14
|
Provides-Extra: duckdb
|
|
13
15
|
Requires-Dist: duckdb>=1.0.0; extra == 'duckdb'
|
|
14
16
|
Description-Content-Type: text/markdown
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.20"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pyrox-client"
|
|
7
|
+
version = "0.0.2"
|
|
8
|
+
description = "HYROX race data client – retrieve full race results via Python"
|
|
9
|
+
authors = [{ name = "Vlad Matei" }]
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
requires-python = ">=3.9"
|
|
13
|
+
dependencies = [
|
|
14
|
+
"pandas>=2.2",
|
|
15
|
+
"fastparquet>=2024.5.0",
|
|
16
|
+
"fsspec>=2024.2.0",
|
|
17
|
+
"s3fs>=2024.2.0",
|
|
18
|
+
"requests>=2.31",
|
|
19
|
+
"platformdirs>=4.2.0",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[project.optional-dependencies]
|
|
23
|
+
duckdb = ["duckdb>=1.0.0"]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# You’re using a src/ layout. This tells Hatch which package to build.
|
|
27
|
+
[tool.hatch.build.targets.wheel]
|
|
28
|
+
packages = ["src/pyrox"]
|
|
29
|
+
|
|
30
|
+
# Ensure sdist includes your source + docs
|
|
31
|
+
[tool.hatch.build.targets.sdist]
|
|
32
|
+
include = [
|
|
33
|
+
"src/pyrox",
|
|
34
|
+
"README.md",
|
|
35
|
+
"pyproject.toml"
|
|
36
|
+
]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from platformdirs import user_cache_dir
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
APP_NAME = "pyrox"
|
|
7
|
+
APP_AUTHOR = "pyrox"
|
|
8
|
+
|
|
9
|
+
_DEFAULT_BUCKET = os.getenv("PYROX_BUCKET", "s3://hyrox-results")
|
|
10
|
+
_DEFAULT_MANIFEST = os.getenv("PYROX_MANIFEST_PATH", "processed/manifest/latest.csv")
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class PyroxConfig:
|
|
14
|
+
bucket: str = _DEFAULT_BUCKET
|
|
15
|
+
manifest_path: str = _DEFAULT_MANIFEST
|
|
16
|
+
cache_dir:Path = Path(user_cache_dir(APP_NAME, APP_AUTHOR))
|
|
17
|
+
|
|
18
|
+
_config = PyroxConfig()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def set_bucket(uri:str) -> None:
|
|
22
|
+
_config.bucket = uri.rsplit("/")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def set_manifest_path(path: str) -> None:
|
|
26
|
+
_config.manifest_path = path
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def get_config() -> PyroxConfig:
|
|
30
|
+
_config.cache_dir.mkdir(parents=True, exist_ok=True)
|
|
31
|
+
return _config
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
from .manifest import load_manifest, _s3_open # re-use your manifest loader + fsspec opener
|
|
8
|
+
from .config import get_config
|
|
9
|
+
from .errors import RaceNotFound, ParquetReadError
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def list_races(season: int | None = None) -> pd.DataFrame:
|
|
13
|
+
"""
|
|
14
|
+
Return available (season, location) pairs from the manifest.
|
|
15
|
+
"""
|
|
16
|
+
df = load_manifest(refresh=True)
|
|
17
|
+
if season is not None:
|
|
18
|
+
try:
|
|
19
|
+
df = df[df["season"] == int(season)]
|
|
20
|
+
except ValueError as e:
|
|
21
|
+
raise (ValueError(f"Input {season} is not of expected type. Please make sure you request an integer."))
|
|
22
|
+
return (
|
|
23
|
+
df[["season", "location"]]
|
|
24
|
+
.drop_duplicates()
|
|
25
|
+
.sort_values(["season", "location"])
|
|
26
|
+
.reset_index(drop=True)
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _local_parquet_cache_path(s3_key: str) -> Path:
|
|
31
|
+
"""
|
|
32
|
+
Map an S3 key to a deterministic local cache path under ~/.cache/pyrox/parquet/.
|
|
33
|
+
"""
|
|
34
|
+
cfg = get_config()
|
|
35
|
+
p = cfg.cache_dir / "parquet" / s3_key.replace("/", "__")
|
|
36
|
+
p.parent.mkdir(parents=True, exist_ok=True)
|
|
37
|
+
return p
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _read_parquet_from_s3(s3_uri: str) -> pd.DataFrame:
|
|
41
|
+
"""
|
|
42
|
+
Download the parquet bytes anonymously from S3 and read with fastparquet.
|
|
43
|
+
"""
|
|
44
|
+
try:
|
|
45
|
+
with _s3_open(s3_uri, "rb", anon=True) as f:
|
|
46
|
+
data = f.read()
|
|
47
|
+
return pd.read_parquet(io.BytesIO(data), engine="fastparquet")
|
|
48
|
+
except Exception as e:
|
|
49
|
+
raise ParquetReadError(f"Failed to read parquet from {s3_uri}: {e}")
|
|
50
|
+
# core.py
|
|
51
|
+
def _to_s3_uri(bucket: str, key: str) -> str:
|
|
52
|
+
"""Join bucket + key safely. If key is already a full s3:// URI, use it as-is."""
|
|
53
|
+
key = key.strip()
|
|
54
|
+
if key.startswith("s3://"):
|
|
55
|
+
return key
|
|
56
|
+
# allow bucket to be "s3://bucket" or just "bucket"
|
|
57
|
+
if not bucket.startswith("s3://"):
|
|
58
|
+
bucket = f"s3://{bucket}"
|
|
59
|
+
return f"{bucket.rstrip('/')}/{key.lstrip('/')}"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_race(*, season: int, location: str) -> pd.DataFrame:
|
|
63
|
+
"""
|
|
64
|
+
Resolve (season, location) -> s3_key via the manifest, then return the race DataFrame.
|
|
65
|
+
|
|
66
|
+
Uses a simple local file cache. If the cached parquet fails to read,
|
|
67
|
+
it is discarded and we re-fetch from S3.
|
|
68
|
+
"""
|
|
69
|
+
manifest = load_manifest(refresh=True)
|
|
70
|
+
|
|
71
|
+
# case-insensitive match on location
|
|
72
|
+
row = manifest[
|
|
73
|
+
(manifest["season"] == int(season)) &
|
|
74
|
+
(manifest["location"].str.casefold() == location.casefold())
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
if row.empty:
|
|
78
|
+
raise RaceNotFound(f"No race found for season={season}, location='{location}'. "
|
|
79
|
+
f"Try: pyrox.list_races({season})")
|
|
80
|
+
|
|
81
|
+
s3_key = row.iloc[0]["path"]
|
|
82
|
+
cfg = get_config()
|
|
83
|
+
s3_uri = _to_s3_uri(cfg.bucket, s3_key)
|
|
84
|
+
|
|
85
|
+
# check local cache first
|
|
86
|
+
local_path = _local_parquet_cache_path(s3_key)
|
|
87
|
+
if local_path.exists():
|
|
88
|
+
try:
|
|
89
|
+
return pd.read_parquet(local_path, engine="fastparquet")
|
|
90
|
+
except Exception:
|
|
91
|
+
local_path.unlink(missing_ok=True) # bad cache → remove and refetch
|
|
92
|
+
|
|
93
|
+
# fetch from S3 and cache
|
|
94
|
+
df = _read_parquet_from_s3(s3_uri)
|
|
95
|
+
try:
|
|
96
|
+
df.to_parquet(local_path, index=False, engine="fastparquet")
|
|
97
|
+
except Exception:
|
|
98
|
+
# cache failures should not fail the API
|
|
99
|
+
pass
|
|
100
|
+
return df
|
|
101
|
+
|
|
102
|
+
breakheere = 0
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Custom exceptions for the pyrox client.
|
|
3
|
+
|
|
4
|
+
Expose a small, predictable hierarchy so users can:
|
|
5
|
+
- catch a broad PyroxError for any client-side issue, or
|
|
6
|
+
- catch specific errors for targeted handling (e.g., missing race).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"PyroxError",
|
|
14
|
+
"ConfigError",
|
|
15
|
+
"ManifestUnavailable",
|
|
16
|
+
"RaceNotFound",
|
|
17
|
+
"ParquetReadError",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class PyroxError(Exception):
|
|
22
|
+
"""Base class for all pyrox-specific errors."""
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ConfigError(PyroxError):
|
|
27
|
+
"""
|
|
28
|
+
Raised when the client configuration is invalid or incomplete.
|
|
29
|
+
Example: bucket URI not set or malformed.
|
|
30
|
+
"""
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ManifestUnavailable(PyroxError):
|
|
35
|
+
"""
|
|
36
|
+
Raised when the manifest cannot be retrieved or parsed.
|
|
37
|
+
|
|
38
|
+
Typical reasons:
|
|
39
|
+
- Network/S3 access problems
|
|
40
|
+
- File missing or not public
|
|
41
|
+
- CSV missing required columns (season, location, s3_key)
|
|
42
|
+
"""
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class RaceNotFound(PyroxError, LookupError):
|
|
47
|
+
"""
|
|
48
|
+
Raised when (season, location) is not present in the manifest.
|
|
49
|
+
|
|
50
|
+
Inherit from LookupError to feel natural in 'lookup' code paths.
|
|
51
|
+
"""
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class ParquetReadError(PyroxError, IOError):
|
|
56
|
+
"""
|
|
57
|
+
Raised when the parquet for a race cannot be read (S3 read failure,
|
|
58
|
+
corrupted object, incompatible parquet version, etc.).
|
|
59
|
+
"""
|
|
60
|
+
pass
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
from typing import Optional, Tuple
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import fsspec
|
|
8
|
+
import pandas as pd
|
|
9
|
+
|
|
10
|
+
from .config import get_config
|
|
11
|
+
from .errors import ManifestUnavailable
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _s3_open(path: str, mode: str = "rb", anon: bool = True):
|
|
15
|
+
"""
|
|
16
|
+
Unified opener for S3 (via fsspec/s3fs).
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
path : str
|
|
21
|
+
Full fsspec path, e.g. "s3://my-bucket/processed/manifest/latest.csv"
|
|
22
|
+
mode : str
|
|
23
|
+
File mode, usually "rb" for binary reads.
|
|
24
|
+
anon : bool
|
|
25
|
+
True => anonymous/public read (no AWS creds required).
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
contextmanager
|
|
30
|
+
Use with 'with _s3_open(...) as f: data = f.read()'
|
|
31
|
+
"""
|
|
32
|
+
# s3fs accepts the 'anon' kw to do public/unsigned requests
|
|
33
|
+
return fsspec.open(path, mode=mode, **({"anon": True} if anon else {}))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _cache_paths(name: str) -> Tuple[Path, Path]:
|
|
37
|
+
"""
|
|
38
|
+
Compute cache locations for the manifest CSV and its ETag sidecar.
|
|
39
|
+
|
|
40
|
+
We cache:
|
|
41
|
+
- the CSV bytes as ~/.cache/pyrox/manifest.latest.csv
|
|
42
|
+
- the ETag string as ~/.cache/pyrox/manifest.latest.csv.etag
|
|
43
|
+
"""
|
|
44
|
+
cfg = get_config()
|
|
45
|
+
cache_file = cfg.cache_dir / name
|
|
46
|
+
meta_file = cfg.cache_dir / f"{name}.etag"
|
|
47
|
+
return cache_file, meta_file
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _read_etag(meta_file: Path) -> Optional[str]:
|
|
51
|
+
"""Read the cached ETag string (if any)."""
|
|
52
|
+
if meta_file.exists():
|
|
53
|
+
try:
|
|
54
|
+
etag = meta_file.read_text().strip()
|
|
55
|
+
return etag or None
|
|
56
|
+
except Exception:
|
|
57
|
+
return None
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _head_s3(path: str) -> dict:
|
|
62
|
+
"""
|
|
63
|
+
Fetch object metadata from S3 (cheap 'HEAD').
|
|
64
|
+
|
|
65
|
+
Returns a dict similar to:
|
|
66
|
+
{
|
|
67
|
+
"ETag": "\"5d41402abc...\"",
|
|
68
|
+
"LastModified": datetime,
|
|
69
|
+
"Size": int,
|
|
70
|
+
...
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
Notes
|
|
74
|
+
-----
|
|
75
|
+
- We obtain the filesystem object from an open file handle (fo.fs),
|
|
76
|
+
then call fs.info(path).
|
|
77
|
+
- Not all gateways populate all keys—but ETag is common for S3.
|
|
78
|
+
"""
|
|
79
|
+
# Open briefly to access underlying filesystem handle
|
|
80
|
+
with fsspec.open(path, mode="rb", anon=True) as fo:
|
|
81
|
+
fs = fo.fs # type: ignore[attr-defined]
|
|
82
|
+
return fs.info(path)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def load_manifest(refresh: bool = True) -> pd.DataFrame:
|
|
86
|
+
"""
|
|
87
|
+
Load the manifest CSV as a pandas DataFrame with required columns:
|
|
88
|
+
['season', 'location', 's3_key']
|
|
89
|
+
|
|
90
|
+
Caching strategy
|
|
91
|
+
----------------
|
|
92
|
+
- Store the last-downloaded manifest under ~/.cache/pyrox.
|
|
93
|
+
- On each call (when refresh=True), perform a HEAD request to get the
|
|
94
|
+
current ETag. If it matches the cached ETag -> use cached CSV.
|
|
95
|
+
Otherwise, re-download and update the cache.
|
|
96
|
+
|
|
97
|
+
Parameters
|
|
98
|
+
----------
|
|
99
|
+
refresh : bool
|
|
100
|
+
If False, skip HEAD check and use cached file if present.
|
|
101
|
+
If True (default), validate with ETag before deciding.
|
|
102
|
+
|
|
103
|
+
Raises
|
|
104
|
+
------
|
|
105
|
+
ManifestUnavailable
|
|
106
|
+
If we cannot fetch or parse the manifest, and there is no usable cache.
|
|
107
|
+
|
|
108
|
+
Returns
|
|
109
|
+
-------
|
|
110
|
+
pd.DataFrame
|
|
111
|
+
Normalized manifest DataFrame.
|
|
112
|
+
"""
|
|
113
|
+
cfg = get_config()
|
|
114
|
+
s3_manifest_uri = f"{cfg.bucket}/{cfg.manifest_path}"
|
|
115
|
+
cache_file, meta_file = _cache_paths("manifest.latest.csv")
|
|
116
|
+
|
|
117
|
+
# 1) Try to fetch latest ETag (safe to fail; we'll fall back).
|
|
118
|
+
current_etag: Optional[str] = None
|
|
119
|
+
if refresh:
|
|
120
|
+
try:
|
|
121
|
+
info = _head_s3(s3_manifest_uri)
|
|
122
|
+
# Some backends wrap ETag in quotes; we keep it as-is because
|
|
123
|
+
# we compare exact strings on both sides.
|
|
124
|
+
current_etag = info.get("ETag")
|
|
125
|
+
except Exception:
|
|
126
|
+
# HEAD can fail (e.g., transient network); we'll fall back to cache or GET.
|
|
127
|
+
current_etag = None
|
|
128
|
+
|
|
129
|
+
# 2) If we have a cached file and either:
|
|
130
|
+
# - HEAD failed (no current_etag), or
|
|
131
|
+
# - ETag matches the cached one,
|
|
132
|
+
# then load cached CSV immediately.
|
|
133
|
+
cached_etag = _read_etag(meta_file)
|
|
134
|
+
if cache_file.exists() and (current_etag is None or cached_etag == current_etag):
|
|
135
|
+
try:
|
|
136
|
+
return pd.read_csv(cache_file)
|
|
137
|
+
except Exception:
|
|
138
|
+
# Corrupted cache? Continue to re-download below.
|
|
139
|
+
pass
|
|
140
|
+
|
|
141
|
+
# 3) Re-download from S3 and update cache.
|
|
142
|
+
try:
|
|
143
|
+
with _s3_open(s3_manifest_uri, "rb", anon=True) as f:
|
|
144
|
+
data = f.read()
|
|
145
|
+
|
|
146
|
+
# Parse CSV from bytes buffer
|
|
147
|
+
df = pd.read_csv(io.BytesIO(data))
|
|
148
|
+
|
|
149
|
+
# Persist cache on success
|
|
150
|
+
cache_file.write_bytes(data)
|
|
151
|
+
if current_etag:
|
|
152
|
+
meta_file.write_text(current_etag)
|
|
153
|
+
|
|
154
|
+
# Basic schema checks
|
|
155
|
+
for col in ("season", "location", "s3_key"):
|
|
156
|
+
if col not in df.columns:
|
|
157
|
+
raise ManifestUnavailable(f"Manifest missing required column: {col}")
|
|
158
|
+
|
|
159
|
+
# Normalize dtypes; keeps downstream filters predictable
|
|
160
|
+
df["season"] = df["season"].astype(int)
|
|
161
|
+
df["location"] = df["location"].astype(str)
|
|
162
|
+
df["s3_key"] = df["s3_key"].astype(str)
|
|
163
|
+
|
|
164
|
+
return df
|
|
165
|
+
|
|
166
|
+
except Exception as e:
|
|
167
|
+
# 4) If network failed, try to limp with the existing cache (even if ETag mismatch).
|
|
168
|
+
if cache_file.exists():
|
|
169
|
+
try:
|
|
170
|
+
return pd.read_csv(cache_file)
|
|
171
|
+
except Exception:
|
|
172
|
+
pass
|
|
173
|
+
# No working cache → bail with a clear error
|
|
174
|
+
raise ManifestUnavailable(f"Could not load manifest from {s3_manifest_uri}: {e}")
|
pyrox_client-0.0.1/.idea/.name
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
pyrox-client
|
|
@@ -1,392 +0,0 @@
|
|
|
1
|
-
<component name="InspectionProjectProfileManager">
|
|
2
|
-
<profile version="1.0">
|
|
3
|
-
<option name="myName" value="Project Default" />
|
|
4
|
-
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
|
5
|
-
<option name="ignoredPackages">
|
|
6
|
-
<value>
|
|
7
|
-
<list size="1">
|
|
8
|
-
<item index="0" class="java.lang.String" itemvalue="lxml" />
|
|
9
|
-
</list>
|
|
10
|
-
</value>
|
|
11
|
-
</option>
|
|
12
|
-
</inspection_tool>
|
|
13
|
-
<inspection_tool class="PyPep8Inspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
|
14
|
-
<option name="ignoredErrors">
|
|
15
|
-
<list>
|
|
16
|
-
<option value="W29" />
|
|
17
|
-
<option value="E501" />
|
|
18
|
-
<option value="W29" />
|
|
19
|
-
<option value="E501" />
|
|
20
|
-
<option value="W29" />
|
|
21
|
-
<option value="E501" />
|
|
22
|
-
<option value="W29" />
|
|
23
|
-
<option value="E501" />
|
|
24
|
-
<option value="W29" />
|
|
25
|
-
<option value="E501" />
|
|
26
|
-
<option value="W29" />
|
|
27
|
-
<option value="E501" />
|
|
28
|
-
<option value="W29" />
|
|
29
|
-
<option value="E501" />
|
|
30
|
-
<option value="W29" />
|
|
31
|
-
<option value="E501" />
|
|
32
|
-
<option value="W29" />
|
|
33
|
-
<option value="E501" />
|
|
34
|
-
<option value="W29" />
|
|
35
|
-
<option value="E501" />
|
|
36
|
-
<option value="W29" />
|
|
37
|
-
<option value="E501" />
|
|
38
|
-
<option value="W29" />
|
|
39
|
-
<option value="E501" />
|
|
40
|
-
<option value="W29" />
|
|
41
|
-
<option value="E501" />
|
|
42
|
-
<option value="W29" />
|
|
43
|
-
<option value="E501" />
|
|
44
|
-
<option value="W29" />
|
|
45
|
-
<option value="E501" />
|
|
46
|
-
<option value="W29" />
|
|
47
|
-
<option value="E501" />
|
|
48
|
-
<option value="W29" />
|
|
49
|
-
<option value="E501" />
|
|
50
|
-
<option value="W29" />
|
|
51
|
-
<option value="E501" />
|
|
52
|
-
<option value="W29" />
|
|
53
|
-
<option value="E501" />
|
|
54
|
-
<option value="W29" />
|
|
55
|
-
<option value="E501" />
|
|
56
|
-
<option value="W29" />
|
|
57
|
-
<option value="E501" />
|
|
58
|
-
<option value="W29" />
|
|
59
|
-
<option value="E501" />
|
|
60
|
-
<option value="W29" />
|
|
61
|
-
<option value="E501" />
|
|
62
|
-
<option value="W29" />
|
|
63
|
-
<option value="E501" />
|
|
64
|
-
<option value="W29" />
|
|
65
|
-
<option value="E501" />
|
|
66
|
-
<option value="W29" />
|
|
67
|
-
<option value="E501" />
|
|
68
|
-
<option value="W29" />
|
|
69
|
-
<option value="E501" />
|
|
70
|
-
<option value="W29" />
|
|
71
|
-
<option value="E501" />
|
|
72
|
-
<option value="W29" />
|
|
73
|
-
<option value="E501" />
|
|
74
|
-
<option value="W29" />
|
|
75
|
-
<option value="E501" />
|
|
76
|
-
<option value="W29" />
|
|
77
|
-
<option value="E501" />
|
|
78
|
-
<option value="W29" />
|
|
79
|
-
<option value="E501" />
|
|
80
|
-
<option value="W29" />
|
|
81
|
-
<option value="E501" />
|
|
82
|
-
<option value="W29" />
|
|
83
|
-
<option value="E501" />
|
|
84
|
-
<option value="W29" />
|
|
85
|
-
<option value="E501" />
|
|
86
|
-
<option value="W29" />
|
|
87
|
-
<option value="E501" />
|
|
88
|
-
<option value="W29" />
|
|
89
|
-
<option value="E501" />
|
|
90
|
-
<option value="W29" />
|
|
91
|
-
<option value="E501" />
|
|
92
|
-
<option value="W29" />
|
|
93
|
-
<option value="E501" />
|
|
94
|
-
<option value="W29" />
|
|
95
|
-
<option value="E501" />
|
|
96
|
-
<option value="W29" />
|
|
97
|
-
<option value="E501" />
|
|
98
|
-
<option value="W29" />
|
|
99
|
-
<option value="E501" />
|
|
100
|
-
<option value="W29" />
|
|
101
|
-
<option value="E501" />
|
|
102
|
-
<option value="W29" />
|
|
103
|
-
<option value="E501" />
|
|
104
|
-
<option value="W29" />
|
|
105
|
-
<option value="E501" />
|
|
106
|
-
<option value="W29" />
|
|
107
|
-
<option value="E501" />
|
|
108
|
-
<option value="W29" />
|
|
109
|
-
<option value="E501" />
|
|
110
|
-
<option value="W29" />
|
|
111
|
-
<option value="E501" />
|
|
112
|
-
<option value="W29" />
|
|
113
|
-
<option value="E501" />
|
|
114
|
-
<option value="W29" />
|
|
115
|
-
<option value="E501" />
|
|
116
|
-
<option value="W29" />
|
|
117
|
-
<option value="E501" />
|
|
118
|
-
<option value="W29" />
|
|
119
|
-
<option value="E501" />
|
|
120
|
-
<option value="W29" />
|
|
121
|
-
<option value="E501" />
|
|
122
|
-
<option value="W29" />
|
|
123
|
-
<option value="E501" />
|
|
124
|
-
<option value="W29" />
|
|
125
|
-
<option value="E501" />
|
|
126
|
-
<option value="W29" />
|
|
127
|
-
<option value="E501" />
|
|
128
|
-
<option value="W29" />
|
|
129
|
-
<option value="E501" />
|
|
130
|
-
<option value="W29" />
|
|
131
|
-
<option value="E501" />
|
|
132
|
-
<option value="W29" />
|
|
133
|
-
<option value="E501" />
|
|
134
|
-
<option value="W29" />
|
|
135
|
-
<option value="E501" />
|
|
136
|
-
<option value="W29" />
|
|
137
|
-
<option value="E501" />
|
|
138
|
-
<option value="W29" />
|
|
139
|
-
<option value="E501" />
|
|
140
|
-
<option value="W29" />
|
|
141
|
-
<option value="E501" />
|
|
142
|
-
<option value="W29" />
|
|
143
|
-
<option value="E501" />
|
|
144
|
-
<option value="W29" />
|
|
145
|
-
<option value="E501" />
|
|
146
|
-
<option value="W29" />
|
|
147
|
-
<option value="E501" />
|
|
148
|
-
<option value="W29" />
|
|
149
|
-
<option value="E501" />
|
|
150
|
-
<option value="W29" />
|
|
151
|
-
<option value="E501" />
|
|
152
|
-
<option value="W29" />
|
|
153
|
-
<option value="E501" />
|
|
154
|
-
<option value="W29" />
|
|
155
|
-
<option value="E501" />
|
|
156
|
-
<option value="W29" />
|
|
157
|
-
<option value="E501" />
|
|
158
|
-
<option value="W29" />
|
|
159
|
-
<option value="E501" />
|
|
160
|
-
<option value="W29" />
|
|
161
|
-
<option value="E501" />
|
|
162
|
-
<option value="W29" />
|
|
163
|
-
<option value="E501" />
|
|
164
|
-
<option value="W29" />
|
|
165
|
-
<option value="E501" />
|
|
166
|
-
<option value="W29" />
|
|
167
|
-
<option value="E501" />
|
|
168
|
-
<option value="W29" />
|
|
169
|
-
<option value="E501" />
|
|
170
|
-
<option value="W29" />
|
|
171
|
-
<option value="E501" />
|
|
172
|
-
<option value="W29" />
|
|
173
|
-
<option value="E501" />
|
|
174
|
-
<option value="W29" />
|
|
175
|
-
<option value="E501" />
|
|
176
|
-
<option value="W29" />
|
|
177
|
-
<option value="E501" />
|
|
178
|
-
<option value="W29" />
|
|
179
|
-
<option value="E501" />
|
|
180
|
-
<option value="W29" />
|
|
181
|
-
<option value="E501" />
|
|
182
|
-
<option value="W29" />
|
|
183
|
-
<option value="E501" />
|
|
184
|
-
<option value="W29" />
|
|
185
|
-
<option value="E501" />
|
|
186
|
-
<option value="W29" />
|
|
187
|
-
<option value="E501" />
|
|
188
|
-
<option value="W29" />
|
|
189
|
-
<option value="E501" />
|
|
190
|
-
<option value="W29" />
|
|
191
|
-
<option value="E501" />
|
|
192
|
-
<option value="W29" />
|
|
193
|
-
<option value="E501" />
|
|
194
|
-
<option value="W29" />
|
|
195
|
-
<option value="E501" />
|
|
196
|
-
<option value="W29" />
|
|
197
|
-
<option value="E501" />
|
|
198
|
-
<option value="W29" />
|
|
199
|
-
<option value="E501" />
|
|
200
|
-
<option value="W29" />
|
|
201
|
-
<option value="E501" />
|
|
202
|
-
<option value="W29" />
|
|
203
|
-
<option value="E501" />
|
|
204
|
-
<option value="W29" />
|
|
205
|
-
<option value="E501" />
|
|
206
|
-
<option value="W29" />
|
|
207
|
-
<option value="E501" />
|
|
208
|
-
<option value="W29" />
|
|
209
|
-
<option value="E501" />
|
|
210
|
-
<option value="W29" />
|
|
211
|
-
<option value="E501" />
|
|
212
|
-
<option value="W29" />
|
|
213
|
-
<option value="E501" />
|
|
214
|
-
<option value="W29" />
|
|
215
|
-
<option value="E501" />
|
|
216
|
-
<option value="W29" />
|
|
217
|
-
<option value="E501" />
|
|
218
|
-
<option value="W29" />
|
|
219
|
-
<option value="E501" />
|
|
220
|
-
<option value="W29" />
|
|
221
|
-
<option value="E501" />
|
|
222
|
-
<option value="W29" />
|
|
223
|
-
<option value="E501" />
|
|
224
|
-
<option value="W29" />
|
|
225
|
-
<option value="E501" />
|
|
226
|
-
<option value="W29" />
|
|
227
|
-
<option value="E501" />
|
|
228
|
-
<option value="W29" />
|
|
229
|
-
<option value="E501" />
|
|
230
|
-
<option value="W29" />
|
|
231
|
-
<option value="E501" />
|
|
232
|
-
<option value="W29" />
|
|
233
|
-
<option value="E501" />
|
|
234
|
-
<option value="W29" />
|
|
235
|
-
<option value="E501" />
|
|
236
|
-
<option value="W29" />
|
|
237
|
-
<option value="E501" />
|
|
238
|
-
<option value="W29" />
|
|
239
|
-
<option value="E501" />
|
|
240
|
-
<option value="W29" />
|
|
241
|
-
<option value="E501" />
|
|
242
|
-
<option value="W29" />
|
|
243
|
-
<option value="E501" />
|
|
244
|
-
<option value="W29" />
|
|
245
|
-
<option value="E501" />
|
|
246
|
-
<option value="W29" />
|
|
247
|
-
<option value="E501" />
|
|
248
|
-
<option value="W29" />
|
|
249
|
-
<option value="E501" />
|
|
250
|
-
<option value="W29" />
|
|
251
|
-
<option value="E501" />
|
|
252
|
-
<option value="W29" />
|
|
253
|
-
<option value="E501" />
|
|
254
|
-
<option value="W29" />
|
|
255
|
-
<option value="E501" />
|
|
256
|
-
<option value="W29" />
|
|
257
|
-
<option value="E501" />
|
|
258
|
-
<option value="W29" />
|
|
259
|
-
<option value="E501" />
|
|
260
|
-
<option value="W29" />
|
|
261
|
-
<option value="E501" />
|
|
262
|
-
<option value="W29" />
|
|
263
|
-
<option value="E501" />
|
|
264
|
-
<option value="W29" />
|
|
265
|
-
<option value="E501" />
|
|
266
|
-
<option value="W29" />
|
|
267
|
-
<option value="E501" />
|
|
268
|
-
<option value="W29" />
|
|
269
|
-
<option value="E501" />
|
|
270
|
-
<option value="W29" />
|
|
271
|
-
<option value="E501" />
|
|
272
|
-
<option value="W29" />
|
|
273
|
-
<option value="E501" />
|
|
274
|
-
<option value="W29" />
|
|
275
|
-
<option value="E501" />
|
|
276
|
-
<option value="W29" />
|
|
277
|
-
<option value="E501" />
|
|
278
|
-
<option value="W29" />
|
|
279
|
-
<option value="E501" />
|
|
280
|
-
<option value="W29" />
|
|
281
|
-
<option value="E501" />
|
|
282
|
-
<option value="W29" />
|
|
283
|
-
<option value="E501" />
|
|
284
|
-
<option value="W29" />
|
|
285
|
-
<option value="E501" />
|
|
286
|
-
<option value="W29" />
|
|
287
|
-
<option value="E501" />
|
|
288
|
-
<option value="W29" />
|
|
289
|
-
<option value="E501" />
|
|
290
|
-
<option value="W29" />
|
|
291
|
-
<option value="E501" />
|
|
292
|
-
<option value="W29" />
|
|
293
|
-
<option value="E501" />
|
|
294
|
-
<option value="W29" />
|
|
295
|
-
<option value="E501" />
|
|
296
|
-
<option value="W29" />
|
|
297
|
-
<option value="E501" />
|
|
298
|
-
<option value="W29" />
|
|
299
|
-
<option value="E501" />
|
|
300
|
-
<option value="W29" />
|
|
301
|
-
<option value="E501" />
|
|
302
|
-
<option value="W29" />
|
|
303
|
-
<option value="E501" />
|
|
304
|
-
<option value="W29" />
|
|
305
|
-
<option value="E501" />
|
|
306
|
-
<option value="W29" />
|
|
307
|
-
<option value="E501" />
|
|
308
|
-
<option value="W29" />
|
|
309
|
-
<option value="E501" />
|
|
310
|
-
<option value="W29" />
|
|
311
|
-
<option value="E501" />
|
|
312
|
-
<option value="W29" />
|
|
313
|
-
<option value="E501" />
|
|
314
|
-
<option value="W29" />
|
|
315
|
-
<option value="E501" />
|
|
316
|
-
<option value="W29" />
|
|
317
|
-
<option value="E501" />
|
|
318
|
-
<option value="W29" />
|
|
319
|
-
<option value="E501" />
|
|
320
|
-
<option value="W29" />
|
|
321
|
-
<option value="E501" />
|
|
322
|
-
<option value="W29" />
|
|
323
|
-
<option value="E501" />
|
|
324
|
-
<option value="W29" />
|
|
325
|
-
<option value="E501" />
|
|
326
|
-
<option value="W29" />
|
|
327
|
-
<option value="E501" />
|
|
328
|
-
<option value="W29" />
|
|
329
|
-
<option value="E501" />
|
|
330
|
-
<option value="W29" />
|
|
331
|
-
<option value="E501" />
|
|
332
|
-
<option value="W29" />
|
|
333
|
-
<option value="E501" />
|
|
334
|
-
<option value="W29" />
|
|
335
|
-
<option value="E501" />
|
|
336
|
-
<option value="W29" />
|
|
337
|
-
<option value="E501" />
|
|
338
|
-
<option value="W29" />
|
|
339
|
-
<option value="E501" />
|
|
340
|
-
<option value="W29" />
|
|
341
|
-
<option value="E501" />
|
|
342
|
-
<option value="W29" />
|
|
343
|
-
<option value="E501" />
|
|
344
|
-
<option value="W29" />
|
|
345
|
-
<option value="E501" />
|
|
346
|
-
<option value="W29" />
|
|
347
|
-
<option value="E501" />
|
|
348
|
-
<option value="W29" />
|
|
349
|
-
<option value="E501" />
|
|
350
|
-
<option value="W29" />
|
|
351
|
-
<option value="E501" />
|
|
352
|
-
<option value="W29" />
|
|
353
|
-
<option value="E501" />
|
|
354
|
-
<option value="W29" />
|
|
355
|
-
<option value="E501" />
|
|
356
|
-
<option value="W29" />
|
|
357
|
-
<option value="E501" />
|
|
358
|
-
<option value="W29" />
|
|
359
|
-
<option value="E501" />
|
|
360
|
-
<option value="W29" />
|
|
361
|
-
<option value="E501" />
|
|
362
|
-
<option value="W29" />
|
|
363
|
-
<option value="E501" />
|
|
364
|
-
<option value="W29" />
|
|
365
|
-
<option value="E501" />
|
|
366
|
-
<option value="W29" />
|
|
367
|
-
<option value="E501" />
|
|
368
|
-
<option value="W29" />
|
|
369
|
-
<option value="E501" />
|
|
370
|
-
<option value="W29" />
|
|
371
|
-
<option value="E501" />
|
|
372
|
-
<option value="W29" />
|
|
373
|
-
<option value="E501" />
|
|
374
|
-
<option value="W29" />
|
|
375
|
-
<option value="E501" />
|
|
376
|
-
<option value="W29" />
|
|
377
|
-
<option value="E501" />
|
|
378
|
-
<option value="W29" />
|
|
379
|
-
<option value="E501" />
|
|
380
|
-
</list>
|
|
381
|
-
</option>
|
|
382
|
-
</inspection_tool>
|
|
383
|
-
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
|
384
|
-
<option name="ignoredErrors">
|
|
385
|
-
<list>
|
|
386
|
-
<option value="N806" />
|
|
387
|
-
<option value="N802" />
|
|
388
|
-
</list>
|
|
389
|
-
</option>
|
|
390
|
-
</inspection_tool>
|
|
391
|
-
</profile>
|
|
392
|
-
</component>
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="ProjectModuleManager">
|
|
4
|
-
<modules>
|
|
5
|
-
<module fileurl="file://$PROJECT_DIR$/../pyrox-client/.idea/pyrox-client.iml" filepath="$PROJECT_DIR$/../pyrox-client/.idea/pyrox-client.iml" />
|
|
6
|
-
</modules>
|
|
7
|
-
</component>
|
|
8
|
-
</project>
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<module type="PYTHON_MODULE" version="4">
|
|
3
|
-
<component name="NewModuleRootManager">
|
|
4
|
-
<content url="file://$MODULE_DIR$" />
|
|
5
|
-
<orderEntry type="inheritedJdk" />
|
|
6
|
-
<orderEntry type="sourceFolder" forTests="false" />
|
|
7
|
-
</component>
|
|
8
|
-
</module>
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="AutoImportSettings">
|
|
4
|
-
<option name="autoReloadType" value="SELECTIVE" />
|
|
5
|
-
</component>
|
|
6
|
-
<component name="ChangeListManager">
|
|
7
|
-
<list default="true" id="697e0274-d3c5-4401-be7b-acf1d10d3541" name="Changes" comment="" />
|
|
8
|
-
<option name="SHOW_DIALOG" value="false" />
|
|
9
|
-
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
10
|
-
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
11
|
-
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
12
|
-
</component>
|
|
13
|
-
<component name="MarkdownSettingsMigration">
|
|
14
|
-
<option name="stateVersion" value="1" />
|
|
15
|
-
</component>
|
|
16
|
-
<component name="ProjectId" id="31jilXllIHNRHUAEcZyhAlo8CE8" />
|
|
17
|
-
<component name="ProjectViewState">
|
|
18
|
-
<option name="hideEmptyMiddlePackages" value="true" />
|
|
19
|
-
<option name="showLibraryContents" value="true" />
|
|
20
|
-
</component>
|
|
21
|
-
<component name="PropertiesComponent"><![CDATA[{
|
|
22
|
-
"keyToString": {
|
|
23
|
-
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
|
24
|
-
"RunOnceActivity.ShowReadmeOnStart": "true",
|
|
25
|
-
"last_opened_file_path": "/Users/vladmatei"
|
|
26
|
-
}
|
|
27
|
-
}]]></component>
|
|
28
|
-
<component name="RunManager">
|
|
29
|
-
<configuration default="true" type="PythonConfigurationType" factoryName="Python">
|
|
30
|
-
<module name="pyrox-client" />
|
|
31
|
-
<option name="INTERPRETER_OPTIONS" value="" />
|
|
32
|
-
<option name="PARENT_ENVS" value="true" />
|
|
33
|
-
<envs>
|
|
34
|
-
<env name="PYTHONUNBUFFERED" value="1" />
|
|
35
|
-
</envs>
|
|
36
|
-
<option name="SDK_HOME" value="" />
|
|
37
|
-
<option name="WORKING_DIRECTORY" value="" />
|
|
38
|
-
<option name="IS_MODULE_SDK" value="false" />
|
|
39
|
-
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
40
|
-
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
41
|
-
<option name="SCRIPT_NAME" value="" />
|
|
42
|
-
<option name="PARAMETERS" value="" />
|
|
43
|
-
<option name="SHOW_COMMAND_LINE" value="false" />
|
|
44
|
-
<option name="EMULATE_TERMINAL" value="false" />
|
|
45
|
-
<option name="MODULE_MODE" value="false" />
|
|
46
|
-
<option name="REDIRECT_INPUT" value="false" />
|
|
47
|
-
<option name="INPUT_FILE" value="" />
|
|
48
|
-
<method v="2" />
|
|
49
|
-
</configuration>
|
|
50
|
-
<configuration name="main" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
|
|
51
|
-
<module name="pyrox-client" />
|
|
52
|
-
<option name="INTERPRETER_OPTIONS" value="" />
|
|
53
|
-
<option name="PARENT_ENVS" value="true" />
|
|
54
|
-
<envs>
|
|
55
|
-
<env name="PYTHONUNBUFFERED" value="1" />
|
|
56
|
-
</envs>
|
|
57
|
-
<option name="SDK_HOME" value="" />
|
|
58
|
-
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
|
59
|
-
<option name="IS_MODULE_SDK" value="true" />
|
|
60
|
-
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
61
|
-
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
62
|
-
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/main.py" />
|
|
63
|
-
<option name="PARAMETERS" value="" />
|
|
64
|
-
<option name="SHOW_COMMAND_LINE" value="false" />
|
|
65
|
-
<option name="EMULATE_TERMINAL" value="false" />
|
|
66
|
-
<option name="MODULE_MODE" value="false" />
|
|
67
|
-
<option name="REDIRECT_INPUT" value="false" />
|
|
68
|
-
<option name="INPUT_FILE" value="" />
|
|
69
|
-
<method v="2" />
|
|
70
|
-
</configuration>
|
|
71
|
-
<configuration default="true" type="Tox" factoryName="Tox">
|
|
72
|
-
<module name="pyrox-client" />
|
|
73
|
-
<option name="INTERPRETER_OPTIONS" value="" />
|
|
74
|
-
<option name="PARENT_ENVS" value="true" />
|
|
75
|
-
<option name="SDK_HOME" value="" />
|
|
76
|
-
<option name="WORKING_DIRECTORY" value="" />
|
|
77
|
-
<option name="IS_MODULE_SDK" value="false" />
|
|
78
|
-
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
79
|
-
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
80
|
-
<method v="2" />
|
|
81
|
-
</configuration>
|
|
82
|
-
<configuration default="true" type="ccruntests" factoryName="Run Study Tests">
|
|
83
|
-
<module name="pyrox-client" />
|
|
84
|
-
<option name="INTERPRETER_OPTIONS" value="" />
|
|
85
|
-
<option name="PARENT_ENVS" value="true" />
|
|
86
|
-
<envs>
|
|
87
|
-
<env name="PYTHONUNBUFFERED" value="1" />
|
|
88
|
-
</envs>
|
|
89
|
-
<option name="SDK_HOME" value="" />
|
|
90
|
-
<option name="WORKING_DIRECTORY" value="" />
|
|
91
|
-
<option name="IS_MODULE_SDK" value="false" />
|
|
92
|
-
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
93
|
-
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
94
|
-
<option name="SCRIPT_NAME" value="" />
|
|
95
|
-
<option name="PARAMETERS" value="" />
|
|
96
|
-
<option name="SHOW_COMMAND_LINE" value="false" />
|
|
97
|
-
<option name="EMULATE_TERMINAL" value="false" />
|
|
98
|
-
<option name="MODULE_MODE" value="false" />
|
|
99
|
-
<option name="REDIRECT_INPUT" value="false" />
|
|
100
|
-
<option name="INPUT_FILE" value="" />
|
|
101
|
-
<option name="studyTest" value="" />
|
|
102
|
-
<method v="2" />
|
|
103
|
-
</configuration>
|
|
104
|
-
<configuration default="true" type="docs" factoryName="Docutils task">
|
|
105
|
-
<module name="pyrox-client" />
|
|
106
|
-
<option name="INTERPRETER_OPTIONS" value="" />
|
|
107
|
-
<option name="PARENT_ENVS" value="true" />
|
|
108
|
-
<option name="SDK_HOME" value="" />
|
|
109
|
-
<option name="WORKING_DIRECTORY" value="" />
|
|
110
|
-
<option name="IS_MODULE_SDK" value="false" />
|
|
111
|
-
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
112
|
-
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
113
|
-
<option name="docutils_input_file" value="" />
|
|
114
|
-
<option name="docutils_output_file" value="" />
|
|
115
|
-
<option name="docutils_params" value="" />
|
|
116
|
-
<option name="docutils_task" value="" />
|
|
117
|
-
<option name="docutils_open_in_browser" value="false" />
|
|
118
|
-
<method v="2" />
|
|
119
|
-
</configuration>
|
|
120
|
-
<configuration default="true" type="docs" factoryName="Sphinx task">
|
|
121
|
-
<module name="pyrox-client" />
|
|
122
|
-
<option name="INTERPRETER_OPTIONS" value="" />
|
|
123
|
-
<option name="PARENT_ENVS" value="true" />
|
|
124
|
-
<option name="SDK_HOME" value="" />
|
|
125
|
-
<option name="WORKING_DIRECTORY" value="" />
|
|
126
|
-
<option name="IS_MODULE_SDK" value="false" />
|
|
127
|
-
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
128
|
-
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
129
|
-
<option name="docutils_input_file" value="" />
|
|
130
|
-
<option name="docutils_output_file" value="" />
|
|
131
|
-
<option name="docutils_params" value="" />
|
|
132
|
-
<option name="docutils_task" value="" />
|
|
133
|
-
<option name="docutils_open_in_browser" value="false" />
|
|
134
|
-
<method v="2" />
|
|
135
|
-
</configuration>
|
|
136
|
-
<configuration default="true" type="tests" factoryName="Autodetect">
|
|
137
|
-
<module name="pyrox-client" />
|
|
138
|
-
<option name="INTERPRETER_OPTIONS" value="" />
|
|
139
|
-
<option name="PARENT_ENVS" value="true" />
|
|
140
|
-
<option name="SDK_HOME" value="" />
|
|
141
|
-
<option name="WORKING_DIRECTORY" value="" />
|
|
142
|
-
<option name="IS_MODULE_SDK" value="false" />
|
|
143
|
-
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
144
|
-
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
145
|
-
<option name="_new_additionalArguments" value="""" />
|
|
146
|
-
<option name="_new_target" value="""" />
|
|
147
|
-
<option name="_new_targetType" value=""PATH"" />
|
|
148
|
-
<method v="2" />
|
|
149
|
-
</configuration>
|
|
150
|
-
<configuration default="true" type="tests" factoryName="Doctests">
|
|
151
|
-
<module name="pyrox-client" />
|
|
152
|
-
<option name="INTERPRETER_OPTIONS" value="" />
|
|
153
|
-
<option name="PARENT_ENVS" value="true" />
|
|
154
|
-
<option name="SDK_HOME" value="" />
|
|
155
|
-
<option name="WORKING_DIRECTORY" value="" />
|
|
156
|
-
<option name="IS_MODULE_SDK" value="false" />
|
|
157
|
-
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
158
|
-
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
159
|
-
<option name="SCRIPT_NAME" value="" />
|
|
160
|
-
<option name="CLASS_NAME" value="" />
|
|
161
|
-
<option name="METHOD_NAME" value="" />
|
|
162
|
-
<option name="FOLDER_NAME" value="" />
|
|
163
|
-
<option name="TEST_TYPE" value="TEST_SCRIPT" />
|
|
164
|
-
<option name="PATTERN" value="" />
|
|
165
|
-
<option name="USE_PATTERN" value="false" />
|
|
166
|
-
<method v="2" />
|
|
167
|
-
</configuration>
|
|
168
|
-
</component>
|
|
169
|
-
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
|
170
|
-
<component name="TaskManager">
|
|
171
|
-
<task active="true" id="Default" summary="Default task">
|
|
172
|
-
<changelist id="697e0274-d3c5-4401-be7b-acf1d10d3541" name="Changes" comment="" />
|
|
173
|
-
<created>1756044033429</created>
|
|
174
|
-
<option name="number" value="Default" />
|
|
175
|
-
<option name="presentableId" value="Default" />
|
|
176
|
-
<updated>1756044033429</updated>
|
|
177
|
-
</task>
|
|
178
|
-
<servers />
|
|
179
|
-
</component>
|
|
180
|
-
<component name="XDebuggerManager">
|
|
181
|
-
<breakpoint-manager>
|
|
182
|
-
<breakpoints>
|
|
183
|
-
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
|
184
|
-
<url>file://$PROJECT_DIR$/../pyrox-client/main.py</url>
|
|
185
|
-
<line>8</line>
|
|
186
|
-
<option name="timeStamp" value="1" />
|
|
187
|
-
</line-breakpoint>
|
|
188
|
-
</breakpoints>
|
|
189
|
-
</breakpoint-manager>
|
|
190
|
-
</component>
|
|
191
|
-
</project>
|
pyrox_client-0.0.1/main.py
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# This is a sample Python script.
|
|
2
|
-
|
|
3
|
-
# Press ⌃R to execute it or replace it with your code.
|
|
4
|
-
# Press Double ⇧ to search everywhere for classes, files, tool windows, actions, and settings.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def print_hi(name):
|
|
8
|
-
# Use a breakpoint in the code line below to debug your script.
|
|
9
|
-
print(f'Hi, {name}') # Press ⌘F8 to toggle the breakpoint.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
# Press the green button in the gutter to run the script.
|
|
13
|
-
if __name__ == '__main__':
|
|
14
|
-
print_hi('PyCharm')
|
|
15
|
-
|
|
16
|
-
# See PyCharm help at https://www.jetbrains.com/help/pycharm/
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["hatchling>=1.20"]
|
|
3
|
-
build-backend = "hatchling.build"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "pyrox-client"
|
|
7
|
-
version = "0.0.1"
|
|
8
|
-
description = "HYROX race data client - retrieve full race results via Python"
|
|
9
|
-
authors = [{name="Vlad Matei"}]
|
|
10
|
-
readme = "README.md"
|
|
11
|
-
license = {text = "MIT"}
|
|
12
|
-
requires-python = ">=3.9"
|
|
13
|
-
dependencies = ["pandas>=2.0", "fastparquet>=15", "requests>=2.31"]
|
|
14
|
-
|
|
15
|
-
[project.optional-dependencies]
|
|
16
|
-
duckdb = ["duckdb>=1.0.0"]
|
|
17
|
-
|
|
18
|
-
[project.urls]
|
|
19
|
-
homepage = "https://github.com/<you>/pyrox"
|
|
20
|
-
|
|
21
|
-
[tool.hatch.build.targets.wheel]
|
|
22
|
-
packages = ["src/pyrox"] # import package path
|
|
23
|
-
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
*
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.0.1"
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import pandas as pd
|
|
2
|
-
import io, json, requests
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
|
|
5
|
-
CDN_BASE = "https://<your-cloudfront-domain>/<prefix>"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
@dataclass(frozen=True)
|
|
9
|
-
class EventRef:
|
|
10
|
-
season: int
|
|
11
|
-
event_id: str
|
|
12
|
-
race: str
|
|
13
|
-
key: str # "season=7/Cardiff_2025__LR3MS4JIB56.parquet"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def _manifest():
|
|
17
|
-
url = f"{CDN_BASE}/catalog/manifest-v1.json"
|
|
18
|
-
r = requests.get(url, timeout=20)
|
|
19
|
-
r.raise_for_status()
|
|
20
|
-
return r.json()
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def list_seasons() -> list[int]:
|
|
24
|
-
return _manifest()["seasons"]
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def list_events(season: int | None = None) -> list[EventRef]:
|
|
28
|
-
m = _manifest()["events"]
|
|
29
|
-
if season is not None:
|
|
30
|
-
m = [e for e in m if e["season"] == season]
|
|
31
|
-
return [EventRef(**{k: e[k] for k in ("season", "event_id", "race", "key")}) for e in m]
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def get_race(*, season: int | None = None, location: str | None = None, event_id: str | None = None) -> pd.DataFrame:
|
|
35
|
-
events = list_events(season)
|
|
36
|
-
if event_id:
|
|
37
|
-
ev = next(e for e in events if e.event_id == event_id)
|
|
38
|
-
elif location:
|
|
39
|
-
# naive match; you can add fuzzy/normalized matching later
|
|
40
|
-
cand = [e for e in events if location.lower() in e.race.lower()]
|
|
41
|
-
if not cand:
|
|
42
|
-
raise ValueError(f"No event matching {location!r}")
|
|
43
|
-
ev = cand[0]
|
|
44
|
-
else:
|
|
45
|
-
raise ValueError("Provide event_id or location (optionally season).")
|
|
46
|
-
url = f"{CDN_BASE}/{ev.key}"
|
|
47
|
-
resp = requests.get(url, timeout=60)
|
|
48
|
-
resp.raise_for_status()
|
|
49
|
-
return pd.read_parquet(io.BytesIO(resp.content))
|
|
File without changes
|