Exemple #1
0
    def __init__(self, shell_binary, shell_argstr, return_code_echo_command,
                 command_separator, is_interactive):
        """Sets up the context for a system shell process.

        Parameters
        ----------
        shell_binary : str
            The shell binary, e.g. ``/bin/bash``, to start.
        shell_argstr : str
            Additional arguments to be passed to the shell at start.
        return_code_echo_command : str
            A command string in the shell's own language that prints to
            standard output the return code of the previously executed command.
        command_separator : str
            The character sequence to separate commands with.
        is_interactive : bool
            Whether the started shell is an interactive one.
            This does only change the behaviour of the context manager, to make
            the shell itself interactive, additional arguments in
            `shell_argstr` might need to be passed.
        """
        self._args = shell_argstr
        self._binary = shell_binary
        # Note: The execution of the command and the reading of the output
        # has to happen BEFORE this timeout is hit, but a large timeout would
        # also mean waiting a lot for small commands, so this has to be
        # balanced carefully.
        self._capture = Capture(timeout=0.5, buffer_size=-1)
        self._command = Command(shell_binary + ' ' + shell_argstr,
                                stdout=self._capture)
        self._echo = return_code_echo_command + command_separator
        self._interactive = is_interactive
        self._separator = command_separator
        self._started = False
Exemple #2
0
    def startStreamer(self):
        if not self._process:
            command = [
                "/mjpeg_streamer/mjpg_streamer",
                "-i",
                "input_uvc.so -d %s -f %s -r %s --no_dynctrl%s" % \
                (self._device,
                 self._fps,
                 self._size,
                 ' -y' if self._format == 'x-raw' else ''
                 ),
                "-o",
                "output_http.so -p %d" % self._httpPort
            ]

            self._process = Command(
                command,
                env={'LD_LIBRARY_PATH': '/mjpeg_streamer'},
                stderr=open(os.devnull, 'w')
            )
            if self._process:
                self._process.run(async=True)
                time.sleep(0.2)
                running = self._process.returncode is None
                return running
        return False
Exemple #3
0
 def test_command_splitting(self):
     logger.debug('test_command started')
     cmd = 'echo foo'
     c = Command(cmd)
     self.assertEqual(c.args, cmd.split())
     c = Command(cmd, shell=True)
     self.assertEqual(c.args, cmd)
Exemple #4
0
 def get_metadata(self, image):
     docker_command = str(self.location) + ' inspect ' + image
     print docker_command
     p = Command(docker_command, stdout=Capture(buffer_size=-1))
     p.run()
     # Testing directly in the string works if the output is only
     # one line.
     # if 'No such image' in p.stdout:
     #    raise DockerImageError
     # data = [json.loads(str(item)) for item in p.stdout.readline().strip().split('\n')]
     json_block = []
     line = p.stdout.readline()
     while(True):
         if not line: break
         if 'no such image' in line:
             raise DockerImageError
         # Stupid sarge appears to add a blank line between
         # json statements. This checks for a blank line and
         # cycles to the next line if it is blank.
         if re.match(r'^\s*$', line):
             line = p.stdout.readline()
             continue
         json_block.append(line)
         line = p.stdout.readline()
     s = ''.join(json_block)
     self.metadata = json.loads(s)
 def get_metadata(self):
     docker_command = str(self.location) + ' inspect ' + self.imageID
     p = Command(docker_command, stdout=Capture(buffer_size=-1))
     p.run()
     # Testing directly in the string works if the output is only
     # one line.
     # if 'No such image' in p.stdout:
     # raise DockerImageError
     # data = [json.loads(str(item)) for item in p.stdout.readline().strip().split('\n')]
     json_block = []
     line = p.stdout.readline()
     while (line):
         if 'no such image' in line:
             raise DockerImageError
         # Stupid sarge appears to add a blank line between
         # json statements. This checks for a blank line and
         # cycles to the next line if it is blank.
         if re.match(r'^\s*$', line):
             line = p.stdout.readline()
             continue
         json_block.append(line)
         line = p.stdout.readline()
     s = ''.join(json_block)
     s = s[1:-2]
     self.metadata = s
 def remove_image(self, name):
     """ removes a named image
     :param name: the name of the image to be removed
     :return: none
     """
     rm_container_string = str(self.location) + ' rm ' + name
     rm_container = Command(rm_container_string)
     rm_container.run()
 def remove_image(self, name):
     """ removes a named image
     :param name: the name of the image to be removed
     :return: none
     """
     rm_container_string = str(self.location) + ' rm ' + name
     rm_container = Command(rm_container_string)
     rm_container.run()
 def stop_container(self, name):
     """ stops a specified container
     :param name: name of the container to stop
     :return:none
     """
     stop_container_string = str(self.location) + ' stop ' + name
     stop_container = Command(stop_container_string)
     stop_container.run()
 def stop_container(self, name):
     """ stops a specified container
     :param name: name of the container to stop
     :return:none
     """
     stop_container_string = str(self.location) + ' stop ' + name
     stop_container = Command(stop_container_string)
     stop_container.run()
Exemple #10
0
    def put_label_image(self, label, imageID):
        """put_label attaches json metadata to smartcontainer label"""

        # Due to the structure of docker, we have to do this in a series of
        # steps. This method attaches a label to a image by creating a
        # temporary container with a label using docker run. We then save that
        # container to a new image with the same.

        # First get tag and name for image id passed to method
        repository, tag = self.get_image_info(imageID)

        # Now "attach" the label by running a new container from the imageID
        label_cmd_string = str(self.location) + ' run --name = labeltmp --label=' + \
            self.label_prefix + '=' + label + ' ' + imageID + ' /bin/echo'
        print label_cmd_string
        p = Command(label_cmd_string)
        p.run(async=True)

        # Save container with new label to new image with previous repo and tag
        commit_cmd_string = str(self.location) + ' commit labeltemp ' + repository + ':' + tag
        commit = Command(commit_cmd_string)
        commit.run()

        # remove temporary container
        rm_container_string = str(self.location) + ' rm labeltemp'
        rm_container = Command(rm_container_string)
        rm_container.run()
 def container_save_as(self, name, saveas, tag):
     """ Saves a container to a new image
     :param name: the name of the container to be saved
     :param saveas: the name of the image to be created
     :param tag: the tag attached to the new image
     :return: none
     """
     commit_cmd_string = str(self.location) + ' commit ' + name + ' ' + saveas
     if tag != "":
         commit_cmd_string = commit_cmd_string + ':' + tag
     commit = Command(commit_cmd_string)
     commit.run()
 def container_save_as(self, name, saveas, tag):
     """ Saves a container to a new image
     :param name: the name of the container to be saved
     :param saveas: the name of the image to be created
     :param tag: the tag attached to the new image
     :return: none
     """
     commit_cmd_string = str(
         self.location) + ' commit ' + name + ' ' + saveas
     if tag != "":
         commit_cmd_string = commit_cmd_string + ':' + tag
     commit = Command(commit_cmd_string)
     commit.run()
Exemple #13
0
 def test_env_usage(self):
     if os.name == 'nt':
         cmd = 'echo %FOO%'
     else:
         cmd = 'echo $FOO'
     if PY3:
         env = {'FOO': 'BAR'}
     else:
         # Python 2.x wants native strings, at least on Windows
         # (and literals are Unicode in this module)
         env = { b'FOO': b'BAR' }
     c = Command(cmd, env=env, stdout=Capture(), shell=True)
     c.run()
     self.assertEqual(c.stdout.text.strip(), 'BAR')
Exemple #14
0
 def test_env_usage(self):
     if os.name == 'nt':
         cmd = 'echo %FOO%'
     else:
         cmd = 'echo $FOO'
     if PY3:
         env = {'FOO': 'BAR'}
     else:
         # Python 2.x wants native strings, at least on Windows
         # (and literals are Unicode in this module)
         env = {b'FOO': b'BAR'}
     c = Command(cmd, env=env, stdout=Capture(), shell=True)
     c.run()
     self.assertEqual(c.stdout.text.strip(), 'BAR')
Exemple #15
0
 def test_env_usage(self):
     if os.name == "nt":
         cmd = "echo %FOO%"
     else:
         cmd = "echo $FOO"
     if PY3:
         env = {"FOO": "BAR"}
     else:
         # Python 2.x wants native strings, at least on Windows
         # (and literals are Unicode in this module)
         env = {b"FOO": b"BAR"}
     c = Command(cmd, env=env, stdout=Capture(), shell=True)
     c.run()
     self.assertEqual(c.stdout.text.strip(), "BAR")
Exemple #16
0
 def test_command_nonexistent(self):
     c = Command('nonesuch foo'.split(), stdout=Capture())
     if PY3:
         ARR = self.assertRaisesRegex
     else:
         ARR = self.assertRaisesRegexp
     ARR(ValueError, 'Command not found: nonesuch', c.run)
Exemple #17
0
    def do_command(self):
        """do_command is main entry point for capturing docker commands"""
        # First run the command and capture the output.
        # For efficiency this should probably change such that
        # if a command doesn't have a capture handler we execute
        # the command uncaptured. Most commands are going to be captured
        # for provenance, so this efficiency concern is probably moot.

        if self.location is None:
            self.find_docker()
        cmd_string = str(self.location) + ' ' + self.command
        p = Command(cmd_string)
        p.run(async=True)

        for name in snarf_docker_commands:
            if name in self.command:
                self.capture_cmd_workflow()
Exemple #18
0
 def test_env(self):
     e = os.environ
     if PY3:
         env = {'FOO': 'BAR'}
     else:
         # Python 2.x wants native strings, at least on Windows
         # (and literals are Unicode in this module)
         env = {b'FOO': b'BAR'}
     c = Command('echo foo', env=env)
     d = c.kwargs['env']
     ek = set(e)
     dk = set(d)
     ek.add('FOO')
     self.assertEqual(dk, ek)
     self.assertEqual(d['FOO'], 'BAR')
Exemple #19
0
	def startVideo(self):
		if not self._process:
			command = [
				"/mjpeg_streamer/mjpg_streamer",
				"-i",
				"input_uvc.so -d %s -f %s -r %s --no_dynctrl%s" % (self._device, self._fps, self._size, ' -y' if self._format == 'x-raw' else ''),
				"-o",
				"output_http.so -p %d" % self._httpPort
			]

			self._process = Command(command, env={'LD_LIBRARY_PATH': '/mjpeg_streamer'}, stderr=open(os.devnull, 'w'))
			if self._process:
				self._process.run(async=True)

				time.sleep(0.2)

				return self._process.returncode is None

		return False
 def fileCopyIn(self, dockerlocation, containerid, filename, path):
     copy_cmd = str(
         dockerlocation
     ) + ' cp ' + filename + " " + containerid + ":" + path + filename
     thisCommand = Command(copy_cmd)
     thisCommand.run()
Exemple #21
0
 def test_command_run(self):
     c = Command('echo foo'.split(), stdout=Capture())
     c.run()
     self.assertEqual(c.returncode, 0)
Exemple #22
0
 def test_command_run(self):
     c = Command('echo foo'.split(), stdout=Capture())
     c.run()
     self.assertEqual(c.returncode, 0)
Exemple #23
0
class Shell(AbstractContextManager):
    """A real shell running on the host machine, to be used in a context."""
    def __init__(self, shell_binary, shell_argstr, return_code_echo_command,
                 command_separator, is_interactive):
        """Sets up the context for a system shell process.

        Parameters
        ----------
        shell_binary : str
            The shell binary, e.g. ``/bin/bash``, to start.
        shell_argstr : str
            Additional arguments to be passed to the shell at start.
        return_code_echo_command : str
            A command string in the shell's own language that prints to
            standard output the return code of the previously executed command.
        command_separator : str
            The character sequence to separate commands with.
        is_interactive : bool
            Whether the started shell is an interactive one.
            This does only change the behaviour of the context manager, to make
            the shell itself interactive, additional arguments in
            `shell_argstr` might need to be passed.
        """
        self._args = shell_argstr
        self._binary = shell_binary
        # Note: The execution of the command and the reading of the output
        # has to happen BEFORE this timeout is hit, but a large timeout would
        # also mean waiting a lot for small commands, so this has to be
        # balanced carefully.
        self._capture = Capture(timeout=0.5, buffer_size=-1)
        self._command = Command(shell_binary + ' ' + shell_argstr,
                                stdout=self._capture)
        self._echo = return_code_echo_command + command_separator
        self._interactive = is_interactive
        self._separator = command_separator
        self._started = False

    def __enter__(self):
        """Starts the shell in a context manager setting."""
        return self.start()

    def __exit__(self, exc_type, exc_value, trace):
        """Destroys the shell and leaves the context."""
        if self._interactive:
            self.kill()
        else:
            self.terminate()
        return False

    def start(self):
        """Starts the underlying shell process as configured in
        :py:func:`__init__`.
        """
        if self._started:
            raise OSError(EEXIST, "The shell is already running!")
        print("[Shell] Starting '{0} {1}'...".format(self._binary, self._args),
              file=sys.stderr)
        try:
            self._command.run(input=PIPE, async_=True)
        except ValueError:
            raise FileNotFoundError("The shell binary '{0}' cannot be found "
                                    "on the system.".format(self._binary))
        self._started = True
        return self

    @property
    def pid(self):
        """The PID of the started process."""
        if not self._started:
            raise OSError(ESRCH, "The shell is not running!")
        return self._command.process.pid

    def kill(self):
        """Kills (by sending ``SIGKILL`` (``9``)) to the shell process."""
        if not self._started:
            raise OSError(ESRCH, "The shell is not running!")
        self._command.kill()
        self._command.wait()
        self._capture.close(True)
        self._started = False

    def terminate(self):
        """Terminates (by sending ``SIGTERM`` (``15``)) to the shell process.

        Note
        ----
        Interactive shells (:py:attr:`is_interactive`) usually catch and ignore
        this signal, and as such, :py:func:`kill` should be used to shut them
        down properly.
        """
        if not self._started:
            raise OSError(ESRCH, "The shell is not running!")
        self._command.terminate()
        self._command.wait()
        self._capture.close(True)
        self._started = False

    def execute_command(self, cmd, timeout=None):
        """Execute `cmd` in the shell, wait `timeout` seconds, and read back
        the result.

        Parameters
        ----------
        cmd : str
            The command to execute.
            This string will be written into the shell's standard input
            verbatim.
        timeout : int
            The time (in seconds) to wait before the output of the command is
            read.

        Returns
        -------
        return_code : int
            The return code of the executed command.
        result : str
            The *standard output* of the executed command.

        Note
        ----
        The command executed in the shell is extended with
        :py:attr:`command_separator` and :py:attr:`return_code_echo_command`,
        and written to the shell.
        In case of a conventional ``/bin/bash`` shell, for example, executing
        `cmd` ``echo "Foo"`` will actually execute:

        .. code-block:: bash

           echo "Foo";
           echo $;

        Which will result in the output:

        .. code-block:: bash

           Foo
           0

        to be read as a result.

        Warning
        -------
        The underlying library and the execution of piped shells does not allow
        a good method of "sensing" when the output became available while
        keeping interactivity.
        A too small `timeout` on a loaded system might result in output being
        lost, while a too big one will result in every command waiting for
        a considerable time.
        """
        cmd = cmd + self._separator + self._echo
        print("[Shell '{0}'] Running command:\n{1}\n".format(
            self._binary,
            '\n'.join(list(map(lambda l: "    > " + l, cmd.split('\n'))))),
              file=sys.stderr)

        self._command.stdin.write(cmd.encode('utf-8'))
        self._command.stdin.flush()

        stdout = self._capture.read(timeout=timeout)
        parts = stdout.decode().rstrip().split('\n')
        result, returncode = '\n'.join(parts[:-1]).rstrip(), parts[-1].rstrip()

        print("[Shell '{0}'] Command result #{1}:\n{2}".format(
            self._binary, returncode, result),
              file=sys.stderr)
        return int(returncode), result
Exemple #24
0
class MJPEGStreamer(object):
    _httpPort = 8085

    def __init__(self, videoDevice, size, fps, format):
        self._logger = logging.getLogger(__name__)
        self._device = '/dev/video%d' % videoDevice
        self._size = size
        self._fps = fps
        self._format = format
        self._videoRunning = False
        self._process = None
        self._streaming = False
        self._needsExposure = True

        self._infoArea = cv2.imread(
            os.path.join(app.static_folder, 'img', 'camera-info-overlay.jpg'),
            cv2.cv.CV_LOAD_IMAGE_COLOR)
        self._infoAreaShape = self._infoArea.shape

        #precalculated stuff
        watermark = cv2.imread(
            os.path.join(app.static_folder, 'img', 'astroprint_logo.png'))
        watermark = cv2.resize(
            watermark, (100, 100 * watermark.shape[0] / watermark.shape[1]))

        self._watermarkShape = watermark.shape

        watermarkMask = cv2.cvtColor(watermark, cv2.COLOR_BGR2GRAY) / 255.0
        watermarkMask = np.repeat(watermarkMask, 3).reshape(
            (self._watermarkShape[0], self._watermarkShape[1], 3))
        self._watermakMaskWeighted = watermarkMask * watermark
        self._watermarkInverted = 1.0 - watermarkMask

    def startStreamer(self):
        if not self._process:
            command = [
                "/mjpeg_streamer/mjpg_streamer", "-i",
                "input_uvc.so -d %s -f %s -r %s --no_dynctrl%s" %
                (self._device, self._fps, self._size,
                 ' -y' if self._format == 'x-raw' else ''), "-o",
                "output_http.so -p %d" % self._httpPort
            ]

            self._process = Command(command,
                                    env={'LD_LIBRARY_PATH': '/mjpeg_streamer'},
                                    stderr=open(os.devnull, 'w'))
            if self._process:
                self._process.run(async=True)

                time.sleep(0.2)

                running = self._process.returncode is None

                return running

        return False

    def startVideo(self):
        if self._streaming:
            return True

        if self.startStreamer():
            self._streaming = True
            return True

        return False

    def stop(self):
        if self._process:
            if self._process.returncode is None:
                self._process.terminate()
                tries = 4
                while self._process.returncode is None:
                    if tries > 0:
                        tries -= 1
                        time.sleep(0.5)
                        self._process.poll()
                    else:
                        break

                if self._process.returncode is None:
                    self._logger.warn(
                        'Unable to terminate nicely, killing the process.')
                    self._process.kill()
                    self._process.wait()

            self._process = None

        self._streaming = False
        self._needsExposure = True

    def stopVideo(self):
        self._streaming = False

    def isVideoStreaming(self):
        return self._streaming

    def getPhoto(self, doneCb, text=None):
        image = None

        if not self._process:
            if not self.startStreamer():
                self._logger.error('Unable to start MJPEG Streamer')
                doneCb(None)
                return

        try:
            if self._needsExposure and not self.isVideoStreaming():
                time.sleep(
                    1.8
                )  # we need to give the camera some time to stabilize the image. 1.8 secs has been tested to work in low end cameras
                self._needsExposure = False

            response = urllib2.urlopen('http://127.0.0.1:%d?action=snapshot' %
                                       self._httpPort)
            image = response.read()

        except urllib2.URLError as e:
            self._logger.error(e)

        if image and text:
            decodedImage = cv2.imdecode(np.fromstring(image, np.uint8),
                                        cv2.CV_LOAD_IMAGE_COLOR)
            self._apply_watermark(decodedImage, text)
            image = cv2.cv.EncodeImage(
                '.jpeg', cv2.cv.fromarray(decodedImage),
                [cv2.cv.CV_IMWRITE_JPEG_QUALITY, 80]).tostring()

        doneCb(image)

    def _apply_watermark(self, img, text):
        if text and img != None:
            imgPortion = img[-(self._watermarkShape[0] + 5):-5,
                             -(self._watermarkShape[1] + 5):-5]
            img[-(self._watermarkShape[0] + 5):-5,
                -(self._watermarkShape[1] +
                  5):-5] = (self._watermarkInverted *
                            imgPortion) + self._watermakMaskWeighted

            img[:self._infoAreaShape[0], :self.
                _infoAreaShape[1]] = self._infoArea
            cv2.putText(img,
                        text, (30, 17),
                        cv2.FONT_HERSHEY_PLAIN,
                        1.0, (81, 82, 241),
                        thickness=1)

            return True

        return False
Exemple #25
0
class MJPEGStreamer(object):
	_httpPort = 8085

	def __init__(self, videoDevice, size, fps, format):
		self._device = '/dev/video%d' % videoDevice
		self._size = size
		self._fps = fps
		self._format = format
		self._videoRunning = False
		self._process = None


		self._infoArea = cv2.imread(os.path.join(app.static_folder, 'img', 'camera-info-overlay.jpg'), cv2.cv.CV_LOAD_IMAGE_COLOR)
		self._infoAreaShape = self._infoArea.shape

		#precalculated stuff
		watermark = cv2.imread(os.path.join(app.static_folder, 'img', 'astroprint_logo.png'))
		watermark = cv2.resize( watermark, ( 100, 100 * watermark.shape[0]/watermark.shape[1] ) )
		
		self._watermarkShape = watermark.shape
		
		watermarkMask = cv2.cvtColor(watermark, cv2.COLOR_BGR2GRAY) / 255.0
		watermarkMask = np.repeat( watermarkMask, 3).reshape( (self._watermarkShape[0],self._watermarkShape[1],3) )
		self._watermakMaskWeighted = watermarkMask * watermark
		self._watermarkInverted = 1.0 - watermarkMask

	def startVideo(self):
		if not self._process:
			command = [
				"/mjpeg_streamer/mjpg_streamer",
				"-i",
				"input_uvc.so -d %s -f %s -r %s --no_dynctrl%s" % (self._device, self._fps, self._size, ' -y' if self._format == 'x-raw' else ''),
				"-o",
				"output_http.so -p %d" % self._httpPort
			]

			self._process = Command(command, env={'LD_LIBRARY_PATH': '/mjpeg_streamer'}, stderr=open(os.devnull, 'w'))
			if self._process:
				self._process.run(async=True)

				time.sleep(0.2)

				return self._process.returncode is None

		return False

	def stopVideo(self):
		if self._process:
			if self._process.returncode is None:
				self._process.terminate()
				self._process.wait()
			
			self._process = None

	def getPhoto(self, text=None, doneCb=None):
		image = None
		stopAfterPhoto = False

		if not self._process:
			self.startVideo()
			stopAfterPhoto = True

		try:
			if self._format == 'x-raw':
				time.sleep(1.8) # we need to give the camera some time to stabilize the image. 1.8 secs has been tested to work in low end cameras

			response = urllib2.urlopen('http://127.0.0.1:%d?action=snapshot' % self._httpPort)
			image = response.read()

		except urllib2.URLError:
			pass

		if image and text:
			decodedImage = cv2.imdecode(np.fromstring(image, np.uint8), cv2.CV_LOAD_IMAGE_COLOR)
			self._apply_watermark(decodedImage, text)
			image = cv2.cv.EncodeImage('.jpeg', cv2.cv.fromarray(decodedImage), [cv2.cv.CV_IMWRITE_JPEG_QUALITY, 80]).tostring()

		if stopAfterPhoto:
			self.stopVideo()

		if doneCb:
			doneCb(image)

		else:
			return image

	def _apply_watermark(self, img, text):
			if text and img != None:
				imgPortion = img[-(self._watermarkShape[0]+5):-5, -(self._watermarkShape[1]+5):-5]
				img[-(self._watermarkShape[0]+5):-5, -(self._watermarkShape[1]+5):-5] = (self._watermarkInverted * imgPortion) + self._watermakMaskWeighted

				img[:self._infoAreaShape[0], :self._infoAreaShape[1]] = self._infoArea
				cv2.putText(img, text, (30,17), cv2.FONT_HERSHEY_PLAIN, 1.0, (81,82,241), thickness=1)

				return True

			return False
Exemple #26
0
    def __init__(self, structure):
        """
        Args:
        """

        self.input_structure = structure.copy()

        iso_location = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                    'iso/')

        self.input_filename_cif = os.path.join(iso_location,
                                               'findsym_input.mcif')
        self.output_filename_cif = os.path.join(iso_location, 'findsym.cif')
        # self.input_filename_findsym = os.path.join(iso_location, 'findsym_in.in')
        self.input_filename_findsym = 'findsym_in.in'
        self.write_cif_input()

        # write initial input from mcif file
        findsym_command = 'findsym_cifinput ' + self.input_filename_cif

        logger.debug("""starting isotropy session in {}
                        using isotropy in: {}""".format(
            os.getcwd(), iso_location))
        self.findsym_cifinput_process = Command(os.path.join(
            iso_location, findsym_command),
                                                stdout=Capture(buffer_size=1),
                                                env={"ISODATA": iso_location})
        try:
            self.findsym_cifinput_process.run(input=PIPE, async_=False)
        except FileNotFoundError:
            raise Exception(
                "Couldn't find Isotropy (findsym) for Linux, see installation instructions"
            )

        with open(self.input_filename_findsym, "w") as io_file:

            # move past initial output
            keep_reading = True
            while keep_reading:
                # this_line = self.iso_process.stdout.readline().decode()
                this_line = self.findsym_cifinput_process.stdout.readline(
                ).decode()
                if this_line:  # don't log until isotropy responds
                    logger.debug("isotropy: {}".format(this_line))
                    io_file.write(this_line)
                else:
                    keep_reading = False

        # run findsym
        findsym_command = 'findsym ' + self.input_filename_findsym

        self.findsym_process = Command(os.path.join(iso_location,
                                                    findsym_command),
                                       stdout=Capture(buffer_size=1),
                                       env={"ISODATA": iso_location})
        try:
            self.findsym_process.run(input=PIPE, async_=False)
        except FileNotFoundError:
            raise Exception(
                "Couldn't find Isotropy (findsym) for Linux, see installation instructions"
            )

        # # move past initial output
        # keep_reading = True
        # while keep_reading:
        #     this_line = self.findsym_process.stdout.readline().decode()
        #     # this_line = self.read_iso_line()
        #     if this_line: # don't log until isotropy responds
        #         logger.debug("isotropy: {}".format(this_line))
        #     else:
        #         keep_reading = False

        self.output_cif_file = CifFile.from_file(self.output_filename_cif)

        msg_int_symbol = int(self.output_cif_file.data['findsym-output'].
                             data['_symmetry_Int_Tables_number'])

        self.magnetic_space_group = MagneticSpaceGroup(msg_int_symbol)
Exemple #27
0
class FindsymSession:
    """
    """
    def __init__(self, structure):
        """
        Args:
        """

        self.input_structure = structure.copy()

        iso_location = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                    'iso/')

        self.input_filename_cif = os.path.join(iso_location,
                                               'findsym_input.mcif')
        self.output_filename_cif = os.path.join(iso_location, 'findsym.cif')
        # self.input_filename_findsym = os.path.join(iso_location, 'findsym_in.in')
        self.input_filename_findsym = 'findsym_in.in'
        self.write_cif_input()

        # write initial input from mcif file
        findsym_command = 'findsym_cifinput ' + self.input_filename_cif

        logger.debug("""starting isotropy session in {}
                        using isotropy in: {}""".format(
            os.getcwd(), iso_location))
        self.findsym_cifinput_process = Command(os.path.join(
            iso_location, findsym_command),
                                                stdout=Capture(buffer_size=1),
                                                env={"ISODATA": iso_location})
        try:
            self.findsym_cifinput_process.run(input=PIPE, async_=False)
        except FileNotFoundError:
            raise Exception(
                "Couldn't find Isotropy (findsym) for Linux, see installation instructions"
            )

        with open(self.input_filename_findsym, "w") as io_file:

            # move past initial output
            keep_reading = True
            while keep_reading:
                # this_line = self.iso_process.stdout.readline().decode()
                this_line = self.findsym_cifinput_process.stdout.readline(
                ).decode()
                if this_line:  # don't log until isotropy responds
                    logger.debug("isotropy: {}".format(this_line))
                    io_file.write(this_line)
                else:
                    keep_reading = False

        # run findsym
        findsym_command = 'findsym ' + self.input_filename_findsym

        self.findsym_process = Command(os.path.join(iso_location,
                                                    findsym_command),
                                       stdout=Capture(buffer_size=1),
                                       env={"ISODATA": iso_location})
        try:
            self.findsym_process.run(input=PIPE, async_=False)
        except FileNotFoundError:
            raise Exception(
                "Couldn't find Isotropy (findsym) for Linux, see installation instructions"
            )

        # # move past initial output
        # keep_reading = True
        # while keep_reading:
        #     this_line = self.findsym_process.stdout.readline().decode()
        #     # this_line = self.read_iso_line()
        #     if this_line: # don't log until isotropy responds
        #         logger.debug("isotropy: {}".format(this_line))
        #     else:
        #         keep_reading = False

        self.output_cif_file = CifFile.from_file(self.output_filename_cif)

        msg_int_symbol = int(self.output_cif_file.data['findsym-output'].
                             data['_symmetry_Int_Tables_number'])

        self.magnetic_space_group = MagneticSpaceGroup(msg_int_symbol)

    def get_msg(self):
        return self.magnetic_space_group

    def __enter__(self):
        return self

    def __exit__(self, exec_type, exc_value, exc_traceback):
        self.sendCommand("QUIT")

    def sendCommand(self, command):
        # read the '*' that indicates the prompt so they don't build up
        this_line = self.read_iso_line()
        # logger.debug("reading *: {}".format(this_line))
        logger.debug(f'python: {command}')
        # self.findsym_process.stdin.write(bytes(command + "\n", "ascii"))
        # self.findsym_process.stdin.flush()

    def write_cif_input(self):

        cif_writer = CifWriter(struct=self.input_structure,
                               symprec=None,
                               write_magmoms=True,
                               significant_figures=8,
                               angle_tolerance=5.0,
                               refine_struct=True)

        cif_writer.write_file(self.input_filename_cif)

    # def write_input(self):

    #     inputfile_string = """ \
    #     !useKeyWords
    #     !title
    #     Structure input file
    #     !latticeParameters
    #     %s
    #     !unitCellCentering
    #     %s
    #     !atomCount
    #     %s
    #     !atomPosition
    #     %s
    #     """ % (lat_param_s, unit_cell_centering_s,
    #            atom_count_s, atom_pos_s)

    def read_iso_line(self):
        raw = self.findsym_process.stdout.readline().decode()
        this_line = raw.rstrip('\n')
        logger.debug("isotropy: {}".format(this_line))
        return this_line
Exemple #28
0
    def __init__(self, values=None, shows=None, labels=None, setting=None):
        """
        Args:
        values: dictionary of keys to be set to values
            key is a string specifying what is being set
                e.g. "basis", "cell", "irrep", "kpoint", "parent"
            value is what this key is being set to
        shows: A list of strings corresponding to data which will be returned
            when display is run.
            Note: some show commands accept additional parameters, for now
            these must be included in the string. Eventually parsing of
            display output should be good enough that they are not needed.
        labels: NOT YET IMPLEMENTED
            dictionary where the key corresponds to the object
            whose notation is being altered, the value corresponds
            to the new notation to be used for this object
            for example {"spacegroup": "SCHOENFLIES"} will cause returned
            results and entered values to use schoenflies notation
        setting:
            a string or list of strings to be passed to
            the setting command can be used to change settings, origin,
            unique axis and/or cell choice. Can also specify if magnetic
            spacegroups are desired
            for now the setting options can only be set
            when creating an Isotropy object, not changed later
        """
        iso_location = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                    'iso/')
        logger.debug("""starting isotropy session in {}
                        using isotropy in: {}""".format(
            os.getcwd(), iso_location))
        self.iso_process = Command(os.path.join(iso_location, 'iso'),
                                   stdout=Capture(buffer_size=1),
                                   env={"ISODATA": iso_location})
        try:
            self.iso_process.run(input=PIPE, async_=True)
        except FileNotFoundError:
            raise Exception(
                "Couldn't find Isotropy for Linux, see installation instructions"
            )
        # move past initial output
        keep_reading = True
        while keep_reading:
            # this_line = self.iso_process.stdout.readline().decode()
            this_line = self.read_iso_line()
            if this_line:  # don't log until isotropy responds
                logger.debug("isotropy: {}".format(this_line))
            if this_line == 'Use "VALUE IRREP VERSION" to change version':
                keep_reading = False

        self.screen = 999  # exploit this too make parsing output easier?
        self.sendCommand("SCREEN {}".format(self.screen))
        #self.page = "NOBREAK" # still feels the need to periodicly put in labels
        self.page = "999"
        self.sendCommand("PAGE {}".format(self.page))
        if setting:
            if type(setting) == list:
                self.setting = setting
            else:
                self.setting = [setting]
        else:
            self.setting = ["INTERNATIONAL"]
        for s in self.setting:
            self.sendCommand("SETTING {}".format(s))
        self.values = Values(self, values)
        self.shows = Shows(self, shows)
Exemple #29
0
class IsotropySession:
    """
    Make simple requests to isotropy.
    isotropy session is kept running in background until closed
    should be used with 'with' statements to ensure isotropy is exited properly
    ex:
    with IsotropySession() as isos:
        do things with isos
    """
    def __init__(self, values=None, shows=None, labels=None, setting=None):
        """
        Args:
        values: dictionary of keys to be set to values
            key is a string specifying what is being set
                e.g. "basis", "cell", "irrep", "kpoint", "parent"
            value is what this key is being set to
        shows: A list of strings corresponding to data which will be returned
            when display is run.
            Note: some show commands accept additional parameters, for now
            these must be included in the string. Eventually parsing of
            display output should be good enough that they are not needed.
        labels: NOT YET IMPLEMENTED
            dictionary where the key corresponds to the object
            whose notation is being altered, the value corresponds
            to the new notation to be used for this object
            for example {"spacegroup": "SCHOENFLIES"} will cause returned
            results and entered values to use schoenflies notation
        setting:
            a string or list of strings to be passed to
            the setting command can be used to change settings, origin,
            unique axis and/or cell choice. Can also specify if magnetic
            spacegroups are desired
            for now the setting options can only be set
            when creating an Isotropy object, not changed later
        """
        iso_location = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                    'iso/')
        logger.debug("""starting isotropy session in {}
                        using isotropy in: {}""".format(
            os.getcwd(), iso_location))
        self.iso_process = Command(os.path.join(iso_location, 'iso'),
                                   stdout=Capture(buffer_size=1),
                                   env={"ISODATA": iso_location})
        try:
            self.iso_process.run(input=PIPE, async_=True)
        except FileNotFoundError:
            raise Exception(
                "Couldn't find Isotropy for Linux, see installation instructions"
            )
        # move past initial output
        keep_reading = True
        while keep_reading:
            # this_line = self.iso_process.stdout.readline().decode()
            this_line = self.read_iso_line()
            if this_line:  # don't log until isotropy responds
                logger.debug("isotropy: {}".format(this_line))
            if this_line == 'Use "VALUE IRREP VERSION" to change version':
                keep_reading = False

        self.screen = 999  # exploit this too make parsing output easier?
        self.sendCommand("SCREEN {}".format(self.screen))
        #self.page = "NOBREAK" # still feels the need to periodicly put in labels
        self.page = "999"
        self.sendCommand("PAGE {}".format(self.page))
        if setting:
            if type(setting) == list:
                self.setting = setting
            else:
                self.setting = [setting]
        else:
            self.setting = ["INTERNATIONAL"]
        for s in self.setting:
            self.sendCommand("SETTING {}".format(s))
        self.values = Values(self, values)
        self.shows = Shows(self, shows)

    def __enter__(self):
        return self

    def __exit__(self, exec_type, exc_value, exc_traceback):
        self.sendCommand("QUIT")

    def restart_session(self):
        try:
            self.sendCommand("QUIT")
        except BrokenPipeError:
            logger.debug('Ignoring BrokenPipeError on restart')
        self.iso_process.kill()
        files_to_remove = glob("*.iso")
        logger.warning("removing iso db files {}".format(files_to_remove))
        for f in files_to_remove:
            os.remove(f)
        self.__init__(
            values=self.values,
            shows=self.shows,
            labels=None,
            setting=self.setting)  # TODO: update if labels implemented

    def sendCommand(self, command):
        # read the '*' that indicates the prompt so they don't build up
        this_line = self.read_iso_line()
        # logger.debug("reading *: {}".format(this_line))
        logger.debug(f'python: {command}')
        self.iso_process.stdin.write(bytes(command + "\n", "ascii"))
        self.iso_process.stdin.flush()

    def getDisplayData(self, display, raw=False, delay=None):
        """
        Args:
        display: what we are asking isotropy to display
            the command sent will be 'DISPLAY {display}'
        raw: if true return a string of the raw output from isotropy
            otherwise the output is automaticly parsed in to a list of dictionaries
        """
        self.sendCommand("DISPLAY {}".format(display))
        # really annoying, TODO: should find a way to not need this delay ever
        if delay is not None:
            time.sleep(delay)
        lines = []
        keep_reading = True
        while keep_reading:
            this_line = self.read_iso_line()
            if this_line in ['*',
                             '']:  # if there is no output '' is returned above
                keep_reading = False
            elif re.match(".*You have requested information about .*",
                          this_line):
                self.read_iso_line()  # read past irrep:...
                self.read_iso_line()  # read past The data base for these...
                self.read_iso_line()  # read past Should this...
                self.read_iso_line()  # read past Enter RETURN
                self.sendCommand("")
                self.read_iso_line()  # read past Adding
                for i in range(10):
                    possibly_blank = self.read_iso_line()
                    if not (possibly_blank in [
                            '*', ''
                    ]):  # if there is no output '' is returned above
                        logger.debug(
                            "moved past data base prompt, adding results")
                        lines.append(possibly_blank)
                        break
                    else:
                        if i == 9:
                            logger.debug(
                                "moved past data base prompt, no results")
            elif re.match(".*Data base for these coupled subgroups .*",
                          this_line):
                self.read_iso_line()  # read past Should this...
                self.read_iso_line()  # read past Enter RETURN
                self.sendCommand("")
                self.read_iso_line()  # read past Adding
                for i in range(10):
                    possibly_blank = self.read_iso_line()
                    if not (possibly_blank in [
                            '*', ''
                    ]):  # if there is no output '' is returned above
                        logger.debug(
                            "moved past data base prompt, adding results")
                        lines.append(possibly_blank)
                        break
                    else:
                        if i == 9:
                            logger.debug(
                                "moved past data base prompt, no results")
            else:
                lines.append(this_line)
        if not raw:
            return self._parse_output(lines)
        return lines

    def read_iso_line(self):
        raw = self.iso_process.stdout.readline().decode()
        this_line = raw.rstrip('\n')
        logger.debug("isotropy: {}".format(this_line))
        if re.match('.*program\shas\sbombed.*', this_line):
            raise IsotropyBombedException()
        if re.match(".*Basis\svectors\sare\snot\sa\sright\-handed\sset.*",
                    this_line):
            raise IsotropyBasisException()
        if re.match(
                ".*not\sall\selements\sof\sthe\ssubgroup\sare\selements\sof\sparent\sgroup.*",
                this_line):
            raise IsotropySubgroupException()
        return this_line

    def _parse_output(self, lines):
        indexes = detect_column_indexes(lines)
        split_by_ind = [split_line_by_indexes(indexes, line) for line in lines]
        parsed_output = [{
            key: detect_data_form_and_convert(prop)
            for key, prop in result.items()
        } for result in detect_multirows_and_split(split_by_ind)]
        return parsed_output
 def fileCopyIn(self, dockerlocation, containerid, filename, path):
     copy_cmd =  str(dockerlocation) + ' cp '+ filename + " " + containerid + ":" + path + filename
     thisCommand = Command(copy_cmd)
     thisCommand.run()