Skip to content

Commit

Permalink
readme and logging
Browse files Browse the repository at this point in the history
  • Loading branch information
sbromberger committed Feb 26, 2024
1 parent 94fd278 commit c5fa3cd
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 111 deletions.
82 changes: 11 additions & 71 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,9 @@ $ cd ../.. #back to root project directory

## Running Current C++ Examples
```python
$ ipython3-3.8.2
$ CLIPPY_BACKEND_PATH=/path/to/binaries ipython3

In [1]: from clippy import clippy_import
from clippy import config
config.cmd_prefix = ''
config.loglevel = 0
In [1]: from clippy import *

╭────────────────────────────────────╮
│ It looks like you want to use HPC. │
Expand All @@ -63,73 +60,16 @@ In [1]: from clippy import clippy_import
│╰─╯│
╰───╯

In [2]: clippy_import('clippy-cpp/build/examples') # imports examples into the local environment - no namespace
howdy('Seth')
Out[2]: 'Howdy, Seth!'

In [3]: clippy_import('clippy-cpp/build/examples', namespace='examples') # imports examples into the examples namespace
examples.howdy('Seth') # can also use a named arg: examples.howdy(name='Seth')
Out[3]: 'Howdy, Seth!'

In [4]: examples.sum(1, 2)
Out[4]: 3.0

In [5]: examples.sort_edges([(5,5),(3,5),(2,2),(0,0)])
Out[5]: [[0, 0], [2, 2], [3, 5], [5, 5]]

In [6]: examples.sort_edges([(5,5),(3,5),(2,2),(0,0)], reverse=True)
Out[6]: [[5, 5], [3, 5], [2, 2], [0, 0]]

In [7]: examples.sort_strings(['zulu','yankee','whiskey','uniform','romeo','mike','kilo','foxtrot','delta','alfa'])
Out[7]:
['alfa',
'delta',
'foxtrot',
'kilo',
'mike',
'romeo',
'uniform',
'whiskey',
'yankee',
'zulu']

In [8]: examples.sort_strings(['zulu','yankee','whiskey','uniform','romeo','mike','kilo','foxtrot','delta','alfa'], reverse=True)
Out[8]:
['zulu',
'yankee',
'whiskey',
'uniform',
'romeo',
'mike',
'kilo',
'foxtrot',
'delta',
'alfa']

In [9]: examples.grumpy()
---------------------------------------------------------------------------
ClippyBackendError Traceback (most recent call last)
<ipython-input-8-bf61ad375b31> in <module>
----> 1 c.grumpy()

~/clippy/clippy.py in fn(self, *args, **kwargs)
125 #
126 # send_dict['args'] = kwargs
--> 127 j = capself.session.exec(capself.name, kwargs)
128 return j
129

~/clippy/clippy.py in exec(self, cmd, submission_dict)
196 self.logger.debug(f'run(): result = {p}')
197 if p.returncode != 0:
--> 198 raise ClippyBackendError(p.stderr)
199
200 return json.loads(p.stdout)

ClippyBackendError: terminate called after throwing an instance of 'std::runtime_error'
what(): I'm Grumpy!
```
In [2]: c = ClippyBag() # creates a bag datastructure.

In [3]: c.insert("foo").insert("bar") # mutating methods can be chained

Out[3]: foo bar

In [4]: c.size() # nonmutating methods return the appropriate output.
Out[4]: 2

```
## Authors
- Seth Bromberger (seth at llnl dot gov)
- Roger Pearce (rpearce at llnl dot gov)
Expand Down
17 changes: 12 additions & 5 deletions src/clippy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,21 @@
import logging
from . import config

logger = logging.Logger('clippy')
logger.setLevel(logging.DEBUG)
# logging.basicConfig()
logfmt = logging.Formatter(config.logformat)
logger = logging.getLogger(__name__)

handler = logging.StreamHandler()
handler.setFormatter(logfmt)
handler.setLevel(config.loglevel)
logger.addHandler(handler)
logger.setLevel(config.loglevel)

def load_classes():

def load_classes(l: logging.Logger):
for backend in config.CLIPPY_BACKENDS:
for name, c in backend.classes().items():
for name, c in backend.classes(l).items():
globals()[name] = c


load_classes()
load_classes(logger)
23 changes: 5 additions & 18 deletions src/clippy/backends/execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@
from .serialization import encode_clippy_json, decode_clippy_json


def _exec(
cmd: list[str], submission_dict: AnyDict, logger: logging.Logger, validate: bool
) -> CompletedProcess:
def _exec(cmd: list[str], submission_dict: AnyDict, logger: logging.Logger, validate: bool) -> CompletedProcess:
'''
Internal function.
Expand All @@ -39,26 +37,17 @@ def _exec(
execcmd = config.cmd_prefix.split() + cmd

logger.debug('Calling %s with input %s', execcmd, cmd_stdin)
p = run(
execcmd, input=cmd_stdin, capture_output=True, encoding='utf-8', check=False
)
p = run(execcmd, input=cmd_stdin, capture_output=True, encoding='utf-8', check=False)
logger.debug('run(): result = %s', p)
print(f'run(): result = {p}')

return p


def _parse(
p: CompletedProcess, logger: logging.Logger, validate: bool
) -> tuple[AnyDict | None, str | None]:
def _parse(p: CompletedProcess, logger: logging.Logger, validate: bool) -> tuple[AnyDict | None, str | None]:
'''Given a CompletedProcess, process the output. Returns JSON dict
from stdout and any stderr that has been generated.'''
if p.returncode:
raise (
ClippyValidationError(p.stderr)
if validate
else ClippyBackendError(p.stderr)
)
raise (ClippyValidationError(p.stderr) if validate else ClippyBackendError(p.stderr))

if p.stderr:
logger.warning('Received stderr: %s', p.stderr)
Expand All @@ -76,9 +65,7 @@ def _exec_and_parse(
return _parse(p, logger, validate)


def _validate(
cmd: str | list[str], dct: AnyDict, logger: logging.Logger
) -> tuple[bool, str]:
def _validate(cmd: str | list[str], dct: AnyDict, logger: logging.Logger) -> tuple[bool, str]:
'''
Converts the dictionary dct into a json file and calls executable cmd.
Returns true/false (validation successful) and any stderr.
Expand Down
26 changes: 10 additions & 16 deletions src/clippy/backends/fs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,52 +21,47 @@
from ...error import ClippyConfigurationError, ClippyTypeError, ClippyValidationError

PATH = sys.path[0]
logger = logging.Logger('init')
logger.setLevel(logging.DEBUG)


def classes() -> dict[str, Any]:
def classes(logger: logging.Logger) -> dict[str, Any]:
paths = config.CLIPPY_FS_BACKEND_PATHS
_classes = {}
# print(f'{paths=}')
for path in paths:
files = os.scandir(path)
# print(f' {classes=}')
for f in files:
if f.name in config.CLIPPY_FS_EXCLUDE_PATHS:
continue
p = pathlib.Path(path, f)
# print(f' {p=}, {os.path.isdir(p)=}')
if os.path.isdir(p):
print(f'appending class at {p=}')
_cls = _create_class(f.name, path)
_cls = _create_class(f.name, path, logger)
_classes[f.name] = _cls
# cmds = get_registered_commands(logger, {'foo': pathlib.Path(origin, name)})
# type(name, (), cmds)
return _classes


# All backends must have a "classes" function that returns a class that can be added to Clippy.
def _create_class(name: str, path: str):
print(f'creating class {name=}, {path=}')
def _create_class(name: str, path: str, logger: logging.Logger):
metafile = pathlib.Path(path, name, CLASS_META_FILE)
meta = {}
if metafile.exists():
with open(metafile, 'r', encoding='utf-8') as json_file:
meta = json.load(json_file)
meta['_name'] = name
meta['_path'] = path
meta['logger'] = logger
class_logger = logging.getLogger(logger.name + '.' + name)
class_logger.setLevel(topconfig.loglevel)
meta['logger'] = class_logger

cls = type(name, (ClippySerializable,), meta)
classpath = pathlib.Path(path, name)
for file in os.scandir(classpath):
fullpath = pathlib.Path(classpath, file)
print(f' checking {file.name=}, {fullpath=}')
if os.access(fullpath, os.X_OK) and file.is_file():
try:
_process_executable(str(fullpath), cls)
except ClippyConfigurationError as e:
print(f'error processing {fullpath}: {e}i; ignoring.')
logger.warning("error processing %s: %s; ignoring", fullpath, e)

return cls

Expand All @@ -80,12 +75,12 @@ def _process_executable(executable: str, cls):
symtable (by default globals()).
'''

print(f'processing executable {executable}')
cls.logger.debug('processing executable %s', executable)
# name = os.path.basename(executable)
cmd = [executable, JSON_FLAG]
# open file, will be received through std out
try:
j = _run(cmd, {}, logger)
j = _run(cmd, {}, cls.logger)

except CalledProcessError as e:
raise ClippyConfigurationError("Execution error " + e.stderr) from e
Expand All @@ -96,7 +91,6 @@ def _process_executable(executable: str, cls):
if not _check_version(j):
raise ClippyConfigurationError("Invalid version information in " + executable)

print(f'{j=}')
docstring = j.get("desc", "")
args = j.get("args", {})
method = j["method_name"]
Expand Down
6 changes: 5 additions & 1 deletion src/clippy/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

""" The clippy configuration file. To be edited by users. """

import logging

from .anydict import AnyDict
from .backends import fs

Expand Down Expand Up @@ -33,7 +35,9 @@
validate_cmd_prefix = ''

# contol the log level of clippy
loglevel: int = 0
loglevel: int = logging.DEBUG

logformat: str = '%(asctime)s [%(filename)s:%(lineno)d (%(funcName)s) %(levelname)s: %(message)s'

# PRIVATE: this dict contains the class types that clippy has constructed.
# once constructed clippy will get the definition from this dict
Expand Down

0 comments on commit c5fa3cd

Please sign in to comment.