async def init_DB(self): """Initialize the database.""" self.logger.debug("data: preparing to initialize the database.") file_path = (Path() / "talismud.db").absolute() db.bind(provider='sqlite', filename=str(file_path), create_db=True) set_sql_debug(True) db.generate_mapping(create_tables=True) self.logger.debug("data: database initialized.") self.init_task = None #Session.service = self #kredh = await Account.create(username="******", password=b"i", email="*****@*****.**") #kredh = await Account.get(id=1).prefetch_related("session") #session = await Session.first().prefetch_related("account") # Open a DBSession and cached, to be persisted during all the # project lifetime. db_session._enter() # Create the START_ROOM and RETURN_ROOM if they don't exist start_room = return_room = None if db.Room.get(barcode=settings.START_ROOM) is None: start_room = db.Room(barcode=settings.START_ROOM, title="Welcome to TalisMUD!") self.logger.info(f"The start room was created.") if db.Room.get(barcode=settings.RETURN_ROOM) is None: return_room = db.Room(barcode=settings.RETURN_ROOM, title="A grey void") self.logger.info(f"The return room was created.") if start_room or return_room: commit() db.Delay.restore() db.BlueprintRecord.apply_all()
def test_moving_character(self): """Move a character inside and outside of a room.""" character = db.Character(name="test") room1 = db.Room(title="here", barcode="1") self.assertIsNone(character.location) self.assertEqual(room1.contents, []) # Move che character in the room character.location = room1 self.assertIs(character.location, room1) # Check that the room contents contains the character self.assertEqual(room1.contents, [character]) # Move the character in a different room room2 = db.Room(title="there", barcode="2") self.assertEqual(room2.contents, []) character.location = room2 self.assertIs(character.location, room2) self.assertEqual(room1.contents, []) self.assertEqual(room2.contents, [character]) # Finally move the character outside of any room character.location = None self.assertIsNone(character.location) self.assertEqual(room1.contents, []) self.assertEqual(room2.contents, [])
def test_recursion(self): """Test the recursion exception when moving inconsistently.""" character1 = db.Character(name="test") character2 = db.Character(name="test2") character2.location = character1 # Moving character1 into character1 should definitely not work with self.assertRaises(RecursionError): character1.location = character1 self.assertIsNone(character1.location) with self.assertRaises(RecursionError): character1.location = character2 # Should be fobidden self.assertIsNone(character1.location) # Now try to create several objects and a more complicated loop room1 = db.Room(title="There", barcode="1") room2 = db.Room(title="Somewhere else", barcode="2") character2.location = character1 character1.location = room2 room2.location = room1 # room1 contains room2 contains character1 contains character2 # So moving room1 in character2 should now fail with self.assertRaises(RecursionError): room1.location = character2 self.assertIsNone(room1.location)
def apply(self): """Apply the document, create a room.""" room = self.object add_tags = False if room is None: room = db.Room(barcode=self.cleaned.barcode, title=self.cleaned.title) add_tags = True elif room.barcode in (settings.START_ROOM, settings.RETURN_ROOM): # These rooms have already been created automatically, # but make sure we add their blueprint tags add_tags = True else: room.title = self.cleaned.title if add_tags: room.blueprints.add(self.blueprint.name) self.blueprint.objects[room] = self room.x = self.cleaned.x room.y = self.cleaned.y room.z = self.cleaned.z description = self.cleaned.description if description: room.description.set(description) # Add the exits, if possible for exit in list(self.cleaned.exits): try: exit.apply() except DelayMe: self.cleaned.exits.remove(exit) raise DelayDocument(exit)
def test_order(self): """Test that the ordering in content is accurate.""" rooms = [] characters = [] for i in range(5): rooms.append(db.Room(title=f"here_{i}", barcode=str(i))) for i in range(20): characters.append(db.Character(name=f"character_{i}")) # Move characters in rooms for character, room in zip(characters, cycle(rooms)): character.location = room for i, room in enumerate(rooms): present = [character for pos, character in enumerate( characters) if pos % 5 == i] self.assertEqual(room.contents, present)
class ExitHandler: """Exit handler, to interact with room exits.""" def __init__(self, room): self.room = room def __repr__(self): """Return the repr for the room exits.""" exits = Exit.of(self.room) reprs = [] for exit in exits: if exit.origin is self.room: reprs.append(f"<Exit({exit.name})>") else: reprs.append(f"<BackExit({exit.back})>") return repr(reprs) def __iter__(self): return iter(tuple(Exit.of(self.room))) def all(self): """Return all exits.""" return list(Exit.of(self.room)) def has(self, name: str) -> bool: """ Return whether the current room has an exit named like this. Args: name (str): name of the exit to check. The comparison is performed case-insensitive. Returns: exist (bool): whether an exit with this name exists. """ name = name.lower() for exit in self: if exit.name == name: return True return False def link_to( self, destination: 'db.Room', name: str, back: ty.Optional[str] = None, barcode: ty.Optional[str] = "", ) -> ty.Optional['db.Exit']: """ Link the owner room to the specified destination. Both rooms have to exist for this method to work. Neither room should be connected, it would break the exit system if more than one exit linked two rooms. Args: destination (Room): the exit destination. name (str): the exit name. back (str, optional): the name of the back exit, if any. barcode (str, optional): the exit barcode, if any. Returns: exit (Exit or None): the exit if created, None if error. """ origin = self.room if Exit.between(origin, destination): return # Create an exit connected origin to destination return db.Exit(origin=origin, to=destination, name=name, back=back, barcode=barcode) def create_room(self, direction: 'Direction', name: str, destination: str, title: str, back: ty.Optional[str] = None, barcode: ty.Optional[str] = "") -> 'db.Exit': """ Create a room in the specified direction, linking it with an exit. This method is usually the one called to add rooms and exits with no real difficulty. This would fail for several reasons, raise as a `NewRoomError` subclass. Args: direction (DIRECTION): a member of DIRECTION, like DIRECTION.SOUTH or DIRECTION.UP. This is the exit direction and the name of the exit is specified in the next argument. name (str): the exit name. destination (str): the destination's future barcode. This will be the new room's barcode and thus, shouldn't be used already. title (str): the new room's title. back (str, optional): the name of the exit from destination to origin (the back exit). If not set, don't create a back exit. barcode (str, optional): the exit's barcode, a way to uniquely identify the exit. It shouldn't be used by another exit. Returns: exit (Exit): the newly-created exit, if successful. Raises: A subclass of `NewRoomError` to inform the user of several possible errors. This should be intercepted (in a command, probably) and handled to display the error in a user-friendlier way. Possible errors: CoordinatesInUse(x, y, z, room): these coordinates are in use, can't create the destination room. ExitNameInUse(room, name): this exit name is already in use in this room, cannot create it. """ origin = self.room x, y, z = origin.x, origin.y, origin.z # If the coordinates are valid, check the new coordinates if all(value is not None for value in (x, y, z)): x, y, z = direction.shift(x, y, z) # Check fthat the coordinates are free if (dest := db.Room.get(x=x, y=y, z=z)): raise CoordinatesInUse(x, y, z, dest) # Check whether there is no exit of this name yet if self.has(name): raise ExitNameInUse(room, name) # Create a room with these coordinates destination = db.Room(barcode=destination, title=title, x=x, y=y, z=z) # Copy the current blueprints to the new room for blueprint in origin.blueprints.get(): destination.blueprints.add(blueprint.name) exit = self.link_to(destination, name=name, back=back, barcode=barcode) origin.blueprints.save(destination) return exit
def create_room(self, title=None, barcode=None): """Create and return a room.""" title = title or f"room {next(ROOM_TITLE)}" barcode = barcode or f"code {next(ROOM_BARCODE)}" return db.Room(title=title, barcode=barcode)