예제 #1
0
파일: case.py 프로젝트: ehmoussi/asterstudy
    def text2stage(self, text, name=None, strict=ConversionLevel.NoFail,
                   force_text=False):
        """
        Create a new stage from a COMM text snippet.

        See `import_stage()` for details about *strict* mode.

        Arguments:
            text (str): COMM code snippet.
            name (str): Name of Stage being created.
            strict (ConversionLevel): Tells how strict the conversion
                must be. For more details, see `general.ConversionLevel`.
                Default is not to fail.

        Returns:
            Stage: New Stage.
        """
        stage = self.create_stage(name)
        is_graphical_mode = not force_text and stage.is_graphical_mode()
        stage.use_text_mode()
        stage.set_text(text)

        if is_graphical_mode:
            try:
                stage.use_graphical_mode(strict)
            except Exception as exc: # pragma pylint: disable=broad-except
                debug_message('can not use graphical mode: {0}'.format(exc))

        return stage
예제 #2
0
def debug_ajs(js_text):  # pragma: no cover
    """For debugging, use one file name per session"""
    if not debug_mode():
        return
    if not hasattr(debug_ajs, "cache"):
        debug_ajs.cache = tempfile.mkstemp(prefix='astdy-', suffix='.ajs')[1]

    with open(debug_ajs.cache, "w") as js_file:
        js_file.write(js_text)
    debug_message("File saved:", debug_ajs.cache)
예제 #3
0
def _debug_parse(num, val, line):  # pragma: no cover
    """Debug helper"""
    if debug_mode():
        if num == token.NEWLINE:
            snum = "*" * 12
        elif num == tokenize.NL:
            snum = "+" * 12
        elif num == tokenize.COMMENT:
            snum = "#" * 12
        else:
            snum = token.tok_name[num]
        fmt = "{0:<12} {1!r:<20}: {2!r}"
        debug_message(fmt.format(snum, val, line))
예제 #4
0
    def convert(self, intext):
        """Fill the stage from a commands file (given as text).

        Arguments:
            intext (str): Content of the commands file.
        """
        init_size = len(self._stg)
        intext = to_unicode(intext)
        try:
            eoi, text = change_text(intext, self._strict)
        except Exception as exc: # pragma pylint: disable=broad-except
            details = traceback.format_exc()
            raise ConversionError(exc, details, '?', '?')
        text = "{0}\n_post_conversion() # {1}\n".format(text, MARK)
        self._exec_ctxt = self._setup()
        try:
            exec text in self._exec_ctxt # pragma pylint: disable=exec-used
        except Exception as exc: # pragma pylint: disable=broad-except
            self._teardown()
            details = traceback.format_exc()
            eoprev, lineno, line = _locate_error(exc, eoi, text)
            if self._strict & ConversionLevel.Partial:
                debug_message("Conversion failed, split after line", eoprev)
                # remove the unfinished command
                if self._unfinish:
                    del self._stg[self._unfinish]
                # _post_conversion was not called
                try:
                    self._post_conversion()
                except Exception: # pragma pylint: disable=broad-except
                    # some commands have not be named...
                    pass
                part1, astext = split_text(intext, eoprev, remove=MARK)
                # debug_message("+" * 50)
                # debug_message(part1)
                # debug_message("-" * 50)
                # debug_message(astext)
                # debug_message("=" * 50)
                # in case of SyntaxError, nothing has been added
                if isinstance(exc, SyntaxError):
                    debug_message("SyntaxError: convert first part separately")
                    comm2study(part1, self._stg, self._strict)
                if astext:
                    self.add_text_stage(astext)
            else:
                # revert the input stage as it was
                while len(self._stg) > init_size:
                    del self._stg[-1]
                raise ConversionError(exc, details, lineno, line)
        finally:
            self._teardown()
예제 #5
0
    def update(self, expression=None, name=None):
        """Evaluates assigned expressions in the `current` context.

        Ensure to be not recursive.

        Returns:
            dict: pairs of name per Python instance.
        """
        if self._updating:
            return
        self._updating = True
        debug_message("updating variable", repr(self))
        try:
            return self._update(expression, name)
        finally:
            self._updating = False
예제 #6
0
def _change_text(text):
    """Pre-processing of the input text.

    - Wrap constant parameters:

      ``a = 1`` is converted as ``a = _CONVERT_VARIABLE(EXPR="1")``

    - Wrap comments:

      ``# line of comment.`` is converted as
      ``_CONVERT_COMMENT(EXPR="# line of comment.")``

    Returns:
        list[int]: list of line numbers of end of instruction.
        str: changed text.
    """
    generator = tokenize.generate_tokens(StringIO(text).readline)
    result = []
    buff = []
    eoi = []
    started = False
    for ret in generator:
        num, val = ret[:2]
        started = started or num == token.NAME
        # _debug_parse(num, val, ret[4])
        if num == token.NEWLINE:
            eoi.append(ret[2][0])
        buff.append((num, val))
        if num in (token.NEWLINE, token.ENDMARKER):
            buff = _replace_variable(buff)
            started = False
        elif num == tokenize.COMMENT and len(buff) == 1:
            # ignore inline comment
            buff = _replace_comment(buff)
            started = False
        if not started:
            result.extend(buff)
            # _debug_parse(tokenize.COMMENT, "> > > new buffer > > >", "???")
            buff = []
    changed = tokenize.untokenize(result)
    debug_message("Pre-processed text:\n", changed)
    return eoi, changed
예제 #7
0
def comm2study(content, stage, strict=ConversionLevel.NoFail):
    """Import a text of code_aster commands into the *Stage* object.

    Arguments:
        content (str): Text of code_aster commands to import.
        stage (Stage): *Stage* in which the *Command* objects are added.
        strict (ConversionLevel): Tells how strict the conversion must be.
            See `general.ConversionLevel` for more details.
            Default is not to fail.
    """
    nbs = stage.parent_case.nb_stages
    debug_message("starting new conversion of stage", stage.number, "/", nbs)
    assert not strict & ConversionLevel.Partial or stage.number == nbs
    builder = CommandBuilder(stage, strict)

    try:
        builder.convert(content)
        stage.reorder()
    finally:
        builder.reset_callbacks()
예제 #8
0
def _locate_error(exc, eoi, text):
    """Return the line number and the line where the exception occurred.

    Returns:
        int: Line number of the end of the previous (successfull) instruction.
        int: Line number of the error.
        line: Line content where the error occurred.
    """
    if isinstance(exc, SyntaxError):
        lineno = exc.args[1][1]
        line = exc.args[1][3].strip()
    else:
        # 0: here, 1: executed text
        ltb = traceback.extract_tb(sys.exc_info()[-1], limit=3)
        try:
            tbck = ltb[1]
            lineno = tbck[1]
        except IndexError: # pragma: no cover
            lineno = -1

    debug_message("Error at line", lineno, "end of instr", eoi)
    lines = text.splitlines()
    upto = []
    offset = 0
    for i in eoi:
        if i >= lineno:
            break
        orig = i - offset
        if lines[i - 1].startswith("raise NotImplementedError"):
            offset += 1
        else:
            upto.append(orig)

    eoprev = upto.pop(-1) if upto else 0
    debug_message("Previous instr at line", eoprev, "(original text)")

    if not isinstance(exc, SyntaxError):
        line = lines[lineno - 1] if len(lines) > lineno - 2 else "?"

    return eoprev, lineno, line
예제 #9
0
    def _insert_id(self, command):
        """Insert a command at the right position."""
        self._discard_position(command)
        idx = 0

        ids = self._ids
        cmdid = command.uid
        for i, uid in enumerate(ids):
            # if command is a child of cmd_i
            if self._model.has_path(uid, cmdid):
                pass
            # elif cmd_i is a child of command:
            elif self._model.has_path(cmdid, uid):
                break
            # no direct dependencies
            else:
                # if command depends on a command that follows,
                # do not use other criteria
                deps = False
                for idj in ids[i + 1:]:
                    # if command is a child of cmd_idj:
                    if self._model.has_path(idj, cmdid):
                        deps = True
                        break
                if deps:
                    idx += 1
                    continue
                cmd_i = self.get_cmd(uid)
                if command.categ < cmd_i.categ:
                    # debug_message("criteria: category", level=2)
                    break
                elif command.categ == cmd_i.categ:
                    if command.uid < uid:
                        # debug_message("criteria: creation order", level=2)
                        break
            idx += 1

        debug_message("insert at", idx, ':', command.title, repr(command))
        ids.insert(idx, command.uid)
예제 #10
0
    def _fill_categories(self):
        """Fill categories map."""
        not_found_msg = "Command {0} is not found in catalogue"

        # 0. First of all add special category for variables
        self._command_to_category['_CONVERT_VARIABLE'] = 'Variables'
        self._categories['Variables'] = []

        # 1. Fill in categories in proper order
        for category in CATEGORIES_DEFINITION:
            self._categories[category] = []
            for name in CATEGORIES_DEFINITION[category]:
                command = self._catalogs.get(name)
                if not command:
                    debug_message(not_found_msg.format(name))
                else:
                    self._categories[category].append(name)
                    self._command_to_category[name] = category

        # Finally, add a category for deprecated commands
        self._categories['Other'] = []
        self._categories['Deprecated'] = []
        self._categories['Hidden'] = []
        for name in DEPRECATED:
            self._categories['Deprecated'].append(name)
            self._command_to_category[name] = 'Deprecated'

        # 2. Put remaining commands to the 'Other' category
        for name in self._catalogs:
            if self._command_to_category.get(name):
                continue
            # fake commands starts with "_": hidden
            if name.startswith("_"):
                category = 'Hidden'
            else:
                category = 'Other'
            self._categories[category].append(name)
            self._command_to_category[name] = category
        self._categories['Other'].sort()
예제 #11
0
def document2history(bdocument, strict=STRICT_DEFAULT, aster_version=None):  # pragma pylint: disable=too-many-locals
    """Converts AsterStudy ProtoBuffer message to History instance

    Arguments:
        bdocument (BDocument): AsterStudy ProtoBuffer document.
        strict (Optional[ConversionLevel]): Tells how strict the conversion
            must be.
        aster_version (Optional[str]): code_aster version used instead of those
            stored in the document.
    """
    from .history import History
    from common import ConversionError
    from .dataset import DataSet
    from .result import Job

    bhistory = bdocument.history
    history = History(bhistory.aster if aster_version is None \
                      else aster_version)
    bvers = bhistory.versionMajor, bhistory.versionMinor, bhistory.versionPatch
    if bvers != history.version_number:
        sbvers = ".".join([str(i) for i in bvers])
        snumb = ".".join([str(i) for i in history.version_number])
        msgerr = ("The study was created using the '{0}' version as {1} "
                  "but the available '{0}' version is {2}").format(
                      history.version, sbvers, snumb)
        if strict & ConversionLevel.Restore:
            raise ValueError(msgerr)
        else:
            debug_message(msgerr)
    history.jobs_list = bhistory.jobs_list

    uid2stage = {}
    for idx, bcase in enumerate(bhistory.cases):
        name = bcase.name
        if idx == 0:
            case = history.current_case
            case.name = name
        else:
            case = history.create_case(name)
예제 #12
0
    def save(self, directory, url):
        """
        Save module data to files; returns file names.

        The function saves the module data to the files in a temporary
        directory specified as a parameter and returns names if files in
        which module data is saved.

        Arguments:
            directory (str): A directory to store data files. Note: this
                can be not a final study destination folder but a
                temporary directly, depending on used save mode
                (single-file or multi-file).

            url (str): Actual study URL (the final study destination).
                Note: this parameter is provided for information
                purposes only! Depending on version of SALOME being used
                this parameter may be empty!

        Returns:
            list[str]: names of files in which data is saved
        """
        try:
            study_name = get_salome_pyqt().getStudyName() + "_"
        except AttributeError:
            study_name = get_base_name(url, False) + "_" if url else ""
        ajs = "{}asterstudy.{}".format(study_name, study_extension())
        path = os.path.join(directory, ajs)
        debug_message("salomegui.save(): ajs: {0}, url: {1}".format(ajs, url))
        self.study().set_url(url)
        try:
            self.study().saveAs(path)
        except IOError:
            ajs = ""
        self._updateActions()
        files = [to_str(ajs)]
        files.extend(self.study().history.save_embedded_files(directory))
        return files
예제 #13
0
    def load(self, files, url):
        """
        Load data from the files; return result status.

        The function restores module data from the files specified as a
        parameter; returns *True* in case of success or *False*
        otherwise.

        Arguments:
            files (list[str]): Data files in which module data is
                stored. Note: first element of this list is a directory
                name. File names are normally specified as relative to
                this directory.

            url (str): Actual study URL (the original study file path).
                Note: this parameter is provided for information
                purposes only! Depending on version of SALOME being used
                this parameter may be empty!

        Returns:
            bool: *True* in case of success; *False* otherwise
        """
        debug_message("salomegui.load(): url: {0}, files: {1}".format(
            url, files))
        # do nothing if url is empty
        if not url:
            return False
        try:
            ajs = os.path.join(files[0], files[1])
            self._setStudy(Study.load(self, ajs, url))
            self.study().set_url(url)
            self.study().loadEmbeddedFilesWrapper(files[0], files[2:])
            return True
        except IOError:
            pass
        return False
예제 #14
0
def _check_deleters(command, deleters):
    """Check if a Command reuse a name of a previously deleted result.
    In this case, the Command must depend on the deleter.

    Arguments:
        command (Command): Command currently checked.
        deleters (dict): Dict `{deleted: deleter}`.
    """
    delnames = [i.name for i in deleters.keys()]
    name = command.name
    if name in ('', '_'):
        return

    if name in delnames:
        # add a dependency to DETRUIRE of the previous 'name'
        delcmds = [(i, val) for i, val in deleters.iteritems() \
                       if i.name == name and i != command]
        if not delcmds:
            return
        key, deleter = delcmds[0]
        del deleters[key]
        debug_message("add deps {0.title}<{0.uid}> vers {1.title}<{1.uid}>"
                      .format(command, deleter))
        add_parent(command, deleter)
예제 #15
0
    def add_text_stage(self, text):
        """Add a text stage for the text that can not be converted.

        Arguments:
            text (str): The text that can not be converted.
        """
        debug_message("add a text stage containing:\n", text)
        stg = self._stg
        case = self._stg.parent_case
        if stg.number != case.nb_stages:
            # a text stage was already inserted: concatenate
            stg = case[case.nb_stages - 1]
            text = stg.get_text(pretty=False) + os.linesep + text
        elif len(stg) != 0:
            # some commands have been added, create a new text stage
            newname = "{0}_{1}".format(stg.name, case.nb_stages)
            stg = case.create_stage(newname)

        try:
            text = format_code(text)
        except SyntaxError:
            pass
        stg.use_text_mode()
        stg.set_text(text)
예제 #16
0
    def read_catalogs(self, version=None):
        """
        Read all catalogs.

        Arguments:
            version (str): Version of code_aster catalogs.
        """
        if version and version == self._version:
            debug_message("Catalog for {0!r}: already loaded".format(version))
            return

        self.reset()
        if not version:
            version = CFG.default_version
        debug_message("Loading catalog for {0!r}".format(version))
        version_path = self.version_path(version)
        debug_message("from path {0!r}".format(version_path))

        # Enable marker
        AsterStudySession.set_cata()
        try:
            self._pkgs = import_aster(version_path)
            commands = self._pkgs["Commands"].__dict__
        except ImportError as exc:
            debug_message("Can not import version {0!r}\nReason: {1}"
                          .format(version_path, exc))
            commands = {}

        if commands:
            self._add_conversion_commands()
        for key, value in commands.iteritems():
            if get_cata_typeid(value) == IDS.command:
                self._catalogs[key] = value

        self._fill_categories()
        self._version = version
        self._read_dockeys()
예제 #17
0
    def _post_conversion(self):
        """Post-conversion function to name the results in *Command* objects.

        Arguments:
            _locals (dict): Context of the comm file.
        """
        _locals = self._exec_ctxt
        _unauthorized = [i for i in CATA]
        # store the name of code_aster datastructures
        result_names = {}
        for name, result in _locals.viewitems():
            if isinstance(result, CATA.baseds):
                if name in _unauthorized:
                    raise ValueError("Unauthorized name: {0!r}".format(name))
                result_names[result] = name
                debug_message("naming result", result, "as", name)
        # store results names in Command objects and evaluate user variables
        results = result_names.keys()
        # it is important to loop on commands by creation order for DETRUIRE
        deleters = OrderedDict()
        for cmd in self._stg:
            if cmd in self._del:
                deleters[cmd] = self._del[cmd]
            _check_deleters(cmd, deleters)

            result = self._cmd_results.get(cmd)
            if result is None:
                continue

            if result in results:
                cmd.name = result_names[result]
                debug_message("naming result of", cmd.title, ":", cmd.name)
            elif cmd in self._reuse:
                # because of tolerated syntax "cmd(reuse='xx', ...)"
                cmd.name = self._reuse[cmd].name
                debug_message("reuse name for", cmd.title, ":", cmd.name)
            if self._strict & ConversionLevel.Naming and \
                    cmd.name in ('', '_'):
                raise NotImplementedError("can not name command: {0}"
                                          .format(cmd))
예제 #18
0
    def displayMEDFileName(self,
                           meshfile,
                           meshname=None,
                           opacity=1.0,
                           erase=False):
        """Redefined from *MeshBaseView*."""
        debug_message("entering displayMEDFileName...")
        import salome

        entry = self.getMeshEntry(meshfile, meshname)

        # activate Asterstudy's VTK view with help of the SalomePyQt utility of
        # SALOME's GUI module
        from ..salomegui import get_salome_pyqt
        get_salome_pyqt().activateViewManagerAndView(self._vtk_viewer)

        if meshfile == self._displayed_mesh[0] \
            and meshname == self._displayed_mesh[1] \
            and not erase:
            self.setAspect(entry, opacity)
            salome.sg.UpdateView()
            debug_message("displayMEDFileName return #1")
            return

        # display the entry in the active view with help of the `sg` python
        # module of `salome` python package

        for dentry in self._diplayed_entry:
            self._diplayed_entry[dentry] = 0
        salome.sg.EraseAll()
        salome.sg.Display(str(entry))

        self._diplayed_entry[entry] = 1
        self._displayed_mesh = (meshfile, meshname)
        self.setAspect(entry, opacity)

        salome.sg.FitAll()
        salome.sg.UpdateView()
        debug_message("displayMEDFileName return final")
예제 #19
0
        if strict & ConversionLevel.Restore:
            raise ValueError(msgerr)
        else:
            debug_message(msgerr)
    history.jobs_list = bhistory.jobs_list

    uid2stage = {}
    for idx, bcase in enumerate(bhistory.cases):
        name = bcase.name
        if idx == 0:
            case = history.current_case
            case.name = name
        else:
            case = history.create_case(name)

        debug_message("loading case {0!r}...".format(name))
        case.base_folder = bcase.base_folder

        case.description = bcase.description
        case.is_backup = bcase.is_backup
        if bcase.in_dir:
            case.in_dir = bcase.in_dir
        if bcase.out_dir:
            case.out_dir = bcase.out_dir

        debug_message("loading stages...")
        for stageid in bcase.stages:
            if stageid in uid2stage:
                case.add_stage(uid2stage[stageid])
            else:
                bstage = bhistory.stages[stageid - 1]
예제 #20
0
    def _exec_command(self, ascommand, **kwargs):
        """Execution of the *ascommand*."""
        debug_message("executing aster command", ascommand.name)
        parents = []
        if len(self._stg) > 0:
            last = self._stg.dataset.get_last_command()
            if last.title == "_CONVERT_COMMENT":
                if ascommand.name == "_CONVERT_COMMENT":
                    # append the text of the comment to the previous comment
                    debug_message("append to last comment", kwargs)
                    last["EXPR"] = last["EXPR"].value + "\n" + kwargs["EXPR"]
                    return
                # add a dependency to the previous comment
                parents.append(last)

        kwargs = add_reuse_badcommands(ascommand, kwargs)
        kwargs = add_unit_default_value(ascommand, kwargs)
        result = ascommand.call_default(__strict__=self._strict, **kwargs)
        debug_message("creating Command for", ascommand.name)
        command = self.add_command(ascommand.name, **kwargs)
        # store the result produced by the Command.
        if result is not None:
            self._cmd_results[command] = result
            self._results_cmd[result] = command
            debug_message("result stored for", command.title, result)

        # DETRUIRE
        if command.title == "DETRUIRE":
            concept = command["CONCEPT"]
            if isinstance(concept, Factor):
                concept = [concept, ]
            for fact in concept:
                names = fact["NOM"].value
                if not isinstance(names, (list, tuple)):
                    names = [names, ]
                for cmd in names:
                    self._del[cmd] = command

        # if a macro-command produces additional results
        for hidden in command.hidden:
            hidden.check(safe=False)
            self._exec_ctxt[hidden.name] = hidden

        # In case of "reuse", a command result may be reset by the current
        # command, that's why we must name it now and not wait
        # for `_post_conversion()`.
        # Name previously created objects
        _locals = self._exec_ctxt
        for name, item in _locals.viewitems():
            if not isinstance(item, CATA.baseds):
                continue

            cmd = self._results_cmd[item]
            cmd.name = name
            debug_message("name updated", name, "for", cmd.title, item)

        for i in parents:
            debug_message("adding parent of", command.title, ":", i.uid)
            add_parent(command, i)

        return result
예제 #21
0
 def _set(self, store, value):
     """Set the value in dict"""
     if not store.has_key(self._current):
         debug_message("Add default value: {0}={1!r}".format(
             self._current, value))
         store[self._current] = value