Search code examples
python-3.xclipsclipspy

CLIPS Python3 CLIPSError


I've run into a bit of an issue with some CLIPSpy code. I've narrowed down the issue to either the encode method of CLIPS_CONSTRUCTS.encode() or the environment.load(constructs_file.name). The goal I'm trying to capture is to fire a rule when the oil temp is above 32 and the oil pressure is above 0. I've attached the SampleData.csv I'm working with. This is part of my thesis research and I'd like to credit all that help me out!

  • OS and version: Windows 10 64-bit
  • Python Version: 3.7.2
  • Libraries and versions (via pip list)
    cffi 1.11.5
    clipspy 0.3.0
    pip 18.1
    pycparser 2.19
    setuptools 40.6.2

Error Received

import sys
from tempfile import NamedTemporaryFile

import clips


CLIPS_CONSTRUCTS = """
(deftemplate oil-measure
  (slot utc-time (type STRING))
  (slot temperature (type INTEGER))
  (slot pressure (type INTEGER)))

(defrule oil-is-hot
  (oil-measure (temperature ?temp) (utc-time ?time))
  (test (> ?temp 32))
  =>
  (printout t ?time tab "temperature:" tab ?temp crlf))

(defrule pressure-is-high
  (oil-measure (pressure ?press&:(> ?press 0)) (utc-time ?time))
  =>
  (printout t ?time tab "pressure:" tab ?press crlf))
"""


def main():
    environment = clips.Environment()

    # use environment.load() to load constructs from a file
    with NamedTemporaryFile() as constructs_file:
        constructs_file.write(CLIPS_CONSTRUCTS.encode())
        constructs_file.flush()

        environment.load(constructs_file.name)

    # enable fact duplication as data has duplicates
    environment.eval("(set-fact-duplication TRUE)")

    # Template facts can be built from their deftemplate
    oil_measure_template = environment.find_template("oil-measure")

    for time, temp, press in get_data_frames(sys.argv[1]):
        new_fact = oil_measure_template.new_fact()

        # Template facts are represented as dictionaries
        new_fact["utc-time"] = time
        new_fact["temperature"] = int(temp)
        new_fact["pressure"] = int(press)

        # Add the fact into the environment Knowledge Base
        new_fact.assertit()

    # Fire all the rules which got activated
    environment.run()


def get_data_frames(file_path):
    """Parse a CSV file returning the dataframes."""
    with open(file_path) as data_file:
        return [l.strip().split(",") for i, l in enumerate(data_file) if i > 1]


if __name__ == "__main__":
    main()

SampleData.csv


Solution

  • This is a limitation of NamedTemporaryFile on Windows documented here.

    You can workaround it using mkstemp or a regular file you remove yourself once done.

    constructs_file, constructs_file_name = mkstemp()
    constructs_file.write(CLIPS_CONSTRUCTS.encode())
    constructs_file.close()
    
    environment.load(constructs_file_name)
    os.remove(constructs_file_name)