<commit_before># Copyright (c) 2018 <NAME>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
"""
This module extends the Craftr core context methods and members required for
the evaluation of Craftr build modules via the Craftr DSL. The DSL context
creates a child Node.py context with the ability to load Craftr modules.
"""

from nr import path
from nr.datastructures.mappings import ChainDict, MappingFromObject
from nodepy.utils import pathlib

import nodepy
import shutil
import {CraftrModuleLoader, do_link} from './nodepy_glue'
import core from '../core'

STDLIB_DIR = module.package.directory.joinpath('craftr-stdlib')


class ModuleOptions:

  def __init__(self, name, context):
    self._name = name
    self._data = {}
    self._context = context

  def __repr__(self):
    return 'ModuleOptions({!r}, {!r})'.format(self._name, self._data)

  def __getattr__(self, key):
    try:
      return self._data[key]
    except KeyError:
      raise AttributeError(key)

  def __setattr__(self, key, value):
    if key not in ('_name', '_data', '_context'):
      self._data[key] = value
    else:
      super().__setattr__(key, value)

  def setdefault(self, key, value):
    return self._context.options.setdefault(self._name + ':' + key, value)


class DslModule(core.Module):

  nodepy_module = None

  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.options = ModuleOptions(self.name, self.context)

  def init_namespace(self, ns):
    ns.module = self
    ns.options = self.options

  @property
  def scope(self):
    assert self.nodepy_module, "DslModule.nodepy_module is not set"
    return MappingFromObject(self.nodepy_module.namespace)


class DslTarget(core.Target):

  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self._scope = {'target': self}

  @property
  def scope(self):
    return ChainDict(self._scope, self.module.scope)


class DslDependency(core.Dependency):

  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self._scope = {'dependency': self}

  @property
  def scope(self):
    return ChainDict(self._scope, self.target.scope)


class Context(core.Context):

  module_class = DslModule
  target_class = DslTarget
  dependency_class = DslDependency

  def __init__(self, build_variant, build_directory, load_builtins=True):
    super().__init__()
    self.module_links_dir = path.join(build_directory, '.module-links')

    self.loader = CraftrModuleLoader(self)
    self.nodepy_context = nodepy.context.Context(parent=require.context)
    self.nodepy_context.resolver.loaders.append(self.loader)
    self.nodepy_context.resolver.paths.append(STDLIB_DIR)
    self.nodepy_context.resolver.paths.append(pathlib.Path(self.module_links_dir))

    # TODO:  Use the nearest available .nodepy/modules directory?
    self.nodepy_context.resolver.paths.append(pathlib.Path(require.context.modules_directory))

    self.build_variant = build_variant
    self.build_directory = build_directory
    self.options = {}
    self.builtins = {'context': self}
    self.require = self.nodepy_context.require

    if load_builtins:
      module = self.require('craftr', exports=False)
      assert module.context is self.nodepy_context
      module = module.namespace
      for key in module.__builtins__:
        self.builtins[key] = getattr(module, key)

    # Remove the build directories module links directory.
    if path.isdir(self.module_links_dir):
      shutil.rmtree(self.module_links_dir)

  def load_module(self, name):
    mod = self.require(name + '.craftr', exports=False)
    return mod.craftr_module

  def load_module_from_file(self, filename, raw=False):
    module = self.loader.load_module(self.nodepy_context, None, filename)
    self.nodepy_context.register_module(module)
    self.nodepy_context.load_module(module)
    if not raw:
      module = module.craftr_module
    return module

  def link_module(self, parent_dir, module_path):
    """
    This method is called when a `link_module` statement is used in a Craftr
    build script in order to establish a temporary link for the current build
    session to that module.

    This writes a `.nodepy-link` file to the build directories `.module-links`
    directory which is then scanned on imports by Node.py. Every time the
    build system is reconfigured, the `.module-links` directory is flushed.
    """

    do_link(path.canonical(module_path, parent_dir), module_dir=self.module_links_dir)

  def report_property_does_not_exist(self, filename, loc, prop_name, propset):
    print('warn: {}:{}:{}: property {} does not exist'.format(
      filename, loc.lineno, loc.colno, prop_name))
<commit_msg>add DslTarget.set_props()<commit_after># Copyright (c) 2018 <NAME>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
"""
This module extends the Craftr core context methods and members required for
the evaluation of Craftr build modules via the Craftr DSL. The DSL context
creates a child Node.py context with the ability to load Craftr modules.
"""

from nr import path
from nr.datastructures.mappings import ChainDict, MappingFromObject
from nodepy.utils import pathlib

import nodepy
import shutil
import {CraftrModuleLoader, do_link} from './nodepy_glue'
import core from '../core'

STDLIB_DIR = module.package.directory.joinpath('craftr-stdlib')


class ModuleOptions:

  def __init__(self, name, context):
    self._name = name
    self._data = {}
    self._context = context

  def __repr__(self):
    return 'ModuleOptions({!r}, {!r})'.format(self._name, self._data)

  def __getattr__(self, key):
    try:
      return self._data[key]
    except KeyError:
      raise AttributeError(key)

  def __setattr__(self, key, value):
    if key not in ('_name', '_data', '_context'):
      self._data[key] = value
    else:
      super().__setattr__(key, value)

  def setdefault(self, key, value):
    return self._context.options.setdefault(self._name + ':' + key, value)


class DslModule(core.Module):

  nodepy_module = None

  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.options = ModuleOptions(self.name, self.context)

  def init_namespace(self, ns):
    ns.module = self
    ns.options = self.options

  @property
  def scope(self):
    assert self.nodepy_module, "DslModule.nodepy_module is not set"
    return MappingFromObject(self.nodepy_module.namespace)


class DslTarget(core.Target):

  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self._scope = {'target': self}

  @property
  def scope(self):
    return ChainDict(self._scope, self.module.scope)

  def set_props(self, export, props):
    container = self.exported_props if export else self.props
    for key, value in props.items():
      if key.startswith('+'):
        key = key[1:]
        container[key] += value
      else:
        container[key] = value


class DslDependency(core.Dependency):

  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self._scope = {'dependency': self}

  @property
  def scope(self):
    return ChainDict(self._scope, self.target.scope)


class Context(core.Context):

  module_class = DslModule
  target_class = DslTarget
  dependency_class = DslDependency

  def __init__(self, build_variant, build_directory, load_builtins=True):
    super().__init__()
    self.module_links_dir = path.join(build_directory, '.module-links')

    self.loader = CraftrModuleLoader(self)
    self.nodepy_context = nodepy.context.Context(parent=require.context)
    self.nodepy_context.resolver.loaders.append(self.loader)
    self.nodepy_context.resolver.paths.append(STDLIB_DIR)
    self.nodepy_context.resolver.paths.append(pathlib.Path(self.module_links_dir))

    # TODO:  Use the nearest available .nodepy/modules directory?
    self.nodepy_context.resolver.paths.append(pathlib.Path(require.context.modules_directory))

    self.build_variant = build_variant
    self.build_directory = build_directory
    self.options = {}
    self.builtins = {'context': self}
    self.require = self.nodepy_context.require

    if load_builtins:
      module = self.require('craftr', exports=False)
      assert module.context is self.nodepy_context
      module = module.namespace
      for key in module.__builtins__:
        self.builtins[key] = getattr(module, key)

    # Remove the build directories module links directory.
    if path.isdir(self.module_links_dir):
      shutil.rmtree(self.module_links_dir)

  def load_module(self, name):
    mod = self.require(name + '.craftr', exports=False)
    return mod.craftr_module

  def load_module_from_file(self, filename, raw=False):
    module = self.loader.load_module(self.nodepy_context, None, filename)
    self.nodepy_context.register_module(module)
    self.nodepy_context.load_module(module)
    if not raw:
      module = module.craftr_module
    return module

  def link_module(self, parent_dir, module_path):
    """
    This method is called when a `link_module` statement is used in a Craftr
    build script in order to establish a temporary link for the current build
    session to that module.

    This writes a `.nodepy-link` file to the build directories `.module-links`
    directory which is then scanned on imports by Node.py. Every time the
    build system is reconfigured, the `.module-links` directory is flushed.
    """

    do_link(path.canonical(module_path, parent_dir), module_dir=self.module_links_dir)

  def report_property_does_not_exist(self, filename, loc, prop_name, propset):
    print('warn: {}:{}:{}: property {} does not exist'.format(
      filename, loc.lineno, loc.colno, prop_name))

{'fraction_non_alphanumeric': 0.09732089360609432, 'fraction_numerical': 0.0007703500813147308, 'mean_word_length': 4.102183406113537, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '880386', 'n_tokens_mistral': 3544, 'n_tokens_neox': 3437, 'n_words': 1079}