Browse Source

move steam2/3 coversions to seperate functions

pull/18/merge
Rossen Georgiev 9 years ago
parent
commit
5db7737c26
  1. 173
      steam/steamid.py
  2. 154
      tests/test_steamid.py

173
steam/steamid.py

@ -1,27 +1,27 @@
import re
from steam.enums import EType, EUniverse
ETypeCharMap = {
0: 'I',
1: 'U',
2: 'M',
3: 'G',
4: 'A',
5: 'P',
6: 'C',
7: 'g',
8: 'T',
8: 'c',
8: 'L',
10: 'a',
}
class SteamID(object):
"""
Object for converting steamID to its' various representations
"""
ETypeChar = {
0: 'I',
1: 'U',
2: 'M',
3: 'G',
4: 'A',
5: 'P',
6: 'C',
7: 'g',
8: 'T',
8: 'c',
8: 'L',
10: 'a',
}
def __init__(self, *args, **kwargs):
"""
The instance can be initialized with various parameters
@ -41,36 +41,26 @@ class SteamID(object):
# you should use the WebAPI to resolve them reliably
SteamID('https://steamcommunity.com/id/drunkenf00l')
"""
self.id = 0
self.type = EType.Invalid
self.universe = EUniverse.Invalid
self.instance = 0
largs = len(args)
if largs == 0 and len(kwargs) == 0:
self.id = 0
self.type = EType.Invalid
self.universe = EUniverse.Invalid
self.instance = 0
elif largs > 0:
if largs > 1:
raise ValueError("Needed only 1 arg, got %d" % largs)
if len(args) == 1:
value = str(args[0])
# numeric input
if value.isdigit() or (value.startswith('-') and value[1:].isdigit()):
if value.isdigit():
value = int(value)
if 0 > value:
raise ValueError("Expected positive int, got %d" % value)
if value >= 2**64:
raise ValueError("Expected a 32/64 bit int")
# 32 bit account id
if value < 2**32:
if 0 < value < 2**32:
self.id = value
self.type = EType.Individual
self.universe = EUniverse.Public
self.instance = 1
# 64 bit
else:
elif value < 2**64:
self.id = value & 0xFFffFFff
self.instance = (value >> 32) & 0xFFffF
self.type = EType((value >> 52) & 0xF)
@ -78,61 +68,25 @@ class SteamID(object):
# textual input e.g. [g:1:4]
else:
# try steam2
match = re.match(r"^STEAM_(?P<universe>[01])"
r":(?P<reminder>[0-1])"
r":(?P<id>\d+)$", value
)
if match:
self.id = (int(match.group('id')) << 1) | int(match.group('reminder'))
self.universe = EUniverse(1)
self.type = EType(1)
self.instance = 1
return
# try steam3
typeChars = ''.join(self.ETypeChar.values())
match = re.match(r"^\["
r"(?P<type>[%s]):" # type char
r"(?P<universe>\d+):" # universe
r"(?P<id>\d+)" # accountid
r"(:(?P<instance>\d+))?" # instance
r"\]$" % typeChars, value
)
if match:
self.id = int(match.group('id'))
self.universe = EUniverse(int(match.group('universe')))
inverseETypeChar = dict((b, a) for (a, b) in self.ETypeChar.items())
self.type = EType(inverseETypeChar[match.group('type')])
self.instance = match.group('instance')
if self.instance is None:
if self.type in (EType.Individual, EType.GameServer):
self.instance = 1
else:
self.instance = 0
else:
self.instance = int(self.instance)
return
raise ValueError("Expected a steam32/64 or textual steam id"
", got %s" % repr(value)
)
result = steam2_to_tuple(value) or steam3_to_tuple(value)
elif len(kwargs):
if 'id' not in kwargs:
raise ValueError("Expected at least 'id' kwarg")
if result:
(self.id,
self.type,
self.universe,
self.instance
) = result
self.id = int(kwargs['id'])
assert self.id <= 0xffffFFFF, "id larger than 32bits"
elif len(kwargs):
self.id = int(kwargs.get('id', 0))
value = kwargs.get('type', 0)
value = kwargs.get('type', 1)
if type(value) in (int, EType):
self.type = EType(value)
else:
self.type = EType[value.lower().capitalize()]
value = kwargs.get('universe', 0)
value = kwargs.get('universe', 1)
if type(value) in (int, EUniverse):
self.universe = EUniverse(value)
else:
@ -160,11 +114,20 @@ class SteamID(object):
return str(self.as_64)
def __cmp__(self, other):
return cmp(self.as_64, other.as_64)
if isinstance(other, SteamID):
return cmp(self.as_64, other.as_64)
else:
raise RuntimeError("Can only compare SteamID instances")
def __hash__(self):
return hash(self.as_64)
def is_valid(self):
return (0 < self.id < 2**32
and self.type is not EType.Invalid
and self.universe is not EUniverse.Invalid
)
@property
def as_steam2(self):
return "STEAM_0:%s:%s" % (
@ -176,14 +139,14 @@ class SteamID(object):
def as_steam3(self):
if self.type is EType.AnonGameServer:
return "[%s:%s:%s:%s]" % (
self.ETypeChar[self.type.value],
ETypeCharMap[self.type.value],
self.universe.value,
self.id,
self.instance
)
else:
return "[%s:%s:%s]" % (
self.ETypeChar[self.type.value],
ETypeCharMap[self.type.value],
self.universe.value,
self.id,
)
@ -212,6 +175,50 @@ class SteamID(object):
return None
def steam2_to_tuple(value):
match = re.match(r"^STEAM_(?P<universe>[01])"
r":(?P<reminder>[0-1])"
r":(?P<id>\d+)$", value
)
if not match:
return None
steam32 = (int(match.group('id')) << 1) | int(match.group('reminder'))
return (steam32, EType(1), EUniverse(1), 1)
def steam3_to_tuple(value):
typeChars = ''.join(ETypeCharMap.values())
match = re.match(r"^\["
r"(?P<type>[%s]):" # type char
r"(?P<universe>\d+):" # universe
r"(?P<id>\d+)" # accountid
r"(:(?P<instance>\d+))?" # instance
r"\]$" % typeChars, value
)
if not match:
return None
steam32 = int(match.group('id'))
universe = EUniverse(int(match.group('universe')))
inverseETypeCharMap = dict((b, a) for (a, b) in ETypeCharMap.items())
etype = EType(inverseETypeCharMap[match.group('type')])
instance = match.group('instance')
if instance is None:
if etype in (EType.Individual, EType.GameServer):
instance = 1
else:
instance = 0
else:
instance = int(instance)
return (steam32, etype, universe, instance)
def steam64_from_url(url):
"""
Takes a Steam Community url and returns steam64 or None

154
tests/test_steamid.py

@ -3,7 +3,7 @@ import mock
import vcr
from steam import steamid
from steam.steamid import SteamID
from steam.steamid import SteamID, ETypeCharMap
from steam.enums import EType, EUniverse
@ -14,27 +14,40 @@ class SteamID_initialization(unittest.TestCase):
self.assertEqual(obj.universe, test_list[2])
self.assertEqual(obj.instance, test_list[3])
def test_arg_toomany(self):
with self.assertRaises(ValueError):
SteamID(1, 2)
with self.assertRaises(ValueError):
SteamID(1, 2, 3)
with self.assertRaises(ValueError):
SteamID(1, 2, 3, 4)
def test_hash(self):
self.assertEqual(hash(SteamID(1)), hash(SteamID(1)))
self.assertNotEqual(hash(SteamID(12345)), hash(SteamID(8888)))
def test_cmp(self):
self.assertEqual(SteamID(1), SteamID(1))
self.assertTrue(SteamID(2) > SteamID(1))
self.assertTrue(SteamID(2) < SteamID(4))
with self.assertRaises(RuntimeError):
a = SteamID(5) == 5
b = SteamID(5) == '5'
def test_is_valid(self):
self.assertTrue(SteamID(1).is_valid())
self.assertTrue(SteamID(id=5).is_valid())
self.assertFalse(SteamID(0).is_valid())
self.assertFalse(SteamID(-50).is_valid())
self.assertFalse(SteamID(id=1, type=EType.Invalid).is_valid())
self.assertFalse(SteamID(id=1, universe=EUniverse.Invalid).is_valid())
def test_arg_toomany_invalid(self):
self.compare(SteamID(1, 2),
[0, EType.Invalid, EUniverse.Invalid, 0])
self.compare(SteamID(1, 2, 3),
[0, EType.Invalid, EUniverse.Invalid, 0])
self.compare(SteamID(1, 2, 3, 4),
[0, EType.Invalid, EUniverse.Invalid, 0])
######################################################
# 1 ARG
######################################################
def test_arg_number_out_of_range(self):
self.assertRaises(ValueError, SteamID, -1)
self.assertRaises(ValueError, SteamID, '-1')
self.assertRaises(ValueError, SteamID, -5555555)
self.assertRaises(ValueError, SteamID, '-5555555')
self.assertRaises(ValueError, SteamID, 2**64)
self.assertRaises(ValueError, SteamID, str(2**64))
self.assertRaises(ValueError, SteamID, 2**128)
self.assertRaises(ValueError, SteamID, str(2**128))
def test_arg_steam32(self):
self.compare(SteamID(1),
[1, EType.Individual, EUniverse.Public, 1])
@ -74,50 +87,46 @@ class SteamID_initialization(unittest.TestCase):
######################################################
# 1 arg - steam2/steam3 format
######################################################
def test_arg_text_invalid(self):
with self.assertRaises(ValueError):
SteamID("randomtext")
@mock.patch.multiple('steam.steamid',
steam2_to_tuple=mock.DEFAULT,
steam3_to_tuple=mock.DEFAULT,
)
def test_arg_steam2(self, steam2_to_tuple, steam3_to_tuple):
steam2_to_tuple.return_value = (1, 2, 3, 4)
steam3_to_tuple.return_value = (5, 6, 7, 8)
def test_arg_steam2(self):
self.compare(SteamID("STEAM_0:1:1"),
[3, EType.Individual, EUniverse.Public, 1]
)
self.compare(SteamID("STEAM_1:1:1"),
[3, EType.Individual, EUniverse.Public, 1]
)
self.compare(SteamID("STEAM_0:0:4"),
[8, EType.Individual, EUniverse.Public, 1]
)
self.compare(SteamID("STEAM_1:0:4"),
[8, EType.Individual, EUniverse.Public, 1]
)
test_instance = SteamID('STEAM_1:1:1')
def test_arg_steam3(self):
self.compare(SteamID("[U:1:1234]"),
[1234, EType.Individual, EUniverse.Public, 1]
)
self.compare(SteamID("[G:1:1234]"),
[1234, EType.GameServer, EUniverse.Public, 1]
)
self.compare(SteamID("[g:1:4]"),
[4, EType.Clan, EUniverse.Public, 0]
)
self.compare(SteamID("[A:1:4]"),
[4, EType.AnonGameServer, EUniverse.Public, 0]
)
self.compare(SteamID("[A:1:1234:567]"),
[1234, EType.AnonGameServer, EUniverse.Public, 567]
)
steam2_to_tuple.assert_called_once_with('STEAM_1:1:1')
self.assertFalse(steam3_to_tuple.called)
self.compare(test_instance,
[1, 2, 3, 4])
@mock.patch.multiple('steam.steamid',
steam2_to_tuple=mock.DEFAULT,
steam3_to_tuple=mock.DEFAULT,
)
def test_arg_steam3(self, steam2_to_tuple, steam3_to_tuple):
steam2_to_tuple.return_value = None
steam3_to_tuple.return_value = (5, 6, 7, 8)
test_instance = SteamID('[g:1:4]')
steam2_to_tuple.assert_called_once_with('[g:1:4]')
steam3_to_tuple.assert_called_once_with('[g:1:4]')
self.compare(test_instance,
[5, 6, 7, 8])
def test_arg_text_invalid(self):
self.compare(SteamID("invalid_format"),
[0, EType.Invalid, EUniverse.Invalid, 0])
######################################################
# KWARGS
######################################################
def test_kwarg_id(self):
# id kwarg is required always
with self.assertRaises(ValueError):
SteamID(instance=0)
SteamID(id=None)
self.assertEqual(SteamID(id=555).id, 555)
self.assertEqual(SteamID(id='555').id, 555)
@ -254,3 +263,38 @@ class steamid_functions(unittest.TestCase):
sid = steamid.steam64_from_url('https://steamcommunity.com/groups/Valve')
self.assertEqual(sid, '103582791429521412')
def test_arg_steam2(self):
self.assertIsNone(steamid.steam2_to_tuple('invalid_format'))
self.assertEqual(steamid.steam2_to_tuple("STEAM_0:1:1"),
(3, EType.Individual, EUniverse.Public, 1)
)
self.assertEqual(steamid.steam2_to_tuple("STEAM_1:1:1"),
(3, EType.Individual, EUniverse.Public, 1)
)
self.assertEqual(steamid.steam2_to_tuple("STEAM_0:0:4"),
(8, EType.Individual, EUniverse.Public, 1)
)
self.assertEqual(steamid.steam2_to_tuple("STEAM_1:0:4"),
(8, EType.Individual, EUniverse.Public, 1)
)
def test_arg_steam3(self):
self.assertIsNone(steamid.steam3_to_tuple('invalid_format'))
self.assertEqual(steamid.steam3_to_tuple("[U:1:1234]"),
(1234, EType.Individual, EUniverse.Public, 1)
)
self.assertEqual(steamid.steam3_to_tuple("[G:1:1234]"),
(1234, EType.GameServer, EUniverse.Public, 1)
)
self.assertEqual(steamid.steam3_to_tuple("[g:1:4]"),
(4, EType.Clan, EUniverse.Public, 0)
)
self.assertEqual(steamid.steam3_to_tuple("[A:1:4]"),
(4, EType.AnonGameServer, EUniverse.Public, 0)
)
self.assertEqual(steamid.steam3_to_tuple("[A:1:1234:567]"),
(1234, EType.AnonGameServer, EUniverse.Public, 567)
)

Loading…
Cancel
Save