def handle_inspect(**kwargs): """ Handle inspect actions. Args: **kwargs (dict): Arguments """ default_args = { 'input': None } default_args.update(kwargs) args = dict_to_namedtuple(default_args) # split input path dirname, basename = os.path.split(unicode(args.input)) # open input filesystem try: in_fs = OSFS(dirname) if in_fs.isfile(basename): inspect_file(in_fs.getsyspath(basename)) elif in_fs.isdir(basename): inspect_dir(in_fs.opendir(basename)) except CreateFailed: console.error('Input {} does not exist.'.format(args.input)) return
def main(): parser = argparse.ArgumentParser(description='Create free editor.slf') parser.add_argument('original', help="Original editor.slf") parser.add_argument( '-o', '--output', default='build/editor.slf', help="Where to store the created slf file" ) args = parser.parse_args() if not os.path.exists(os.path.dirname(args.output)): os.makedirs(os.path.dirname(args.output)) target_fs = BufferedSlfFS() replacement_fs = OSFS('editor') with open(args.original, 'rb') as source_file: source_fs = SlfFS(source_file) target_fs.library_name = source_fs.library_name target_fs.library_path = source_fs.library_path target_fs.version = source_fs.version target_fs.sort = source_fs.sort for directory in source_fs.walkdirs(): if directory == '/': continue target_fs.makedir(directory) for file in source_fs.walkfiles(): base_name, _ = os.path.splitext(file) with source_fs.open(file, 'rb') as source, target_fs.open(file, 'wb') as target: ja2_images = load_8bit_sti(source) replacement_path = base_name + '.gif' replacement_file_exists = replacement_fs.isfile(replacement_path) replacement_dir = file replacement_dir_exists = replacement_fs.isdir(replacement_dir) if len(ja2_images) == 1 and replacement_file_exists: print("Replacing {0} with {1}".format(file, replacement_path)) replacement_img = Image.open(replacement_fs.open(replacement_path, 'rb')) ja2_images._palette = replacement_img.palette ja2_images.images[0]._image = replacement_img elif len(ja2_images) > 1 and replacement_dir_exists: for i in range(len(ja2_images)): replacement_path = replacement_dir + '/{}.gif'.format(i) print("Replacing {0} with {1}".format(file, replacement_path)) replacement_img = Image.open(replacement_fs.open(replacement_path, 'rb')) ja2_images._palette = replacement_img.palette ja2_images.images[i]._image = replacement_img else: print("Replacing {0} with nothingness".format(file)) for sub_image in ja2_images.images: width, height = sub_image.image.size sub_image._image = Image.new('P', (width, height), color=54) save_8bit_sti(ja2_images, target) with open(args.output, 'wb') as target_file: target_fs.save(target_file)
def eggifySingle(srcFS, src, destFS, dest, config=None): """ Eggify single source to single destination. Args: src (basestring) dest (basestring) Raises: MissingDestinationException """ if dest is None: raise MissingDestinationException() if config is None: config = {} if src.startswith("/") or src[1] == ":": head, tail = os.path.split(src) srcFS = OSFS(head) src = tail if srcFS.isfile(unicode(src)): assertFS(destFS.getsyspath(unicode(dest))) workingDir = srcFS.getsyspath(unicode("/")) devnull = open(os.devnull, 'w') cmd = ["python", src, "bdist_egg"] if "purge" in config.keys() and config["purge"]: cmd.append("--exclude-source-files") subprocess.check_call(cmd, cwd=workingDir, stdout=devnull, stderr=devnull) if srcFS.isdir(unicode("dist")): distFS = srcFS.opendir(unicode("dist")) for name in reversed(sorted(distFS.listdir("/"))): if name.endswith(".egg"): destEggFS = destFS.opendir(unicode(dest)) # remove existing eggs removeOldEggs(destEggFS, name) eggSrcPath = distFS.getsyspath(unicode(name)) eggDestPath = destEggFS.getsyspath(unicode(name)) copy_file(distFS, unicode(name), destEggFS, unicode(name)) print "copied {} to {}".format(eggSrcPath, eggDestPath) break
def handle_preview(**kwargs): """ Handle preview actions. Args: **kwargs (dict): Arguments """ default_args = { 'input': None, 'output': None, 'prefix': None, 'layer': None, 'num_threads': None, 'multithreading': 1 } default_args.update(kwargs) args = dict_to_namedtuple(default_args) # open output filesystem out_fs = assure_fs(args.output) # join layer layer = None if args.layer: layer = ' '.join(args.layer) # split input path dirname, basename = os.path.split(unicode(args.input)) # open input filesystem try: in_fs = OSFS(dirname) if in_fs.isfile(basename): filename, extension = os.path.splitext(basename) # prepend prefix to filename if args.prefix: filename = args.prefix + filename out_name = unicode(filename + '.jpg') preview_file(in_fs.getsyspath(basename), out_fs.getsyspath(out_name), layer) elif in_fs.isdir(basename): preview_dir(in_fs.opendir(basename), out_fs, args.num_threads, bool(args.multithreading), prefix=args.prefix, layer=layer) except CreateFailed: console.error('Input {} does not exist.'.format(args.input)) return
def application(environ, start_response): fs = OSFS(join(dirname(__file__), "static")) path = environ["PATH_INFO"] if path in ("", "/"): path = "index.html" if path == "/getbbcode": bbcode = unicode(environ["wsgi.input"].read(), 'utf-8') html = render_bbcode(bbcode, clean=True, paragraphs=True, render_unknown_tags=True) start_response("200 OK", [("Content-type", "text/html; charset=utf-8")]) return [html.encode("utf-8")] mime_type, _encoding = mimetypes.guess_type(basename(path)) if not fs.isfile(path): start_response("404 NOT FOUND", []) return ["Nobody here but us chickens: %s" % path] start_response("200 OK", [("Content-type", mime_type)]) return [fs.getcontents(path)]
def main(): parser = argparse.ArgumentParser(description='Create free editor.slf') parser.add_argument('--original', help="Original editor.slf") parser.add_argument('-o', '--output', default='build/editor.slf', help="Where to store the created slf file") parser.add_argument('--name', help="Library name") args = parser.parse_args() if not os.path.exists(os.path.dirname(args.output)): os.makedirs(os.path.dirname(args.output)) if args.original is None: target_fs = create_free_editorslf(args.name) with open(args.output, 'wb') as target_file: target_fs.save(target_file) generate_md5_file(args.output) return # create editor.slf by replacing images in the original editor.slf target_fs = BufferedSlfFS() replacement_fs = OSFS('editor') with open(args.original, 'rb') as source_file: source_fs = SlfFS(source_file) target_fs.library_name = args.name or source_fs.library_name target_fs.library_path = source_fs.library_path target_fs.version = source_fs.version target_fs.sort = source_fs.sort for directory in source_fs.walkdirs(): if directory == '/': continue target_fs.makedir(directory) for file in source_fs.walkfiles(): base_name, _ = os.path.splitext(file) with source_fs.open(file, 'rb') as source, target_fs.open( file, 'wb') as target: ja2_images = load_8bit_sti(source) replacement_path = base_name + '.gif' replacement_file_exists = replacement_fs.isfile( replacement_path) replacement_dir = file replacement_dir_exists = replacement_fs.isdir(replacement_dir) if len(ja2_images) == 1 and replacement_file_exists: print("Replacing {0} with {1}".format( file, replacement_path)) replacement_img = Image.open( replacement_fs.open(replacement_path, 'rb')) ja2_images._palette = replacement_img.palette ja2_images.images[0]._image = replacement_img elif len(ja2_images) > 1 and replacement_dir_exists: for i in range(len(ja2_images)): replacement_path = replacement_dir + '/{}.gif'.format( i) print("Replacing {0} with {1}".format( file, replacement_path)) replacement_img = Image.open( replacement_fs.open(replacement_path, 'rb')) ja2_images._palette = replacement_img.palette ja2_images.images[i]._image = replacement_img else: print("Replacing {0} with nothingness".format(file)) for sub_image in ja2_images.images: width, height = sub_image.image.size sub_image._image = Image.new('P', (width, height), color=54) save_8bit_sti(ja2_images, target) with open(args.output, 'wb') as target_file: target_fs.save(target_file) generate_md5_file(args.output)
class TestDatasetManager(unittest.TestCase): trash_dir = "./tests/resources/trash_data" def setUp(self): self.os = OSFS(".") def tearDown(self): for data in self.os.listdir(self.trash_dir): if data != ".keep": self.os.remove("{}/{}".format(self.trash_dir, data)) self.os.close() def test_should_read_yaml_from_dir(self): expected = { "one_test": { "source": "http://source/teste", "description": "my little dataset" } } data = DatasetManager("./tests/resources/one_data") self.assertDictEqual(data.get_datasets(), expected) def test_should_read_multiple_yaml_from_dir(self): expected = { "one_test": { "source": "https://raw.githubusercontent.com/pcsanwald/kaggle-titanic/master/train.csv", "description": "my little dataset" }, "two_test": { "source": "https://raw.githubusercontent.com/pcsanwald/kaggle-titanic/master/train.csv", "description": "my little dataset 2" } } data = DatasetManager("./tests/resources/multiple_data", fs=self.os) result = list(data.get_datasets().keys()) result.sort() expected = ["one_test", "two_test"] self.assertListEqual(expected, result) def test_should_get_dataset(self): data = DatasetManager("./tests/resources/local_data") dataset = { "local_test": { "source": "./tests/resources/local_data/train.csv", "description": "my little dataset local" } } self.assertDictEqual(data.get_dataset("local_test"), dataset.get("local_test")) def test_should_get_dataset_unknown(self): data = DatasetManager("./tests/resources/local_data") with self.assertRaises(IOError): data.get_dataset("unknown_test") def test_should_create_dataset(self): data = DatasetManager(self.trash_dir, fs=self.os) identifier = "data_name" dataset = { "identifier": identifier, "description": "description", "source": "/tmp/test.csv", } data.create_dataset(**dataset) loaded_datasets = data.get_datasets() dataset_config = loaded_datasets.get(identifier) self.assertTrue( self.os.isfile("{}/{}.yaml".format(self.trash_dir, identifier))) self.assertEqual(len(self.os.listdir(self.trash_dir)), 2) self.assertEqual(list(loaded_datasets.keys())[0], identifier) self.assertEqual(dataset_config.get("description"), dataset["description"]) self.assertEqual(dataset_config.get("source"), dataset["source"]) def test_should_create_dataset_with_custom_data(self): data = DatasetManager(self.trash_dir, fs=self.os) identifier = "data_name_custom" dataset = { "identifier": identifier, "description": "description", "source": "/tmp/test.csv" } data.create_dataset(**dataset) self.assertTrue( self.os.isfile("{}/{}.yaml".format(self.trash_dir, identifier))) self.assertEqual(len(os.listdir(self.trash_dir)), 2) loaded_dataset = data.get_datasets() self.assertEqual(list(loaded_dataset.keys()), [identifier]) datasource_configs = loaded_dataset.get(identifier) self.assertEqual(datasource_configs["description"], dataset["description"]) self.assertEqual(datasource_configs["source"], dataset["source"]) def test_should_remove_dataset(self): data = DatasetManager(self.trash_dir, fs=self.os) identifier = "data_name" dataset = { "identifier": identifier, "description": "description", "source": "/tmp/test.csv" } data.create_dataset(**dataset) self.assertTrue( os.path.isfile("{}/{}.yaml".format(self.trash_dir, identifier))) self.assertEqual(len(os.listdir(self.trash_dir)), 2) data.remove_dataset(identifier) self.assertFalse( os.path.isfile("{}/{}.yaml".format(self.trash_dir, identifier))) self.assertEqual(len(os.listdir(self.trash_dir)), 1) def test_should_remove_unknown_dataset(self): data = DatasetManager("./tests/resources/local_data", fs=self.os) with self.assertRaises(IOError): data.remove_dataset("unknown_dataset")
def handle_rechannel(**kwargs): """ Handle rechannel actions. Args: **kwargs (dict): Arguments """ default_args = { 'input': None, 'output': None, 'prefix': None, 'map': None, 'num_threads': None, 'multithreading': 1 } default_args.update(kwargs) args = dict_to_namedtuple(default_args) # open output filesystem out_fs = assure_fs(args.output) # split map path dirname, basename = os.path.split(unicode(args.map)) try: map_fs = OSFS(dirname) if map_fs.isfile(basename): with map_fs.open(basename) as file_handle: try: layer_map = json.loads(file_handle.read()) except Exception as error: console.error(error) return else: console.error('Map {} does not exist.'.format(args.map)) return except CreateFailed: console.error('Map parent directory {} does not exist.'.format(args.map)) return # split input path dirname, basename = os.path.split(unicode(args.input)) # open input filesystem try: in_fs = OSFS(dirname) if in_fs.isfile(basename): # prepend prefix to basename if args.prefix: basename = args.prefix + basename rechannel_file(in_fs.getsyspath(basename), out_fs.getsyspath(basename), layer_map) elif in_fs.isdir(basename): rechannel_dir(in_fs.opendir(basename), out_fs, layer_map, args.num_threads, bool(args.multithreading), prefix=args.prefix) except CreateFailed: console.error('Input {} does not exist.'.format(args.input)) return
class VirtualHost(object): """ Represents a single host. This class implements the commands that are host-specific, like pwd, ls, etc. """ def __init__(self, params, network, fs_dir): self.hostname = params['hostname'] self.ip_address = params['ip_address'] self.network = network self.env = params['env'] valid_ips = map(str, network[1:-1]) if self.ip_address is None: logger.error( 'IP address for {} is not specified in the config file (or is "null")' .format(self.hostname)) if not self._set_ip_from_previous_run(fs_dir, valid_ips): self.ip_address = get_random_item(valid_ips) logger.info('Assigned random IP {} to host {}'.format( self.ip_address, self.hostname)) else: if not self.ip_address in valid_ips: logger.error( 'IP Address {} for {} is not valid for the specified network' .format(params['ip_address'], self.hostname)) if not self._set_ip_from_previous_run(fs_dir, valid_ips): self.ip_address = get_random_item(valid_ips) logger.info('Assigned random IP {} to host {}'.format( self.ip_address, self.hostname)) self.valid_logins = params['valid_logins'] self.logged_in = False self.current_user = None if params.get('default', False): self.default = True else: self.default = False self.filesystem = OSFS(os.path.join( fs_dir, '{}_{}'.format(self.hostname, self.ip_address)), create=True) self.working_path = '/' def authenticate(self, username, password): if self.valid_logins.get(username, None) == password: return True return False def login(self, username): logger.debug('User "{}" has logged into "{}" host'.format( username, self.hostname)) self.logged_in = True self.current_user = username def logout(self): self.logged_in = False self.current_user = None @property def welcome(self): if self.filesystem.isfile('/etc/motd'): with self.filesystem.open('/etc/motd') as motd_file: return motd_file.read() else: return 'Welcome to {} server.'.format(self.hostname) @property def prompt(self): prompt = '{}@{}:{}$ '.format(self.current_user, self.hostname, self.working_path) return prompt def run_echo(self, params, shell): if not params: shell.writeline('') elif params[0].startswith('$') and len(params) == 1: var_name = params[0][1:] value = self.env.get(var_name, '') shell.writeline(value) elif '*' in params: params.remove('*') params.extend(self.filesystem.listdir()) shell.writeline(' '.join(params)) else: shell.writeline(' '.join(params)) def run_pwd(self, params, shell): if params: shell.writeline('pwd: too many arguments') else: shell.writeline('{}'.format(self.working_path)) def run_wget(self, params, shell): parser = Parser(add_help=False) parser.add_argument('-h', '--help', action='store_true', default=False) parser.add_argument('-V', '--version', action='store_true', default=False) parser.add_argument('-O', '--output-document') args, unparsed = parser.parse_known_args(params) if unparsed: url = unparsed[0] elif not args.help and not args.version: noparam_file_path = os.path.join(os.path.dirname(hornet.__file__), 'data', 'commands', 'wget', 'no_param') self.send_data_from_file(noparam_file_path, shell) return if args.help: help_file_path = os.path.join(os.path.dirname(hornet.__file__), 'data', 'commands', 'wget', 'help') self.send_data_from_file(help_file_path, shell) return if args.version: version_file_path = os.path.join(os.path.dirname(hornet.__file__), 'data', 'commands', 'wget', 'version') self.send_data_from_file(version_file_path, shell) return wget_command = WgetCommand(url, self.working_path, self.filesystem, args, shell) wget_command.process() def run_ping(self, params, shell): options = [x for x in params if x.startswith('-')] if '-h' in options or len(params) == 0: help_file_path = os.path.join(os.path.dirname(hornet.__file__), 'data', 'commands', 'ping', 'help') self.send_data_from_file(help_file_path, shell) return filtered_params = [p for p in params if not p.startswith('-')] ping_host = filtered_params[-1] logger.debug('Going to ping {}'.format(ping_host)) ping_command = PingCommand(ping_host, shell) ping_command.process() def run_ifconfig(self, params, shell): if len(params) >= 2: shell.writeline('SIOCSIFFLAGS: Operation not permitted') return if params: parameter = params[0] if parameter == '--version': version_file_path = os.path.join( os.path.dirname(hornet.__file__), 'data', 'commands', 'ifconfig', 'version') self.send_data_from_file(version_file_path, shell) logger.debug( 'Sending version string for ifconfig from {} file'.format( version_file_path)) return elif parameter == '--help' or parameter == '-h': help_file_path = os.path.join(os.path.dirname(hornet.__file__), 'data', 'commands', 'ifconfig', 'help') self.send_data_from_file(help_file_path, shell) logger.debug( 'Sending version string for ifconfig from {} file'.format( help_file_path)) return output_template_path = os.path.join(os.path.dirname(hornet.__file__), 'data', 'commands', 'ifconfig', 'output_template') ifconfig_command = IfconfigCommand(params, output_template_path, self.ip_address, self.network) output = ifconfig_command.process() shell.writeline(output) def run_ls(self, params, shell): paths = [] other_params = [] for p in params: if p.startswith('-'): other_params.append(p) else: paths.append(p) if not paths: # List contents of working dir by default paths.append(self.working_path) parser = Parser(add_help=False) parser.add_argument('-a', '--all', action='store_true', default=False) parser.add_argument('-A', '--almost-all', action='store_true', default=False) parser.add_argument('-d', '--directory', action='store_true', default=False) parser.add_argument('-l', action='store_true', default=False) # We ignore these (for now), but still parse them ;-) parser.add_argument('-h', '--human-readable', action='store_true', default=False) parser.add_argument('-b', '--escape', action='store_true', default=False) parser.add_argument('--block-size') parser.add_argument('-B', '--ignore-backups', action='store_true', default=False) parser.add_argument('-c', action='store_true', default=False) parser.add_argument('-C', action='store_true', default=False) parser.add_argument('--color') parser.add_argument('-D', '--dired', action='store_true', default=False) parser.add_argument('-f', action='store_true', default=False) parser.add_argument('-F', '--classify', action='store_true', default=False) parser.add_argument('--file-type', action='store_true', default=False) parser.add_argument('--format') parser.add_argument('--full-time', action='store_true', default=False) parser.add_argument('-g', action='store_true', default=False) parser.add_argument('--group-directories-first', action='store_true', default=False) parser.add_argument('-G', '--no-group', action='store_true', default=False) parser.add_argument('-H', '--dereference-command-line', action='store_true', default=False) parser.add_argument('--dereference-command-line-symlink-to-dir', action='store_true', default=False) parser.add_argument('--hide') parser.add_argument('--indicator-style') parser.add_argument('-i', '--inode', action='store_true', default=False) parser.add_argument('-I', '--ignore') parser.add_argument('-k', '--kibibytes', action='store_true', default=False) parser.add_argument('-L', '--deference', action='store_true', default=False) parser.add_argument('-m', action='store_true', default=False) parser.add_argument('-n', '--numeric-uid-gid', action='store_true', default=False) parser.add_argument('-N', '--literal', action='store_true', default=False) parser.add_argument('-o', action='store_true', default=False) parser.add_argument('-p', action='store_true', default=False) parser.add_argument('-q', '--hide-control-chars', action='store_true', default=False) parser.add_argument('--show-control-chars', action='store_true', default=False) parser.add_argument('-Q', '--quote-name', action='store_true', default=False) parser.add_argument('--quoting-style') parser.add_argument('-r', '--reverse', action='store_true', default=False) parser.add_argument('-R', '--recursive', action='store_true', default=False) parser.add_argument('-s', '--size', action='store_true', default=False) parser.add_argument('-S', action='store_true', default=False) parser.add_argument('--sort') parser.add_argument('--time') parser.add_argument('--time-style') parser.add_argument('-t', action='store_true', default=False) parser.add_argument('-T', '--tabsize', default=False) parser.add_argument('-u', action='store_true', default=False) parser.add_argument('-U', action='store_true', default=False) parser.add_argument('-v', action='store_true', default=False) parser.add_argument('-w', '--width') parser.add_argument('-x', action='store_true', default=False) parser.add_argument('-X', action='store_true', default=False) parser.add_argument('-1', dest='one_per_line', action='store_true', default=False) parser.add_argument('--help', action='store_true', default=False) parser.add_argument('--version', action='store_true', default=False) try: args = parser.parse_args(other_params) except ParseError: shell.writeline('ls: invalid options: \"{}\"'.format( ' '.join(params))) shell.writeline('Try \'ls --help\' for more information.') return if args.help: help_file_path = os.path.join(os.path.dirname(hornet.__file__), 'data', 'commands', 'ls', 'help') logger.debug( 'Sending help string from file {}'.format(help_file_path)) self.send_data_from_file(help_file_path, shell) return if args.version: version_file_path = os.path.join(os.path.dirname(hornet.__file__), 'data', 'commands', 'ls', 'version') logger.debug('Sending version string from file {}'.format( version_file_path)) self.send_data_from_file(version_file_path, shell) return ls_cmd = LsCommand(args, paths, self.filesystem, self.working_path) output = ls_cmd.process() shell.writeline(output) def run_cd(self, params, shell): if len(params) == 0: params = ['/'] cd_path = os.path.join(self.working_path, params[0]) new_path_exists = False try: new_path_exists = self.filesystem.exists(cd_path) except BackReferenceError as e: logger.warn('Access to the external file system was attempted.') cd_path = '/' new_path_exists = True finally: if not new_path_exists: shell.writeline('cd: {}: No such file or directory'.format( params[0])) else: self.working_path = os.path.normpath(cd_path) logger.debug( 'Working directory for host {} changed to {}'.format( self.hostname, self.working_path)) def run_uname(self, params, shell): if not params: shell.writeline('Linux') return buff = '' info = [ 'Linux', self.hostname, '3.13.0-37-generic', '#64-Ubuntu SMP Mon Sep 22 21:30:01 UTC 2014', 'i686', 'i686', 'i686', 'GNU/Linux' ] parser = Parser(add_help=False) parser.add_argument('-a', '--all', default=False, action='store_true') parser.add_argument('-s', '--kernel-name', default=False, action='store_true') parser.add_argument('-n', '--nodename', default=False, action='store_true') parser.add_argument('-r', '--kernel-release', default=False, action='store_true') parser.add_argument('-v', '--kernel-version', default=False, action='store_true') parser.add_argument('-m', '--kernel-machine', default=False, action='store_true') parser.add_argument('-p', '--processor', default=False, action='store_true') parser.add_argument('-i', '--hardware-platform', default=False, action='store_true') parser.add_argument('-o', '--operating-system', default=False, action='store_true') parser.add_argument('--help', default=False, action='store_true') parser.add_argument('--version', default=False, action='store_true') try: args = parser.parse_args(params) except ParseError: shell.writeline('uname: invalid options -- \'{}\''.format( ' '.join(params))) shell.writeline('Try \'uname --help\' for more information.') return if args.all: buff = ' '.join(info) shell.writeline(buff) return if args.help: help_file_path = os.path.join(os.path.dirname(hornet.__file__), 'data', 'commands', 'uname', 'help') self.send_data_from_file(help_file_path, shell) return if args.version: version_file_path = os.path.join(os.path.dirname(hornet.__file__), 'data', 'commands', 'uname', 'version') self.send_data_from_file(version_file_path, shell) return if args.kernel_name: buff = buff + info[0] + ' ' if args.nodename: buff = buff + self.hostname + ' ' if args.kernel_release: buff = buff + info[2] + ' ' if args.kernel_version: buff = buff + info[3] + ' ' if args.kernel_machine: buff = buff + info[4] + ' ' if args.processor: buff = buff + info[4] + ' ' if args.hardware_platform: buff = buff + info[4] + ' ' if args.operating_system: buff += 'GNU/Linux' shell.writeline(buff) def _set_ip_from_previous_run(self, fs_dir, valid_ips): # pragma: no cover for dir_name in os.listdir(fs_dir): if dir_name.startswith(self.hostname + '_'): possible_ip = dir_name.split('_')[1] if possible_ip in valid_ips: self.ip_address = possible_ip logger.info('Assigned IP {} to host {}'.format( self.ip_address, self.hostname)) return True return False @staticmethod def send_data_from_file(path, shell): with open(path, 'r') as infile: for line in infile: line = line.strip() shell.writeline(line)