Merge pull request #6 from joeyahines/new_config

New config
doc_update
Joey Hines 2018-08-30 09:21:21 -05:00 committed by GitHub
commit 29942ac2dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 94 additions and 91 deletions

View File

@ -1,6 +1,5 @@
import codecs import codecs
import configparser import configparser
import os
def create_config(config, path): def create_config(config, path):
@ -29,18 +28,17 @@ def create_config(config, path):
} }
config['Special Names'] = {} config['Special Names'] = {}
with open('{}/GeoffreyConfig.ini'.format(path), 'w') as configfile: with open(path, 'w') as configfile:
config.write(configfile) config.write(configfile)
def read_config(): def read_config(path):
config = configparser.ConfigParser() config = configparser.ConfigParser()
path = os.path.dirname(os.path.abspath(__file__)) try:
config.read_file(codecs.open("{}/GeoffreyConfig.ini".format(path), "r", "utf8")) config.read_file(codecs.open(path, "r", "utf8"))
except FileNotFoundError:
if len(config.sections()) == 0:
create_config(config, path) create_config(config, path)
print("GeoffreyConfig.ini generated.") print("Config generated.")
quit(0) quit(0)
return config return config
@ -48,9 +46,9 @@ def read_config():
class Config: class Config:
def __init__(self): def __init__(self, path):
try: try:
self.config = read_config() self.config = read_config(path)
self.engine_args = self.read_engine_arg() self.engine_args = self.read_engine_arg()
self.token = self.config['Discord']['Token'] self.token = self.config['Discord']['Token']
@ -86,4 +84,6 @@ class Config:
return engine_args.format(driver, username, password, host, port, database_name) return engine_args.format(driver, username, password, host, port, database_name)
bot_config = Config() def get_config(config_path):
return Config(config_path)

View File

@ -2,8 +2,9 @@ from geoffrey.DatabaseInterface import *
class Commands: class Commands:
def __init__(self, engine_args=None): def __init__(self, bot_config, debug=False):
self.interface = DatabaseInterface(engine_args) self.bot_config = bot_config
self.interface = DatabaseInterface(bot_config, debug)
def get_player(self, session, discord_uuid=None, mc_uuid=None): def get_player(self, session, discord_uuid=None, mc_uuid=None):
if discord_uuid is not None: if discord_uuid is not None:
@ -87,7 +88,8 @@ class Commands:
location_name = location_list[0].name location_name = location_list[0].name
tunnel = self.interface.add_tunnel(session, player, tunnel_color, tunnel_number, location_name) tunnel = self.interface.add_tunnel(session, player, tunnel_color, tunnel_number, location_name,
self.bot_config)
tunnel_info = tunnel.__str__() tunnel_info = tunnel.__str__()
finally: finally:
@ -159,7 +161,7 @@ class Commands:
def info(self, location_name): def info(self, location_name):
session = self.interface.database.Session() session = self.interface.database.Session()
try: try:
loc = self.interface.find_location_by_name(session, location_name)[0].full_str() loc = self.interface.find_location_by_name(session, location_name)[0].full_str(self.bot_config)
finally: finally:
session.close() session.close()
@ -231,7 +233,7 @@ class Commands:
location.tunnel.tunnel_direction = TunnelDirection.str_to_tunnel_dir(tunnel_color) location.tunnel.tunnel_direction = TunnelDirection.str_to_tunnel_dir(tunnel_color)
location.tunnel.tunnel_number = tunnel_number location.tunnel.tunnel_number = tunnel_number
else: else:
self.interface.add_tunnel(session, player, tunnel_color, tunnel_number, loc_name) self.interface.add_tunnel(session, player, tunnel_color, tunnel_number, loc_name, self.bot_config)
loc_str = location.__str__() loc_str = location.__str__()
@ -305,7 +307,7 @@ class Commands:
expr = (ItemListing.name == item) & (ItemListing.shop == shop) expr = (ItemListing.name == item) & (ItemListing.shop == shop)
self.interface.database.delete_entry(session, ItemListing, expr) self.interface.database.delete_entry(session, ItemListing, expr)
shop_str = shop.full_str() shop_str = shop.full_str(self.bot_config)
finally: finally:
session.close() session.close()

View File

@ -3,11 +3,8 @@ from geoffrey.DatabaseModels import *
class DatabaseInterface: class DatabaseInterface:
def __init__(self, engine_args=None): def __init__(self, bot_config, debug=False):
if engine_args is None: self.database = GeoffreyDatabase(bot_config, debug)
self.database = GeoffreyDatabase()
else:
self.database = GeoffreyDatabase(engine_args)
def add_base(self, session, owner, name, x_pos, z_pos, dimension=None): def add_base(self, session, owner, name, x_pos, z_pos, dimension=None):
base = Base(name, x_pos, z_pos, owner, dimension) base = Base(name, x_pos, z_pos, owner, dimension)
@ -19,7 +16,7 @@ class DatabaseInterface:
self.database.add_object(session, shop) self.database.add_object(session, shop)
return shop return shop
def add_tunnel(self, session, owner, color, number, location_name): def add_tunnel(self, session, owner, color, number, location_name, config):
tunnels = self.find_tunnel_by_owner(session, owner) tunnels = self.find_tunnel_by_owner(session, owner)
if location_name is None: if location_name is None:
if len(tunnels): if len(tunnels):
@ -36,7 +33,7 @@ class DatabaseInterface:
except IndexError: except IndexError:
raise LocationLookUpError raise LocationLookUpError
tunnel = Tunnel(owner, color, number, location) tunnel = Tunnel(owner, color, number, config, location)
self.database.add_object(session, tunnel) self.database.add_object(session, tunnel)
return tunnel return tunnel

View File

@ -7,7 +7,6 @@ from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, column_property, sessionmaker from sqlalchemy.orm import relationship, column_property, sessionmaker
from sqlalchemy.sql import expression from sqlalchemy.sql import expression
from geoffrey.BotConfig import bot_config
from geoffrey.BotErrors import * from geoffrey.BotErrors import *
from geoffrey.MinecraftAccountInfoGrabber import * from geoffrey.MinecraftAccountInfoGrabber import *
@ -25,8 +24,11 @@ def check_similarity(a, b):
class GeoffreyDatabase: class GeoffreyDatabase:
def __init__(self, engine_args=bot_config.engine_args): def __init__(self, bot_config, debug):
self.engine = create_engine(engine_args, pool_recycle=3600, pool_pre_ping=True) if not debug:
self.engine = create_engine(bot_config.engine_args, pool_recycle=3600, pool_pre_ping=True)
else:
self.engine = create_engine(bot_config.config['SQL']['test_args'], pool_recycle=3600, pool_pre_ping=True)
self.Session = sessionmaker(bind=self.engine) self.Session = sessionmaker(bind=self.engine)
SQL_Base.metadata.create_all(self.engine) SQL_Base.metadata.create_all(self.engine)
@ -83,21 +85,21 @@ class GeoffreyDatabase:
class TunnelDirection(enum.Enum): class TunnelDirection(enum.Enum):
North = bot_config.north_tunnel North = "North"
East = bot_config.east_tunnel East = "East"
South = bot_config.south_tunnel South = "South"
West = bot_config.west_tunnel West = "West"
def str_to_tunnel_dir(arg): def str_to_tunnel_dir(bot_config, arg):
arg = arg.lower() arg = arg.lower()
if check_similarity(TunnelDirection.North.value, arg): if check_similarity(bot_config.north_tunnel, arg):
return TunnelDirection.North return TunnelDirection.North
elif check_similarity(TunnelDirection.East.value, arg): elif check_similarity(bot_config.east_tunnel, arg):
return TunnelDirection.East return TunnelDirection.East
elif check_similarity(TunnelDirection.South.value, arg): elif check_similarity(bot_config.south_tunnel, arg):
return TunnelDirection.South return TunnelDirection.South
elif check_similarity(TunnelDirection.West.value, arg): elif check_similarity(bot_config.west_tunnel, arg):
return TunnelDirection.West return TunnelDirection.West
else: else:
raise InvalidTunnelError raise InvalidTunnelError
@ -149,11 +151,11 @@ class Tunnel(SQL_Base):
location_id = Column(Integer, ForeignKey('geoffrey_locations.id', ondelete='CASCADE')) location_id = Column(Integer, ForeignKey('geoffrey_locations.id', ondelete='CASCADE'))
location = relationship("Location", back_populates="tunnel", lazy="joined") location = relationship("Location", back_populates="tunnel", lazy="joined")
def __init__(self, owner, tunnel_color, tunnel_number, location=None): def __init__(self, owner, tunnel_color, tunnel_number, config, location=None):
try: try:
self.owner = owner self.owner = owner
self.location = location self.location = location
self.tunnel_direction = TunnelDirection.str_to_tunnel_dir(tunnel_color) self.tunnel_direction = TunnelDirection.str_to_tunnel_dir(config, tunnel_color)
self.tunnel_number = tunnel_number self.tunnel_number = tunnel_number
except (ValueError, IndexError): except (ValueError, IndexError):
raise TunnelInitError raise TunnelInitError
@ -206,7 +208,7 @@ class Location(SQL_Base):
except (ValueError, IndexError): except (ValueError, IndexError):
raise LocationInitError raise LocationInitError
def dynmap_link(self): def dynmap_link(self, bot_config):
return '<{}/?worldname={}&mapname=surface&zoom=4&x={}&y=65&z={}>'.\ return '<{}/?worldname={}&mapname=surface&zoom=4&x={}&y=65&z={}>'.\
format(bot_config.dynmap_url, bot_config.world_name, self.x, self.z) format(bot_config.dynmap_url, bot_config.world_name, self.x, self.z)
@ -221,8 +223,8 @@ class Location(SQL_Base):
return "**{}** @ {}, Owner: **{}**, Type: **{}**".format(self.name, self.pos_to_str(), self.owner.name, return "**{}** @ {}, Owner: **{}**, Type: **{}**".format(self.name, self.pos_to_str(), self.owner.name,
self.type) self.type)
def full_str(self): def full_str(self, bot_config):
return self.__str__() + '\n' + self.dynmap_link() return self.__str__() + '\n' + self.dynmap_link(bot_config)
def __str__(self): def __str__(self):
return self.info_str() return self.info_str()
@ -260,8 +262,8 @@ class Shop(Location):
else: else:
return '' return ''
def full_str(self): def full_str(self, bot_config):
return Location.full_str(self) + self.inv_to_str() return Location.full_str(self, bot_config) + self.inv_to_str()
def __str__(self): def __str__(self):
return Location.__str__(self) return Location.__str__(self)

View File

@ -1,7 +1,5 @@
from itertools import zip_longest from itertools import zip_longest
from geoffrey.BotConfig import bot_config
def get_name(args): def get_name(args):
if len(args) > 0: if len(args) > 0:
@ -12,7 +10,7 @@ def get_name(args):
return name return name
def get_nickname(discord_user): def get_nickname(discord_user, bot_config):
if discord_user.nick is None: if discord_user.nick is None:
name = discord_user.display_name name = discord_user.display_name
else: else:

View File

@ -4,12 +4,8 @@ Geoffrey Minecraft Info Database
Created by: Joey Hines (ZeroHD) Created by: Joey Hines (ZeroHD)
""" """
import logging
import logging.handlers as handlers
from sys import stdout
from geoffrey import bot from geoffrey import bot
from geoffrey.BotConfig import bot_config
if __name__ == '__main__': if __name__ == '__main__':
print("Starting bot...") print("Starting bot...")

View File

@ -5,12 +5,11 @@ from discord import Game
from discord.ext import commands from discord.ext import commands
from discord.utils import oauth_url from discord.utils import oauth_url
from sqlalchemy.exc import OperationalError from sqlalchemy.exc import OperationalError
import logging.handlers as handlers import logging.handlers as handlers
from sys import stdout from sys import stdout
from os import path
from geoffrey.BotConfig import *
from geoffrey.BotConfig import bot_config
from geoffrey.BotErrors import * from geoffrey.BotErrors import *
from geoffrey.Commands import Commands from geoffrey.Commands import Commands
from geoffrey.DatabaseModels import Player from geoffrey.DatabaseModels import Player
@ -38,12 +37,10 @@ extensions = ['geoffrey.cogs.Add_Commands',
'geoffrey.cogs.Search_Commands', 'geoffrey.cogs.Search_Commands',
'geoffrey.cogs.Admin_Commands'] 'geoffrey.cogs.Admin_Commands']
bot = commands.Bot(command_prefix=bot_config.prefix, description=description, case_insensitive=True) bot_config = None
bot_commands = None
try: bot = commands.Bot(command_prefix='?', description=description, case_insensitive=True)
bot_commands = Commands()
except OperationalError:
logger.info('Could not connect to MySQL server.')
@bot.event @bot.event
@ -52,7 +49,7 @@ async def on_ready():
info = await bot.application_info() info = await bot.application_info()
url = oauth_url(info.id) url = oauth_url(info.id)
logger.info("Bot url: %s", url) logger.info("Bot url: %s", url)
await bot.change_presence(activity=Game(bot_config.status)) await bot.change_presence(game=Game(name="Geoffrey"))
@bot.event @bot.event
@ -62,7 +59,8 @@ async def on_command(command, ctx):
else: else:
subcommand = ":" + ctx.invoked_subcommand subcommand = ":" + ctx.invoked_subcommand
logger.info("User %s, used command %s%s with context: %s", ctx.message.author, command, subcommand, ctx.args) logger.info("User %s, used command %s%s with context: %s", ctx.message.author, command, subcommand,
ctx.args)
@bot.event @bot.event
@ -101,13 +99,15 @@ async def on_command_error(error, ctx):
return return
if error_str is None: if error_str is None:
await send_error_message('Geoffrey encountered unhandled exception: {}. Context:'.format(error, ctx.args)) await send_error_message(
'Geoffrey encountered unhandled exception: {}. Context:'.format(error, ctx.args))
logger.error("Geoffrey encountered unhandled exception: %s", error) logger.error("Geoffrey encountered unhandled exception: %s", error)
error_str = bad_error_message.format(ctx.invoked_with) error_str = bad_error_message.format(ctx.invoked_with)
await bot.send_message(ctx.message.channel, '{} **Error Running Command:** {}'.format(ctx.message.author.mention, await bot.send_message(ctx.message.channel,
error_str)) '{} **Error Running Command:** {}'.format(ctx.message.author.mention,
error_str))
async def send_error_message(msg): async def send_error_message(msg):
@ -116,6 +116,7 @@ async def send_error_message(msg):
await bot.send_message(user, msg) await bot.send_message(user, msg)
async def username_update(): async def username_update():
await bot.wait_until_ready() await bot.wait_until_ready()
while not bot.is_closed: while not bot.is_closed:
@ -140,7 +141,8 @@ async def username_update():
session.close() session.close()
await asyncio.sleep(600) await asyncio.sleep(600)
def setup_logging():
def setup_logging(config):
discord_logger = logging.getLogger('discord') discord_logger = logging.getLogger('discord')
discord_logger.setLevel(logging.INFO) discord_logger.setLevel(logging.INFO)
@ -150,7 +152,7 @@ def setup_logging():
bot_info_logger.setLevel(logging.INFO) bot_info_logger.setLevel(logging.INFO)
handler = handlers.TimedRotatingFileHandler(filename='Geoffrey.log', when='D', handler = handlers.TimedRotatingFileHandler(filename='Geoffrey.log', when='D',
interval=bot_config.rotation_duration, backupCount=bot_config.count, interval=config.rotation_duration, backupCount=config.count,
encoding='utf-8') encoding='utf-8')
handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')) handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s'))
@ -165,19 +167,24 @@ def setup_logging():
bot_info_logger.addHandler(console) bot_info_logger.addHandler(console)
def start_bot(): def start_bot(config_path="{}/GeoffreyConfig.ini".format(path.dirname(path.abspath(__file__)))):
try: try:
setup_logging() global bot_config, bot_commands
Commands() bot_config = get_config(config_path)
setup_logging(bot_config)
bot_commands = Commands(bot_config)
for extension in extensions: for extension in extensions:
try: try:
bot.load_extension(extension) bot.load_extension(extension)
except Exception as e: except Exception as e:
logger.info('Failed to load extension {}'.format(extension)) logger.info('Failed to load extension {}'.format(extension))
raise e raise e
bot.loop.create_task(username_update())
logger.info('Logging into Discord...') logger.info('Logging into Discord...')
bot.run(bot_config.token) bot.run(bot_config.token)
except KeyboardInterrupt: except KeyboardInterrupt:
logger.info("Bot received keyboard interrupt") logger.info("Bot received keyboard interrupt")
except Exception as e: except Exception as e:

View File

@ -2,7 +2,7 @@ from discord.ext import commands
from geoffrey.BotErrors import * from geoffrey.BotErrors import *
from geoffrey.DiscordHelperFunctions import * from geoffrey.DiscordHelperFunctions import *
from geoffrey.bot import bot_commands from geoffrey.bot import bot_commands, bot_config
@commands.cooldown(5, 60, commands.BucketType.user) @commands.cooldown(5, 60, commands.BucketType.user)
@ -24,7 +24,7 @@ class Add_Commands:
""" """
try: try:
player_name = get_nickname(ctx.message.author) player_name = get_nickname(ctx.message.author, bot_config)
bot_commands.register(player_name, ctx.message.author.id) bot_commands.register(player_name, ctx.message.author.id)
await self.bot.say('{}, you have been added to the database.'.format(ctx.message.author.mention)) await self.bot.say('{}, you have been added to the database.'.format(ctx.message.author.mention))
except AttributeError: except AttributeError:

View File

@ -1,9 +1,8 @@
from discord import Game from discord import Game
from discord.ext import commands from discord.ext import commands
from geoffrey.BotConfig import bot_config
from geoffrey.BotErrors import * from geoffrey.BotErrors import *
from geoffrey.bot import bot_commands from geoffrey.bot import bot_commands, bot_config
def check_mod(user): def check_mod(user):

View File

@ -2,7 +2,7 @@ from discord.ext import commands
from geoffrey.BotErrors import * from geoffrey.BotErrors import *
from geoffrey.DiscordHelperFunctions import * from geoffrey.DiscordHelperFunctions import *
from geoffrey.bot import bot_commands from geoffrey.bot import bot_commands, bot_config
class Delete_Commands: class Delete_Commands:

View File

@ -2,7 +2,7 @@ from discord.ext import commands
from geoffrey.BotErrors import * from geoffrey.BotErrors import *
from geoffrey.DiscordHelperFunctions import * from geoffrey.DiscordHelperFunctions import *
from geoffrey.bot import bot_commands from geoffrey.bot import bot_commands, bot_config
class Edit_Commands: class Edit_Commands:

View File

@ -2,7 +2,7 @@ from discord.ext import commands
from geoffrey.BotErrors import * from geoffrey.BotErrors import *
from geoffrey.DiscordHelperFunctions import * from geoffrey.DiscordHelperFunctions import *
from geoffrey.bot import bot_commands from geoffrey.bot import bot_commands, bot_config
class Search_Commands: class Search_Commands:

View File

@ -1,12 +1,13 @@
from unittest import TestCase from unittest import TestCase
from Commands import * from Commands import *
from BotConfig import get_config
class TestCommands(TestCase): class TestCommands(TestCase):
def setUp(self): def setUp(self):
self.bot_config = get_config()
self.commands = Commands(bot_config.config['SQL']['test_args']) self.commands = Commands(self.bot_config, True)
self.session = self.commands.interface.database.Session() self.session = self.commands.interface.database.Session()
self.commands.interface.database.clear_all(self.session) self.commands.interface.database.clear_all(self.session)
self.session.close() self.session.close()
@ -49,13 +50,13 @@ class TestCommands(TestCase):
self.commands.register('ZeroHD', '143072699567177728') self.commands.register('ZeroHD', '143072699567177728')
self.commands.add_shop(0, 0, shop_name='test shop', discord_uuid='143072699567177728') self.commands.add_shop(0, 0, shop_name='test shop', discord_uuid='143072699567177728')
tunnel2 = self.commands.add_tunnel(bot_config.east_tunnel, 50, location_name='test_shop', tunnel2 = self.commands.add_tunnel(self.bot_config.east_tunnel, 50, location_name='test_shop',
discord_uuid='143072699567177728') discord_uuid='143072699567177728')
if bot_config.east_tunnel not in tunnel2: if self.bot_config.east_tunnel not in tunnel2:
self.fail() self.fail()
self.assertRaises(LocationHasTunnelError, self.commands.add_tunnel, bot_config.east_tunnel, 50, self.assertRaises(LocationHasTunnelError, self.commands.add_tunnel, self.bot_config.east_tunnel, 50,
location_name='test_shop', discord_uuid='143072699567177728') location_name='test_shop', discord_uuid='143072699567177728')
def test_find(self): def test_find(self):
@ -126,11 +127,11 @@ class TestCommands(TestCase):
self.commands.register('ZeroHD', '143072699567177728') self.commands.register('ZeroHD', '143072699567177728')
self.commands.add_shop(0, 0, shop_name='frick', discord_uuid='143072699567177728') self.commands.add_shop(0, 0, shop_name='frick', discord_uuid='143072699567177728')
self.commands.add_tunnel(bot_config.north_tunnel, 50, location_name='frick', discord_uuid='143072699567177728') self.commands.add_tunnel(self.bot_config.north_tunnel, 50, location_name='frick', discord_uuid='143072699567177728')
result = self.commands.info('frick') result = self.commands.info('frick')
if bot_config.north_tunnel in result: if self.bot_config.north_tunnel in result:
pass pass
else: else:
self.fail() self.fail()
@ -139,11 +140,11 @@ class TestCommands(TestCase):
self.commands.register('ZeroHD', '143072699567177728') self.commands.register('ZeroHD', '143072699567177728')
self.commands.add_shop(0, 0, shop_name='test shop', discord_uuid='143072699567177728') self.commands.add_shop(0, 0, shop_name='test shop', discord_uuid='143072699567177728')
self.commands.add_tunnel(bot_config.south_tunnel, 50, None, discord_uuid='143072699567177728') self.commands.add_tunnel(self.bot_config.south_tunnel, 50, None, discord_uuid='143072699567177728')
result = self.commands.tunnel('ZeroHD') result = self.commands.tunnel('ZeroHD')
if bot_config.south_tunnel in result: if self.bot_config.south_tunnel in result:
pass pass
else: else:
self.fail() self.fail()
@ -190,11 +191,11 @@ class TestCommands(TestCase):
self.commands.register('ZeroHD', '143072699567177728') self.commands.register('ZeroHD', '143072699567177728')
self.commands.add_shop(0, 0, shop_name='test shop', discord_uuid='143072699567177728') self.commands.add_shop(0, 0, shop_name='test shop', discord_uuid='143072699567177728')
self.commands.edit_tunnel(bot_config.east_tunnel, 500, 'test shop', discord_uuid='143072699567177728') self.commands.edit_tunnel(self.bot_config.east_tunnel, 500, 'test shop', discord_uuid='143072699567177728')
result = self.commands.info('test shop') result = self.commands.info('test shop')
if bot_config.east_tunnel in result: if self.bot_config.east_tunnel in result:
pass pass
else: else:
self.fail() self.fail()

View File

@ -1,17 +1,18 @@
from unittest import TestCase from unittest import TestCase
from DatabaseInterface import * from DatabaseInterface import *
from BotConfig import *
class TestGeoffreyDatabase(TestCase): class TestGeoffreyDatabase(TestCase):
def setUp(self): def setUp(self):
self.interface = DatabaseInterface(bot_config.config['SQL']['test_args']) self.config = get_config()
self.interface = DatabaseInterface(self.config, debug=True)
self.session = self.interface.database.Session() self.session = self.interface.database.Session()
self.interface.database.clear_all(self.session) self.interface.database.clear_all(self.session)
self.owner = Player('ZeroHD', '143072699567177728') self.owner = Player('ZeroHD', '143072699567177728')
self.loc = Location('test', 1, 3, self.owner, dimension='Nether') self.loc = Location('test', 1, 3, self.owner, dimension='Nether')
self.tunnel = Tunnel(self.owner, bot_config.west_tunnel, 105, self.loc) self.tunnel = Tunnel(self.owner, self.config.west_tunnel, 105, self.config, self.loc)
def tearDown(self): def tearDown(self):
self.session.commit() self.session.commit()
@ -90,7 +91,7 @@ class TestGeoffreyDatabase(TestCase):
def test_add_tunnel(self): def test_add_tunnel(self):
player = self.add_player() player = self.add_player()
tunnel1 = self.interface.add_tunnel(self.session, player, bot_config.south_tunnel, 155, None) tunnel1 = self.interface.add_tunnel(self.session, player, self.config.south_tunnel, 155, None, self.config)
tunnel2 = self.interface.find_tunnel_by_owner_name(self.session, 'ZeroHD')[0] tunnel2 = self.interface.find_tunnel_by_owner_name(self.session, 'ZeroHD')[0]
self.assertEqual(tunnel1, tunnel2) self.assertEqual(tunnel1, tunnel2)