Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-running script with imported modules may crash #104

Closed
fragmuffin opened this issue Oct 14, 2017 · 10 comments
Closed

Re-running script with imported modules may crash #104

fragmuffin opened this issue Oct 14, 2017 · 10 comments

Comments

@fragmuffin
Copy link
Member

Steps to re-create

  1. Create a local file ~/temp/my_module/__init__.py with contents...
import logging
root = logging.getLogger()
root.setLevel(logging.INFO)

# FreeCAD Logging Handler
class FreeCADConsoleHandler(logging.Handler):
    def emit(self, record):
        log_text = self.format(record) + "\n"
        if record.levelno >= logging.ERROR:
            FreeCAD.Console.PrintError(log_text)
        elif record.levelno >= logging.WARNING:
            FreeCAD.Console.PrintWarning(log_text)
        else:
            FreeCAD.Console.PrintMessage(log_text)

import cadquery # necessary to import FreeCAD
import FreeCAD
FreeCAD.Console  # will raise exception if not available

freecad_handler = FreeCADConsoleHandler()
freecad_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(message)s')
freecad_handler.setFormatter(formatter)

root.addHandler(freecad_handler)
  1. open FreeCAD, and start a new cadquery script, copy this in...
import sys
import os
sys.path.append(os.path.join(os.environ['HOME'], 'temp'))
import my_module

import logging
log = logging.getLogger(__name__)
log.info('hi there')
  1. run the script (eg: with F2)
  2. run it again (eg: with F2)

Expectation

log output should show "hi there" twice, having run the script successfully twice

hi there
Executed ~/.FreeCAD/Mod/cadquery_module/Templates/script_template.py
hi there
Executed ~/.FreeCAD/Mod/cadquery_module/Templates/script_template.py

Actual Results
The script runs successfully the first time, but has trouble with the value of logging on the second run.

hi there
Executed ~/.FreeCAD/Mod/cadquery_module/Templates/script_template.py
Running the Python command 'CadQueryExecuteScript' failed:
Traceback (most recent call last):
  File "/home/nymphii/.FreeCAD/Mod/cadquery_module/Gui/Command.py", line 223, in Activated
    imp.load_source('temp_module', tempFile.name)
  File "/tmp/tmpK2L3Sh", line 8, in <module>
    log.info('hi there')
  File "/usr/lib/python2.7/logging/__init__.py", line 1167, in info
    self._log(INFO, msg, args, **kwargs)
  File "/usr/lib/python2.7/logging/__init__.py", line 1286, in _log
    self.handle(record)
  File "/usr/lib/python2.7/logging/__init__.py", line 1296, in handle
    self.callHandlers(record)
  File "/usr/lib/python2.7/logging/__init__.py", line 1336, in callHandlers
    hdlr.handle(record)
  File "/usr/lib/python2.7/logging/__init__.py", line 759, in handle
    self.emit(record)
  File "/home/nymphii/temp/my_module/__init__.py", line 9, in emit
    if record.levelno >= logging.ERROR:

'NoneType' object has no attribute 'ERROR'

Work-around
Close FreeCAD, then re-open it

Isolated to logging?
root-cause not determined yet, so I don't know

Introduced by: #103 (sorry 😟)

@jmwright
Copy link
Member

I tried a less sophisticated version of module unloading a year or two ago and abandoned it because I had trouble getting it to work. At the time I felt there was something weird about the Python execution environment, but never figured out if I was right about that. It seems like you're code should be really close to working, and it's a needed feature.

What happens if you force the script to run using CQGI by adding something like this at the bottom?

result = cq.Workplane('XY').box(1, 1, 1)
show_object(result)

@jmwright
Copy link
Member

Here's the issue related to that earlier attempt. I think CQGI takes care of it when you're displaying a model, but I didn't think about the cases where someone doesn't run show_object.

#58

@fragmuffin
Copy link
Member Author

@jmwright

It seems like you're code should be really close to working, and it's a needed feature

I agree!, I think it's necessary to have a pure python method of running scripts that works inside FreeCAD, and outside, so the same script can be easily debugged in FreeCAD without "switching" code on and off, or having show_object in an ugly try block.

If anyone else experiences this issue, please "+1" 👍 this issue, or comment here.
So we know that others are experiencing it.

It may be isolated to logging (I have a theory, but don't know how to test it), in which case this may be an isolated problem.

@jmwright please let me know if you're concerned about this issue, and I'll prioritise finding a root cause... otherwise this is fairly low on my priority list

@jmwright
Copy link
Member

@fragmuffin This is the next item on my CadQuery list. I'm hoping we can figure it out, but if it ends up being a huge time sink, and it only causes problems in a few edge cases, it may be forced down the priority list. It's unfortunate, but there's so much going on with CadQuery right now, and there's just not enough time for everything.

@jmwright
Copy link
Member

By unfortunate I mean that it's unfortunate that I don't have more time. Having a lot going on in the CadQuery community is a good thing.

@jmwright
Copy link
Member

@fragmuffin I've started looking into this and I can reproduce the error, I'm just not sure where it's coming from yet. I swapped load_source() out for execfile() and it didn't change anything. I did notice a couple of things though.

  1. If I copy the code from the module into the main script (modifying it as needed) in FreeCAD, there's no error related to logging.
  2. Even if I comment out import my_module the error will still keep referencing the module each time I execute the script.

@fragmuffin
Copy link
Member Author

@jmwright this issue is at the top of my cadquery todo list; I haven't forgotten, I've just got a few other projects I need to finish first.
It seems I've made some inaccurate assumptions about importing.

To clarify point 2:
Do you run the script as documented once.
Then remove import my_module and run a 2nd time?

@jmwright
Copy link
Member

It seems I've made some inaccurate assumptions about importing.

FreeCAD has always seemed a little weird about importing.

Do you run the script as documented once.
Then remove import my_module and run a 2nd time?

Correct. My next step was going to be to check the script's temporary file to make sure it's changing, but I have no reason to believe that mechanism is broken.

@jmwright
Copy link
Member

CQGI (CadQuery Gateway Interface) uses the Python ast module to execute a script in a constructed environment. I'm wondering if I should switch to that way of running scripts.

https://github.com/dcowden/cadquery/blob/master/cadquery/cqgi.py#L109

@dcowden
Copy link
Member

dcowden commented Oct 24, 2017

@jmwright for an example , have a look at the docker-cli branch-- cq_cmd.py has most of the boilerplate you need to use cqgi to run scripts. the cqgi part is only a few lines, but there tends to be other common code like setting extra paramters, checking output formats, etc.
I'd be intersted to see how much of the code in cq_cmd.py you end up needing to duplicate in your application. That code would be candidates to move into cqgi itself.

As an example, when writing cq_cmd.py, it was clear to me that some kind of 'check that this export format is valid' function, and a function to set parameters using a dictionary, would be nice additions to cqgi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants