runtilities 2.3.0.dev2__tar.gz → 3.0.0.dev1__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.
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/PKG-INFO +1 -1
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/runsignup.py +47 -71
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/version.py +1 -1
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/runtilities.egg-info/PKG-INFO +1 -1
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/README.md +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/__init__.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/analyzeagegrade.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/athlinks.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/athlinksresults.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/comparegpx.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/competitor.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/competitor2csv.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/getweather.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/gpx2kml.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/parseralogxml.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/parseresults.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/parserun-bk3.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/parsetcx.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/ra2membersfile.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/racewx-render.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/racewx.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/renderclubagstats.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/runningahead.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/runningaheadmembers.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/runningaheadparticipants.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/runningaheadresults.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/strava.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/textnormalize.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/ultrasignup.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/ultrasignupresults.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/xmldict.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/xmldict1.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/xmldict2.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/running/xmlreader.py +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/runtilities.egg-info/SOURCES.txt +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/runtilities.egg-info/dependency_links.txt +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/runtilities.egg-info/entry_points.txt +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/runtilities.egg-info/not-zip-safe +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/runtilities.egg-info/requires.txt +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/runtilities.egg-info/top_level.txt +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/setup.cfg +0 -0
- {runtilities-2.3.0.dev2 → runtilities-3.0.0.dev1}/setup.py +0 -0
|
@@ -1,25 +1,3 @@
|
|
|
1
|
-
###########################################################################################
|
|
2
|
-
# runsignup - access methods for runsignup.com
|
|
3
|
-
#
|
|
4
|
-
# Date Author Reason
|
|
5
|
-
# ---- ------ ------
|
|
6
|
-
# 12/31/17 Lou King Create from runningahead.com
|
|
7
|
-
#
|
|
8
|
-
# Copyright 2017 Lou King
|
|
9
|
-
#
|
|
10
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
11
|
-
# you may not use this file except in compliance with the License.
|
|
12
|
-
# You may obtain a copy of the License at
|
|
13
|
-
#
|
|
14
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
15
|
-
#
|
|
16
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
17
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
18
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
19
|
-
# See the License for the specific language governing permissions and
|
|
20
|
-
# limitations under the License.
|
|
21
|
-
#
|
|
22
|
-
###########################################################################################
|
|
23
1
|
'''
|
|
24
2
|
runsignup - access methods for runsignup.com
|
|
25
3
|
===================================================
|
|
@@ -52,10 +30,6 @@ names = NameDenormalizer()
|
|
|
52
30
|
|
|
53
31
|
# use api.runsignup.com per https://info.runsignup.com/2025/08/06/upgrading-our-api-infrastructure-for-ai-api-runsignup-com/
|
|
54
32
|
|
|
55
|
-
# login API (deprecated)
|
|
56
|
-
login_url = 'https://api.runsignup.com/rest/login'
|
|
57
|
-
logout_url = 'https://api.runsignup.com/rest/logout'
|
|
58
|
-
|
|
59
33
|
# methods
|
|
60
34
|
members_url = 'https://api.runsignup.com/rest/club/{club_id}/members'
|
|
61
35
|
getrace_url = 'https://api.runsignup.com/rest/race/{race_id}'
|
|
@@ -78,17 +52,21 @@ class RunSignUp():
|
|
|
78
52
|
'''
|
|
79
53
|
access methods for RunSignUp.com
|
|
80
54
|
|
|
81
|
-
|
|
82
|
-
|
|
55
|
+
key and secret should be supplied for authenticated access
|
|
56
|
+
|
|
57
|
+
per https://info.runsignup.com/2026/07/17/new-api-registration-requirements/, all API callers must
|
|
58
|
+
register (free) and supply the resulting token/secret on every call starting 2027-01-01; existing
|
|
59
|
+
api_key/api_secret credentials are unaffected and continue to be required alongside these
|
|
83
60
|
|
|
84
61
|
:param key: key from runsignup (direct key, no OAuth)
|
|
85
62
|
:param secret: secret from runsignup (direct secret, no OAuth)
|
|
86
|
-
:param
|
|
87
|
-
:param
|
|
63
|
+
:param api_reg_token: API caller registration token, sent as rsu_api_reg GET parameter
|
|
64
|
+
:param api_reg_secret: API caller registration secret, sent as X-RSU-API-REG-SECRET header
|
|
88
65
|
:param debug: set to True for debug logging of http requests, default False
|
|
89
66
|
'''
|
|
90
67
|
|
|
91
|
-
def __init__(self, userpriv=False, key=None, secret=None,
|
|
68
|
+
def __init__(self, userpriv=False, key=None, secret=None,
|
|
69
|
+
api_reg_token=None, api_reg_secret=None, debug=False):
|
|
92
70
|
"""
|
|
93
71
|
initialize
|
|
94
72
|
"""
|
|
@@ -108,27 +86,20 @@ class RunSignUp():
|
|
|
108
86
|
requests_log.setLevel(logging.NOTSET)
|
|
109
87
|
requests_log.propagate = False
|
|
110
88
|
|
|
111
|
-
self.userpriv =
|
|
112
|
-
if (not key and not email):
|
|
113
|
-
self.userpriv = True
|
|
89
|
+
self.userpriv = not key
|
|
114
90
|
if (key and not secret) or (secret and not key):
|
|
115
91
|
raise parameterError('key and secret must be supplied together')
|
|
116
|
-
if (
|
|
117
|
-
raise parameterError('
|
|
92
|
+
if (api_reg_token and not api_reg_secret) or (api_reg_secret and not api_reg_token):
|
|
93
|
+
raise parameterError('api_reg_token and api_reg_secret must be supplied together')
|
|
118
94
|
|
|
119
95
|
self.key = key
|
|
120
96
|
self.secret = secret
|
|
121
|
-
self.
|
|
122
|
-
self.
|
|
97
|
+
self.api_reg_token = api_reg_token
|
|
98
|
+
self.api_reg_secret = api_reg_secret
|
|
123
99
|
self.debug = debug
|
|
124
100
|
self.client_credentials = {}
|
|
125
101
|
|
|
126
|
-
if self.userpriv
|
|
127
|
-
self.credentials_type = 'none'
|
|
128
|
-
elif key:
|
|
129
|
-
self.credentials_type = 'key'
|
|
130
|
-
else:
|
|
131
|
-
self.credentials_type = 'login'
|
|
102
|
+
self.credentials_type = 'none' if self.userpriv else 'key'
|
|
132
103
|
|
|
133
104
|
def __enter__(self):
|
|
134
105
|
self.open()
|
|
@@ -142,22 +113,18 @@ class RunSignUp():
|
|
|
142
113
|
# set up session for multiple requests
|
|
143
114
|
self.session = requests.Session()
|
|
144
115
|
|
|
116
|
+
# per https://info.runsignup.com/2026/07/17/new-api-registration-requirements/, registration
|
|
117
|
+
# secret is sent as a header, applies regardless of credentials_type
|
|
118
|
+
if self.api_reg_secret:
|
|
119
|
+
self.session.headers.update({'X-RSU-API-REG-SECRET': self.api_reg_secret})
|
|
120
|
+
|
|
145
121
|
if not self.userpriv:
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
else:
|
|
153
|
-
# login to runsignup - note temporary keys will expire 1 hour after last API call
|
|
154
|
-
# see https://api.runsignup.com/API/login/POST
|
|
155
|
-
r = requests.post(login_url, params={'format' : 'json'}, data={'email' : self.email, 'password' : self.password})
|
|
156
|
-
resp = r.json()
|
|
157
|
-
|
|
158
|
-
self.credentials_type = 'login'
|
|
159
|
-
self.client_credentials = {'tmp_key' : resp['tmp_key'],
|
|
160
|
-
'tmp_secret' : resp['tmp_secret']}
|
|
122
|
+
self.client_credentials = {'api_key' : self.key,
|
|
123
|
+
'api_secret' : self.secret}
|
|
124
|
+
|
|
125
|
+
# registration token is sent as a GET parameter alongside whichever credentials were set above
|
|
126
|
+
if self.api_reg_token:
|
|
127
|
+
self.client_credentials['rsu_api_reg'] = self.api_reg_token
|
|
161
128
|
|
|
162
129
|
def close(self):
|
|
163
130
|
'''
|
|
@@ -166,8 +133,6 @@ class RunSignUp():
|
|
|
166
133
|
self.client_credentials = {}
|
|
167
134
|
self.session.close()
|
|
168
135
|
|
|
169
|
-
# TODO: should we also log out?
|
|
170
|
-
|
|
171
136
|
def members(self, club_id, **kwargs):
|
|
172
137
|
'''
|
|
173
138
|
return members accessible to this application
|
|
@@ -420,7 +385,8 @@ class RunSignUp():
|
|
|
420
385
|
return data
|
|
421
386
|
|
|
422
387
|
#----------------------------------------------------------------------
|
|
423
|
-
def updatemembercache(club_id, membercachefilename, key=None, secret=None,
|
|
388
|
+
def updatemembercache(club_id, membercachefilename, key=None, secret=None,
|
|
389
|
+
api_reg_token=None, api_reg_secret=None, debug=False):
|
|
424
390
|
if debug:
|
|
425
391
|
# set up debug logging
|
|
426
392
|
thislogger.setLevel(logging.DEBUG)
|
|
@@ -431,7 +397,8 @@ def updatemembercache(club_id, membercachefilename, key=None, secret=None, email
|
|
|
431
397
|
thislogger.propagate = True
|
|
432
398
|
|
|
433
399
|
# set up access to RunSignUp
|
|
434
|
-
rsu = RunSignUp(key=key, secret=secret,
|
|
400
|
+
rsu = RunSignUp(key=key, secret=secret,
|
|
401
|
+
api_reg_token=api_reg_token, api_reg_secret=api_reg_secret, debug=debug)
|
|
435
402
|
rsu.open()
|
|
436
403
|
|
|
437
404
|
# transform from RunSignUp to membercache format
|
|
@@ -608,7 +575,8 @@ def updatemembercache(club_id, membercachefilename, key=None, secret=None, email
|
|
|
608
575
|
return rsumembers
|
|
609
576
|
|
|
610
577
|
#----------------------------------------------------------------------
|
|
611
|
-
def members2csv(club_id, key, secret, mapping, filepath=None, encoding=None
|
|
578
|
+
def members2csv(club_id, key, secret, mapping, filepath=None, encoding=None,
|
|
579
|
+
api_reg_token=None, api_reg_secret=None):
|
|
612
580
|
'''
|
|
613
581
|
Access club_id through RunSignUp API to retrieve members. Return
|
|
614
582
|
list of members as if csv file. Optionally save csv file.
|
|
@@ -619,11 +587,13 @@ def members2csv(club_id, key, secret, mapping, filepath=None, encoding=None):
|
|
|
619
587
|
:param mapping: OrderedDict {'outfield1':'infield1', 'outfield2':outfunction(inrec), ...} or ['inoutfield1', 'inoutfield2', ...]
|
|
620
588
|
:param normfile: (optional) pathname to save csv file
|
|
621
589
|
:param encoding: (optional) encoding to use for file
|
|
590
|
+
:param api_reg_token: API caller registration token, sent as rsu_api_reg GET parameter
|
|
591
|
+
:param api_reg_secret: API caller registration secret, sent as X-RSU-API-REG-SECRET header
|
|
622
592
|
:rtype: csv file records, as list
|
|
623
593
|
'''
|
|
624
594
|
|
|
625
595
|
# get the members from the RunSignUp API
|
|
626
|
-
with RunSignUp(key=key, secret=secret) as rsu:
|
|
596
|
+
with RunSignUp(key=key, secret=secret, api_reg_token=api_reg_token, api_reg_secret=api_reg_secret) as rsu:
|
|
627
597
|
members = rsu.members(club_id)
|
|
628
598
|
|
|
629
599
|
filerows = record2csv(members, mapping, filepath, encoding=encoding)
|
|
@@ -879,12 +849,15 @@ class RunSignupFluent(UniversalClient):
|
|
|
879
849
|
'''
|
|
880
850
|
Fluent interface to RunSignUp API -- see https://universal-client.readthedocs.io
|
|
881
851
|
'''
|
|
882
|
-
def __init__(self, key=None, secret=None, debug=False):
|
|
852
|
+
def __init__(self, key=None, secret=None, api_reg_token=None, api_reg_secret=None, debug=False):
|
|
883
853
|
'''
|
|
884
854
|
initialize RunSignUp Fluent client
|
|
885
855
|
|
|
886
856
|
:param key: api key for RunSignUp
|
|
887
857
|
:param secret: api secret for RunSignUp
|
|
858
|
+
:param api_reg_token: API caller registration token, sent as rsu_api_reg GET parameter -- see
|
|
859
|
+
https://info.runsignup.com/2026/07/17/new-api-registration-requirements/
|
|
860
|
+
:param api_reg_secret: API caller registration secret, sent as X-RSU-API-REG-SECRET header
|
|
888
861
|
:param debug: debug flag
|
|
889
862
|
'''
|
|
890
863
|
# rsuservice = Oauth2Service(
|
|
@@ -898,9 +871,12 @@ class RunSignupFluent(UniversalClient):
|
|
|
898
871
|
self._params = params = {'api_key' : key,
|
|
899
872
|
'api_secret' : secret,
|
|
900
873
|
'format' : 'json' }
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
874
|
+
if api_reg_token:
|
|
875
|
+
params['rsu_api_reg'] = api_reg_token
|
|
876
|
+
|
|
877
|
+
client_kwargs = {'url': 'https://api.runsignup.com/rest', 'params': params}
|
|
878
|
+
if api_reg_secret:
|
|
879
|
+
client_kwargs['headers'] = {'X-RSU-API-REG-SECRET': api_reg_secret}
|
|
880
|
+
|
|
881
|
+
super().__init__(**client_kwargs)
|
|
906
882
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# this string is used for the version string in the documentation, as well as the egg
|
|
2
|
-
__version__ = '
|
|
2
|
+
__version__ = '3.0.0.dev1'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|