Ejemplo n.º 1
0
    def get(self):
        """
        @api {GET} /express/ps/single/pricing 配送系列 - 拿计价
        @apiName ps_express_single_get_price
        @apiGroup app_ps

        @apiParam (query param) {float} weight 运单重量
        @apiParam (query param) {int} [volume_a] 运单体积-长
        @apiParam (query param) {int} [volume_b] 运单体积-宽
        @apiParam (query param) {int} [volume_c] 运单体积-高
        :return:
        """
        try:
            params = Schema(
                Or({'weight': schema_float_2}, {
                    "volume_a": schema_int,
                    "volume_b": schema_int,
                    "volume_c": schema_int
                })).validate(self.get_query_args())
        except SchemaError as e:
            logging.warn(e)
            self.resp_args_error()
            return

        fh_extra, msg, weight_max = pricing(volume=params.get('volume_a', 0) *
                                            params.get('volume_b', 0) *
                                            params.get('volume_c', 0),
                                            weight=params.get('weight', 0.0))

        self.resp(
            dict(msg=msg,
                 weight=weight_max,
                 fh_extra=fh_extra,
                 fh=15.0 + fh_extra))
Ejemplo n.º 2
0
    def test_schema_simple_get(self):
        schema_plain = {'a': {'type': int, 'get': public}}

        A = Schema(schema_plain)

        value = A.get({'a': 3})
        self.assertEqual(value, {'a': 3})
Ejemplo n.º 3
0
    def test_schema_simple_get_forbidden(self):
        schema_plain = {'a': {'type': int, 'get': private}}

        A = Schema(schema_plain)

        value = A.get({'a': 3})
        self.assertEqual(value, {})
Ejemplo n.º 4
0
    def test_schema_path_b_is_private(self):
        schema_plain = {'b': {'type': str, 'get': private}}
        B = Schema(schema_plain)

        schema_plain = {'a': {'type': B, 'set': public}}

        A = Schema(schema_plain)

        value = A.get({'a': {'b': 'hello'}})
        self.assertEqual(value, {'a': {}})
Ejemplo n.º 5
0
    def test_schema_path_b_is_current_user_miguel(self):
        schema_plain = {'b': {'type': str, 'get': current_user_is('user')}}
        B = Schema(schema_plain)

        schema_plain = {'a': {'type': B, 'set': public}, 'user': {'type': str}}

        A = Schema(schema_plain)

        with patch('schema.current_user') as mock:
            mock.return_value = 'miguel'
            value = A.get({'user': '******', 'a': {'b': 'hello'}})
            self.assertEqual(value, {'user': '******', 'a': {'b': 'hello'}})
Ejemplo n.º 6
0
    def test_schema_path_b_is_owner(self):
        schema_plain = {'b': {'type': str, 'get': is_owner}}
        B = Schema(schema_plain)

        schema_plain = {'a': {'type': B, 'set': public}}

        A = Schema(schema_plain)

        with patch('schema.current_user') as mock:
            mock.return_value = 'miguel'
            value = A.get({'__owners': ['miguel'], 'a': {'b': 'hello'}})
            self.assertEqual(value, {'a': {'b': 'hello'}})
Ejemplo n.º 7
0
    def _test_multiple_schema(my):

        # add a second schema
        new_schema = SearchType.create("sthpw/schema")
        new_schema.set_value("project_code", "unittest")
        new_schema.set_value("code", "second_schema")
        new_schema.set_value("schema", '''
<schema>
    <search_type name="test/node1"/>
    <search_type name="test/node2"/>
    <search_type name="test/node3"/>
    <search_type name="test/node4"/>
    <connect from="test/node1" to="test/node2"/>
    <connect from="test/node2" to="test/node3"/>
    <connect from="test/node3" to="test/node4"/>
</schema>''')
        new_schema.commit()

        schema = Schema.get(reset_cache=True)
        print schema.get_value("schema")
Ejemplo n.º 8
0
    def _test_multiple_schema(self):

        # add a second schema
        new_schema = SearchType.create("sthpw/schema")
        new_schema.set_value("project_code", "unittest")
        new_schema.set_value("code", "second_schema")
        new_schema.set_value("schema", '''
<schema>
    <search_type name="test/node1"/>
    <search_type name="test/node2"/>
    <search_type name="test/node3"/>
    <search_type name="test/node4"/>
    <connect from="test/node1" to="test/node2"/>
    <connect from="test/node2" to="test/node3"/>
    <connect from="test/node3" to="test/node4"/>
</schema>''')
        new_schema.commit()

        schema = Schema.get(reset_cache=True)
        print schema.get_value("schema")
Ejemplo n.º 9
0
class Feature(object):
  """
  An object composed of a set of named attributes with values.

  A feature is constructed from a ``dict`` of name value pairs and an optional identifier.

  >>> f = Feature({ 'name': 'anvil', 'price': 100.0 }, 'widgets.1')
  >>> str(f.get('name'))
  'anvil'

  A feature can also be constructed optionally with a :class:`Schema`.

  >>> from schema import Schema
  >>> s = Schema('widgets', [('name', str), ('price', float)])
  >>> f = Feature({'name': 'anvil'}, '1', s)
  >>> f
  widgets.1 {name: anvil, price: None}

  When *schema* is specified feature values can be passed a ``list``.

  >>> s = Schema('widgets', [('name', str), ('price', float)])
  >>> f = Feature(['anvil', 100.0], '1', s)
  >>> f
  widgets.1 {name: anvil, price: 100.0}
  """
  def __init__(self, atts=None, id=None, schema=None, f=None):

    from schema import Schema
    if atts:
      # attributes specified directly

      # if list specified assume values in order of schema
      if isinstance(atts, list):
        if not schema:
          raise Exception('Values may be specified as list only when schema is supplied')

        natts = {}  
        for i in range(len(atts)):
          natts[schema.fields[i].name] = atts[i]
        atts = natts

      # generate feature type if necessary
      self.schema = schema 
      if not self.schema: 
        self.schema = Schema('feature', [(att, type(val)) for att,val in atts.iteritems()])
      
      # generate feature
      b = SimpleFeatureBuilder(self.schema._type)
      for att, val in atts.iteritems(): 
        b.set(att, val)

      self._feature = b.buildFeature(str(id) if id else None)

    elif f:
      # feature specififed directly
      self._feature = f
      self.schema = schema if schema else Schema(ft=f.type)

    else:
      raise Exception('No attributes specified for feature')

  def getid(self):
    return self._feature.identifier.toString()

  id = property(getid, None)
  """
  Identifier of the feature as a ``str``

  >>> f = Feature({'name': 'anvil'}, 'widgets.1')
  >>> f.id
  'widgets.1'
  """

  def getgeom(self):
    return core.map(self._feature.defaultGeometry)

  def setgeom(self, g):
    self._feature.defaultGeometry = g

  geom = property(getgeom, setgeom)
  """
  The geometry of the feature.

  >>> import geom
  >>> f = Feature({'geom': geom.Point(1,1)})
  >>> f.geom
  POINT (1 1)
  >>> f.geom = geom.Point(2,2)
  >>> f.geom
  POINT (2 2)
  """

  def getbounds(self):
    if self.geom:
       return geom.Bounds(prj=self.schema.proj, env=self.geom.getEnvelopeInternal())

  bounds = property(getbounds)
  """
  The :class:`Bounds <geoscript.geom.bounds.Bounds>` of the feature geometry. 
  Will return ``None`` if the feature does not contain any geometric attributes.
  """

  def get(self, name):
    """
    Returns a feature attribute value by name. ``KeyError`` is thrown if the attribute does not exist.

    *name* is the name of the attribute whose value to return.

    >>> f = Feature({'name': 'anvil', 'price': 100.0})
    >>> str(f.get('name'))
    'anvil'
    """
    self.schema.get(name)
    return self._feature.getAttribute(name)

  def set(self, name, value):
    """
    Sets a feature attribute value by name. ``KeyError`` is thrown is the attribute does not exist.

    *name* is the name of the attribute whose value to set. 

    *value* is the new attribute value.

    >>> f = Feature({'name': 'anvil', 'price': 100.0})
    >>> str(f.get('name'))
    'anvil'
    >>> f.set('name', 'mallet')
    >>> str(f.get('name'))
    'mallet'
    """

    self.schema.get(name)
    self._feature.setAttribute(name, value)

  def getattributes(self):
    atts = {}
    for fld in self.schema.fields:
      atts[fld.name] = core.map(self._feature.getAttribute(fld.name))

    return atts

  attributes = property(getattributes, None)
  """
  A ``dict`` of name, value for the attributes of the feature.

  >>> f = Feature({'name': 'anvil', 'price': 100.0})
  >>> atts = f.attributes
  >>> str(atts['name'])
  'anvil'
  >>> atts['price']
  100.0
  """

  def __getitem__(self, key):
    return self.get(key)

  def __setitem__(self, key, value):
    self.set(key, value)

  def __iter__(self):
    return self.schema.__iter__()

  def iterkeys(self):
    return self.__iter__()

  def iteritems(self):
    return self.attributes.iteritems()

  def keys(self):
    return [f.name for f in self.schema.fields]

  def values(self):
    return [core.map(val) for val in self._feature.getAttributes()]

  def __repr__(self):
    atts = ['%s: %s' % (fld.name, self.get(fld.name)) for fld in self.schema.fields]

    id = self.id if self.id.startswith(self.schema.name) else '%s.%s' % (self.schema.name, self.id)
    return '%s {%s}' % (id, string.join(atts,', '))

  def __eq__(self, other):
    return other and self._feature == other._feature
Ejemplo n.º 10
0
class Config(object):  # pylint: disable=too-many-instance-attributes
    """Class that manages configuration files for a dvc repo.

    Args:
        dvc_dir (str): optional path to `.dvc` directory, that is used to
            access repo-specific configs like .dvc/config and
            .dvc/config.local.
        validate (bool): optional flag to tell dvc if it should validate the
            config or just load it as is. 'True' by default.


    Raises:
        ConfigError: thrown when config has an invalid format.
    """

    APPNAME = "dvc"
    APPAUTHOR = "iterative"

    # NOTE: used internally in RemoteLOCAL to know config
    # location, that url should resolved relative to.
    PRIVATE_CWD = "_cwd"

    CONFIG = "config"
    CONFIG_LOCAL = "config.local"

    BOOL_SCHEMA = And(str, is_bool, Use(to_bool))

    SECTION_CORE = "core"
    SECTION_CORE_LOGLEVEL = "loglevel"
    SECTION_CORE_LOGLEVEL_SCHEMA = And(Use(str.lower), supported_loglevel)
    SECTION_CORE_REMOTE = "remote"
    SECTION_CORE_INTERACTIVE_SCHEMA = BOOL_SCHEMA
    SECTION_CORE_INTERACTIVE = "interactive"
    SECTION_CORE_ANALYTICS = "analytics"
    SECTION_CORE_ANALYTICS_SCHEMA = BOOL_SCHEMA

    SECTION_CACHE = "cache"
    SECTION_CACHE_DIR = "dir"
    SECTION_CACHE_TYPE = "type"
    SECTION_CACHE_TYPE_SCHEMA = supported_cache_type
    SECTION_CACHE_PROTECTED = "protected"
    SECTION_CACHE_LOCAL = "local"
    SECTION_CACHE_S3 = "s3"
    SECTION_CACHE_GS = "gs"
    SECTION_CACHE_SSH = "ssh"
    SECTION_CACHE_HDFS = "hdfs"
    SECTION_CACHE_AZURE = "azure"
    SECTION_CACHE_SLOW_LINK_WARNING = "slow_link_warning"
    SECTION_CACHE_SCHEMA = {
        Optional(SECTION_CACHE_LOCAL): str,
        Optional(SECTION_CACHE_S3): str,
        Optional(SECTION_CACHE_GS): str,
        Optional(SECTION_CACHE_HDFS): str,
        Optional(SECTION_CACHE_SSH): str,
        Optional(SECTION_CACHE_AZURE): str,
        Optional(SECTION_CACHE_DIR): str,
        Optional(SECTION_CACHE_TYPE, default=None): SECTION_CACHE_TYPE_SCHEMA,
        Optional(SECTION_CACHE_PROTECTED, default=False): BOOL_SCHEMA,
        Optional(PRIVATE_CWD): str,
        Optional(SECTION_CACHE_SLOW_LINK_WARNING, default=True): BOOL_SCHEMA,
    }

    # backward compatibility
    SECTION_CORE_CLOUD = "cloud"
    SECTION_CORE_CLOUD_SCHEMA = And(Use(str.lower), supported_cloud)
    SECTION_CORE_STORAGEPATH = "storagepath"

    SECTION_CORE_SCHEMA = {
        Optional(SECTION_CORE_LOGLEVEL):
        And(str, Use(str.lower), SECTION_CORE_LOGLEVEL_SCHEMA),
        Optional(SECTION_CORE_REMOTE, default=""):
        And(str, Use(str.lower)),
        Optional(SECTION_CORE_INTERACTIVE, default=False):
        SECTION_CORE_INTERACTIVE_SCHEMA,
        Optional(SECTION_CORE_ANALYTICS, default=True):
        SECTION_CORE_ANALYTICS_SCHEMA,
        # backward compatibility
        Optional(SECTION_CORE_CLOUD, default=""):
        SECTION_CORE_CLOUD_SCHEMA,
        Optional(SECTION_CORE_STORAGEPATH, default=""):
        str,
    }

    # backward compatibility
    SECTION_AWS = "aws"
    SECTION_AWS_STORAGEPATH = "storagepath"
    SECTION_AWS_CREDENTIALPATH = "credentialpath"
    SECTION_AWS_ENDPOINT_URL = "endpointurl"
    SECTION_AWS_LIST_OBJECTS = "listobjects"
    SECTION_AWS_REGION = "region"
    SECTION_AWS_PROFILE = "profile"
    SECTION_AWS_USE_SSL = "use_ssl"
    SECTION_AWS_SCHEMA = {
        SECTION_AWS_STORAGEPATH: str,
        Optional(SECTION_AWS_REGION): str,
        Optional(SECTION_AWS_PROFILE): str,
        Optional(SECTION_AWS_CREDENTIALPATH): str,
        Optional(SECTION_AWS_ENDPOINT_URL): str,
        Optional(SECTION_AWS_LIST_OBJECTS, default=False): BOOL_SCHEMA,
        Optional(SECTION_AWS_USE_SSL, default=True): BOOL_SCHEMA,
    }

    # backward compatibility
    SECTION_GCP = "gcp"
    SECTION_GCP_STORAGEPATH = SECTION_AWS_STORAGEPATH
    SECTION_GCP_CREDENTIALPATH = SECTION_AWS_CREDENTIALPATH
    SECTION_GCP_PROJECTNAME = "projectname"
    SECTION_GCP_SCHEMA = {
        SECTION_GCP_STORAGEPATH: str,
        Optional(SECTION_GCP_PROJECTNAME): str,
    }

    # backward compatibility
    SECTION_LOCAL = "local"
    SECTION_LOCAL_STORAGEPATH = SECTION_AWS_STORAGEPATH
    SECTION_LOCAL_SCHEMA = {SECTION_LOCAL_STORAGEPATH: str}

    SECTION_AZURE_CONNECTION_STRING = "connection_string"
    # Alibabacloud oss options
    SECTION_OSS_ACCESS_KEY_ID = "oss_key_id"
    SECTION_OSS_ACCESS_KEY_SECRET = "oss_key_secret"
    SECTION_OSS_ENDPOINT = "oss_endpoint"

    SECTION_REMOTE_REGEX = r'^\s*remote\s*"(?P<name>.*)"\s*$'
    SECTION_REMOTE_FMT = 'remote "{}"'
    SECTION_REMOTE_URL = "url"
    SECTION_REMOTE_USER = "******"
    SECTION_REMOTE_PORT = "port"
    SECTION_REMOTE_KEY_FILE = "keyfile"
    SECTION_REMOTE_TIMEOUT = "timeout"
    SECTION_REMOTE_PASSWORD = "******"
    SECTION_REMOTE_ASK_PASSWORD = "******"
    SECTION_REMOTE_SCHEMA = {
        SECTION_REMOTE_URL: str,
        Optional(SECTION_AWS_REGION): str,
        Optional(SECTION_AWS_PROFILE): str,
        Optional(SECTION_AWS_CREDENTIALPATH): str,
        Optional(SECTION_AWS_ENDPOINT_URL): str,
        Optional(SECTION_AWS_LIST_OBJECTS, default=False): BOOL_SCHEMA,
        Optional(SECTION_AWS_USE_SSL, default=True): BOOL_SCHEMA,
        Optional(SECTION_GCP_PROJECTNAME): str,
        Optional(SECTION_CACHE_TYPE): SECTION_CACHE_TYPE_SCHEMA,
        Optional(SECTION_CACHE_PROTECTED, default=False): BOOL_SCHEMA,
        Optional(SECTION_REMOTE_USER): str,
        Optional(SECTION_REMOTE_PORT): Use(int),
        Optional(SECTION_REMOTE_KEY_FILE): str,
        Optional(SECTION_REMOTE_TIMEOUT): Use(int),
        Optional(SECTION_REMOTE_PASSWORD): str,
        Optional(SECTION_REMOTE_ASK_PASSWORD): BOOL_SCHEMA,
        Optional(SECTION_AZURE_CONNECTION_STRING): str,
        Optional(SECTION_OSS_ACCESS_KEY_ID): str,
        Optional(SECTION_OSS_ACCESS_KEY_SECRET): str,
        Optional(SECTION_OSS_ENDPOINT): str,
        Optional(PRIVATE_CWD): str,
    }

    SECTION_STATE = "state"
    SECTION_STATE_ROW_LIMIT = "row_limit"
    SECTION_STATE_ROW_CLEANUP_QUOTA = "row_cleanup_quota"
    SECTION_STATE_SCHEMA = {
        Optional(SECTION_STATE_ROW_LIMIT): And(Use(int), is_whole),
        Optional(SECTION_STATE_ROW_CLEANUP_QUOTA): And(Use(int), is_percent),
    }

    SCHEMA = {
        Optional(SECTION_CORE, default={}): SECTION_CORE_SCHEMA,
        Optional(Regex(SECTION_REMOTE_REGEX)): SECTION_REMOTE_SCHEMA,
        Optional(SECTION_CACHE, default={}): SECTION_CACHE_SCHEMA,
        Optional(SECTION_STATE, default={}): SECTION_STATE_SCHEMA,
        # backward compatibility
        Optional(SECTION_AWS, default={}): SECTION_AWS_SCHEMA,
        Optional(SECTION_GCP, default={}): SECTION_GCP_SCHEMA,
        Optional(SECTION_LOCAL, default={}): SECTION_LOCAL_SCHEMA,
    }

    def __init__(self, dvc_dir=None, validate=True):
        self.system_config_file = os.path.join(self.get_system_config_dir(),
                                               self.CONFIG)
        self.global_config_file = os.path.join(self.get_global_config_dir(),
                                               self.CONFIG)

        if dvc_dir is not None:
            self.dvc_dir = os.path.abspath(os.path.realpath(dvc_dir))
            self.config_file = os.path.join(dvc_dir, self.CONFIG)
            self.config_local_file = os.path.join(dvc_dir, self.CONFIG_LOCAL)
        else:
            self.dvc_dir = None
            self.config_file = None
            self.config_local_file = None

        self._system_config = None
        self._global_config = None
        self._repo_config = None
        self._local_config = None

        self.config = None

        self.load(validate=validate)

    @staticmethod
    def get_global_config_dir():
        """Returns global config location. E.g. ~/.config/dvc/config.

        Returns:
            str: path to the global config directory.
        """
        from appdirs import user_config_dir

        return user_config_dir(appname=Config.APPNAME,
                               appauthor=Config.APPAUTHOR)

    @staticmethod
    def get_system_config_dir():
        """Returns system config location. E.g. /etc/dvc.conf.

        Returns:
            str: path to the system config directory.
        """
        from appdirs import site_config_dir

        return site_config_dir(appname=Config.APPNAME,
                               appauthor=Config.APPAUTHOR)

    @staticmethod
    def init(dvc_dir):
        """Initializes dvc config.

        Args:
            dvc_dir (str): path to .dvc directory.

        Returns:
            dvc.config.Config: config object.
        """
        config_file = os.path.join(dvc_dir, Config.CONFIG)
        open(config_file, "w+").close()
        return Config(dvc_dir)

    def _load(self):
        self._system_config = configobj.ConfigObj(self.system_config_file)
        self._global_config = configobj.ConfigObj(self.global_config_file)

        if self.config_file is not None:
            self._repo_config = configobj.ConfigObj(self.config_file)
        else:
            self._repo_config = configobj.ConfigObj()

        if self.config_local_file is not None:
            self._local_config = configobj.ConfigObj(self.config_local_file)
        else:
            self._local_config = configobj.ConfigObj()

        self.config = None

    def _load_config(self, path):
        config = configobj.ConfigObj(path)
        config = self._lower(config)
        self._resolve_paths(config, path)
        return config

    @staticmethod
    def _resolve_path(path, config_file):
        assert os.path.isabs(config_file)
        config_dir = os.path.dirname(config_file)
        return os.path.abspath(os.path.join(config_dir, path))

    def _resolve_cache_path(self, config, fname):
        cache = config.get(self.SECTION_CACHE)
        if cache is None:
            return

        cache_dir = cache.get(self.SECTION_CACHE_DIR)
        if cache_dir is None:
            return

        cache[self.PRIVATE_CWD] = os.path.dirname(fname)

    def _resolve_paths(self, config, fname):
        if fname is None:
            return

        self._resolve_cache_path(config, fname)
        for section in config.values():
            if self.SECTION_REMOTE_URL not in section.keys():
                continue

            section[self.PRIVATE_CWD] = os.path.dirname(fname)

    def load(self, validate=True):
        """Loads config from all the config files.

        Args:
            validate (bool): optional flag to tell dvc if it should validate
                the config or just load it as is. 'True' by default.


        Raises:
            dvc.config.ConfigError: thrown if config has invalid format.
        """
        self._load()
        try:
            self.config = self._load_config(self.system_config_file)
            user = self._load_config(self.global_config_file)
            config = self._load_config(self.config_file)
            local = self._load_config(self.config_local_file)

            # NOTE: schema doesn't support ConfigObj.Section validation, so we
            # need to convert our config to dict before passing it to
            for conf in [user, config, local]:
                self.config = self._merge(self.config, conf)

            if validate:
                self.config = Schema(self.SCHEMA).validate(self.config)

            # NOTE: now converting back to ConfigObj
            self.config = configobj.ConfigObj(self.config,
                                              write_empty_values=True)
            self.config.filename = self.config_file
            self._resolve_paths(self.config, self.config_file)
        except Exception as ex:
            raise ConfigError(ex)

    @staticmethod
    def _get_key(conf, name, add=False):
        for k in conf.keys():
            if k.lower() == name.lower():
                return k

        if add:
            conf[name] = {}
            return name

        return None

    def save(self, config=None):
        """Saves config to config files.

        Args:
            config (configobj.ConfigObj): optional config object to save.

        Raises:
            dvc.config.ConfigError: thrown if failed to write config file.
        """
        if config is not None:
            clist = [config]
        else:
            clist = [
                self._system_config,
                self._global_config,
                self._repo_config,
                self._local_config,
            ]

        for conf in clist:
            if conf.filename is None:
                continue

            try:
                logger.debug("Writing '{}'.".format(conf.filename))
                dname = os.path.dirname(os.path.abspath(conf.filename))
                try:
                    os.makedirs(dname)
                except OSError as exc:
                    if exc.errno != errno.EEXIST:
                        raise
                conf.write()
            except Exception as exc:
                msg = "failed to write config '{}'".format(conf.filename)
                raise ConfigError(msg, exc)

    def get_remote_settings(self, name):
        import posixpath
        """
        Args:
            name (str): The name of the remote that we want to retrieve

        Returns:
            dict: The content beneath the given remote name.

        Example:
            >>> config = {'remote "server"': {'url': 'ssh://localhost/'}}
            >>> get_remote_settings("server")
            {'url': 'ssh://localhost/'}
        """
        settings = self.config.get(self.SECTION_REMOTE_FMT.format(
            name.lower()))

        if settings is None:
            raise ConfigError(
                "unable to find remote section '{}'".format(name))

        parsed = urlparse(settings["url"])

        # Support for cross referenced remotes.
        # This will merge the settings, giving priority to the outer reference.
        # For example, having:
        #
        #       dvc remote add server ssh://localhost
        #       dvc remote modify server user root
        #       dvc remote modify server ask_password true
        #
        #       dvc remote add images remote://server/tmp/pictures
        #       dvc remote modify images user alice
        #       dvc remote modify images ask_password false
        #       dvc remote modify images password asdf1234
        #
        # Results on a config dictionary like:
        #
        #       {
        #           "url": "ssh://localhost/tmp/pictures",
        #           "user": "******",
        #           "password": "******",
        #           "ask_password": False,
        #       }
        #
        if parsed.scheme == "remote":
            reference = self.get_remote_settings(parsed.netloc)
            url = posixpath.join(reference["url"], parsed.path.lstrip("/"))
            merged = reference.copy()
            merged.update(settings)
            merged["url"] = url
            return merged

        return settings

    @staticmethod
    def unset(config, section, opt=None):
        """Unsets specified option and/or section in the config.

        Args:
            config (configobj.ConfigObj): config to work on.
            section (str): section name.
            opt (str): optional option name.
        """
        if section not in config.keys():
            raise ConfigError("section '{}' doesn't exist".format(section))

        if opt is None:
            del config[section]
            return

        if opt not in config[section].keys():
            raise ConfigError("option '{}.{}' doesn't exist".format(
                section, opt))
        del config[section][opt]

        if not config[section]:
            del config[section]

    @staticmethod
    def set(config, section, opt, value):
        """Sets specified option in the config.

        Args:
            config (configobj.ConfigObj): config to work on.
            section (str): section name.
            opt (str): option name.
            value: value to set option to.
        """
        if section not in config.keys():
            config[section] = {}

        config[section][opt] = value

    @staticmethod
    def show(config, section, opt):
        """Prints option value from the config.

        Args:
            config (configobj.ConfigObj): config to work on.
            section (str): section name.
            opt (str): option name.
        """
        if section not in config.keys():
            raise ConfigError("section '{}' doesn't exist".format(section))

        if opt not in config[section].keys():
            raise ConfigError("option '{}.{}' doesn't exist".format(
                section, opt))

        logger.info(config[section][opt])

    @staticmethod
    def _merge(first, second):
        res = {}
        sections = list(first.keys()) + list(second.keys())
        for section in sections:
            first_copy = first.get(section, {}).copy()
            second_copy = second.get(section, {}).copy()
            first_copy.update(second_copy)
            res[section] = first_copy
        return res

    @staticmethod
    def _lower(config):
        new_config = {}
        for s_key, s_value in config.items():
            new_s = {}
            for key, value in s_value.items():
                new_s[key.lower()] = str(value)
            new_config[s_key.lower()] = new_s
        return new_config
Ejemplo n.º 11
0
class Feature(object):
    """
  An object composed of a set of named attributes with values.

  A feature is constructed from a ``dict`` of name value pairs and an optional identifier.

  >>> f = Feature({ 'name': 'anvil', 'price': 100.0 }, 'widgets.1')
  >>> str(f.get('name'))
  'anvil'

  A feature can also be constructed optionally with a :class:`Schema`.

  >>> from schema import Schema
  >>> s = Schema('widgets', [('name', str), ('price', float)])
  >>> f = Feature({'name': 'anvil'}, '1', s)
  >>> f
  widgets.1 {name: anvil, price: None}

  When *schema* is specified feature values can be passed a ``list``.

  >>> s = Schema('widgets', [('name', str), ('price', float)])
  >>> f = Feature(['anvil', 100.0], '1', s)
  >>> f
  widgets.1 {name: anvil, price: 100.0}
  """
    def __init__(self, atts=None, id=None, schema=None, f=None):

        from schema import Schema
        if atts:
            # attributes specified directly

            # if list specified assume values in order of schema
            if isinstance(atts, list):
                if not schema:
                    raise Exception(
                        'Values may be specified as list only when schema is supplied'
                    )

                natts = {}
                for i in range(len(atts)):
                    natts[schema.fields[i].name] = atts[i]
                atts = natts

            # generate feature type if necessary
            self.schema = schema
            if not self.schema:
                self.schema = Schema('feature',
                                     [(att, type(val))
                                      for att, val in atts.iteritems()])

            # generate feature
            b = SimpleFeatureBuilder(self.schema._type)
            for att, val in atts.iteritems():
                b.set(att, val)

            self._feature = b.buildFeature(str(id) if id else None)

        elif f:
            # feature specififed directly
            self._feature = f
            self.schema = schema if schema else Schema(ft=f.type)

        else:
            raise Exception('No attributes specified for feature')

    def getid(self):
        return self._feature.identifier.toString()

    id = property(getid, None)
    """
  Identifier of the feature as a ``str``

  >>> f = Feature({'name': 'anvil'}, 'widgets.1')
  >>> f.id
  'widgets.1'
  """

    def getgeom(self):
        return core.map(self._feature.defaultGeometry)

    def setgeom(self, g):
        self._feature.defaultGeometry = g

    geom = property(getgeom, setgeom)
    """
  The geometry of the feature.

  >>> import geom
  >>> f = Feature({'geom': geom.Point(1,1)})
  >>> f.geom
  POINT (1 1)
  >>> f.geom = geom.Point(2,2)
  >>> f.geom
  POINT (2 2)
  """

    def getbounds(self):
        if self.geom:
            return geom.Bounds(prj=self.schema.proj,
                               env=self.geom.getEnvelopeInternal())

    bounds = property(getbounds)
    """
  The :class:`Bounds <geoscript.geom.bounds.Bounds>` of the feature geometry. 
  Will return ``None`` if the feature does not contain any geometric attributes.
  """

    def get(self, name):
        """
    Returns a feature attribute value by name. ``KeyError`` is thrown if the attribute does not exist.

    *name* is the name of the attribute whose value to return.

    >>> f = Feature({'name': 'anvil', 'price': 100.0})
    >>> str(f.get('name'))
    'anvil'
    """
        self.schema.get(name)
        return self._feature.getAttribute(name)

    def set(self, name, value):
        """
    Sets a feature attribute value by name. ``KeyError`` is thrown is the attribute does not exist.

    *name* is the name of the attribute whose value to set. 

    *value* is the new attribute value.

    >>> f = Feature({'name': 'anvil', 'price': 100.0})
    >>> str(f.get('name'))
    'anvil'
    >>> f.set('name', 'mallet')
    >>> str(f.get('name'))
    'mallet'
    """

        self.schema.get(name)
        self._feature.setAttribute(name, value)

    def getattributes(self):
        atts = {}
        for fld in self.schema.fields:
            atts[fld.name] = core.map(self._feature.getAttribute(fld.name))

        return atts

    attributes = property(getattributes, None)
    """
  A ``dict`` of name, value for the attributes of the feature.

  >>> f = Feature({'name': 'anvil', 'price': 100.0})
  >>> atts = f.attributes
  >>> str(atts['name'])
  'anvil'
  >>> atts['price']
  100.0
  """

    def __getitem__(self, key):
        return self.get(key)

    def __setitem__(self, key, value):
        self.set(key, value)

    def __iter__(self):
        return self.schema.__iter__()

    def iterkeys(self):
        return self.__iter__()

    def iteritems(self):
        return self.attributes.iteritems()

    def keys(self):
        return [f.name for f in self.schema.fields]

    def values(self):
        return [core.map(val) for val in self._feature.getAttributes()]

    def __repr__(self):
        atts = [
            '%s: %s' % (fld.name, self.get(fld.name))
            for fld in self.schema.fields
        ]

        id = self.id if self.id.startswith(
            self.schema.name) else '%s.%s' % (self.schema.name, self.id)
        return '%s {%s}' % (id, string.join(atts, ', '))

    def __eq__(self, other):
        return other and self._feature == other._feature
Ejemplo n.º 12
0
class Page:
    "Banana banana"
    meta_schema = {
        Optional('title'): And(str, len),
        Optional('symbols'): Schema([And(str, len)]),
        Optional('private-symbols'): Schema([And(str, len)]),
        Optional('short-description'): And(str, len),
        Optional('description'): And(str, len),
        Optional('render-subpages'): bool,
        Optional('auto-sort'): bool,
        Optional('full-width'): bool,
        Optional('see-also'): And(str, len),
        Optional('extra'): Schema({str: object}),
        Optional('thumbnail'): And(str, len)
    }

    # pylint: disable=too-many-arguments
    def __init__(self,
                 source_file,
                 ast,
                 output_path,
                 project_name,
                 meta=None,
                 raw_contents=None):
        "Banana banana"
        assert source_file
        basename = os.path.basename(source_file)
        name = os.path.splitext(basename)[0]
        ref = os.path.join(output_path,
                           re.sub(r'\W+', '-',
                                  os.path.splitext(basename)[0]))
        pagename = '%s.html' % ref

        self.ast = ast
        self.extension_name = None
        self.source_file = source_file
        self.raw_contents = raw_contents
        self.comment = None
        self.generated = False
        self.pre_sorted = False
        self.output_attrs = None
        self.subpages = OrderedSet()
        self.symbols = []
        self.private_symbols = []
        self.typed_symbols = OrderedDict()
        self.by_parent_symbols = OrderedDict()
        self.is_stale = True
        self.formatted_contents = None
        self.detailed_description = None
        self.build_path = None
        self.project_name = project_name
        self.cached_paths = OrderedSet()

        meta = meta or {}
        self.listed_symbols = []
        self.symbol_names = []
        self.short_description = None
        self.render_subpages = True
        self.title = ''
        self.meta = Schema(Page.meta_schema).validate({})
        self.__update_meta(meta)
        self.__discover_title(meta)
        self.link = Link(pagename, self.title or name, ref)

    def __update_meta(self, meta):
        for key, value in meta.items():
            try:
                self.meta.update(
                    Schema(Page.meta_schema).validate(
                        {key.replace('_', '-').lower(): value}))
            except SchemaError as _:
                warn(
                    'invalid-page-metadata',
                    '%s: Invalid metadata: \n%s, discarding metadata' %
                    (self.source_file, str(_)))

        if not self.meta.get('extra'):
            self.meta['extra'] = defaultdict()

        self.title = meta.get('title', self.title)
        self.thumbnail = meta.get('thumbnail')
        self.listed_symbols = OrderedSet(
            meta.get('symbols') or self.symbol_names)
        self.private_symbols = OrderedSet(
            meta.get('private-symbols') or self.private_symbols)
        self.symbol_names = OrderedSet(
            meta.get('symbols') or self.symbol_names)
        self.short_description = meta.get('short-description',
                                          self.short_description)
        self.render_subpages = meta.get('render-subpages',
                                        self.render_subpages)

    def __getstate__(self):
        return {
            'ast': None,
            'build_path': None,
            'title': self.title,
            'raw_contents': self.raw_contents,
            'short_description': self.short_description,
            'extension_name': self.extension_name,
            'link': self.link,
            'meta': self.meta,
            'source_file': self.source_file,
            'comment': self.comment,
            'generated': self.generated,
            'is_stale': False,
            'formatted_contents': None,
            'detailed_description': None,
            'output_attrs': None,
            'symbols': [],
            'private_symbols': {},
            'typed_symbols': {},
            'by_parent_symbols': {},
            'subpages': self.subpages,
            'listed_symbols': self.listed_symbols,
            'symbol_names': self.symbol_names,
            'project_name': self.project_name,
            'pre_sorted': self.pre_sorted,
            'cached_paths': self.cached_paths,
            'render_subpages': self.render_subpages
        }

    def __repr__(self):
        return "<Page %s>" % self.source_file

    @staticmethod
    def __get_empty_typed_symbols():
        typed_symbols_list = namedtuple('TypedSymbolsList',
                                        ['name', 'symbols'])
        empty_typed_symbols = {}

        for subclass in all_subclasses(Symbol):
            empty_typed_symbols[subclass] = typed_symbols_list(
                subclass.get_plural_name(), [])

        return empty_typed_symbols

    def set_comment(self, comment):
        """
        Sets @comment as main comment for @self.
        """
        if comment:
            self.__update_meta(comment.meta)

        self.comment = comment

    def resolve_symbols(self, tree, database, link_resolver):
        """
        When this method is called, the page's symbol names are queried
        from `database`, and added to lists of actual symbols, sorted
        by symbol class.
        """
        self.typed_symbols = self.__get_empty_typed_symbols()
        all_syms = OrderedSet()
        for sym_name in self.symbol_names:
            sym = database.get_symbol(sym_name)
            self.__query_extra_symbols(sym, all_syms, tree, link_resolver,
                                       database)

        if tree.project.is_toplevel:
            page_path = self.link.ref
        else:
            page_path = self.project_name + '/' + self.link.ref

        if self.meta.get("auto-sort", True):
            all_syms = sorted(all_syms, key=lambda x: x.unique_name)
        for sym in all_syms:
            sym.update_children_comments()
            self.__resolve_symbol(sym, link_resolver, page_path)
            self.symbol_names.add(sym.unique_name)

        # Always put symbols with no parent at the end
        no_parent_syms = self.by_parent_symbols.pop(None, None)
        if no_parent_syms:
            self.by_parent_symbols[None] = no_parent_syms

        for sym_type in [
                ClassSymbol, AliasSymbol, InterfaceSymbol, StructSymbol
        ]:
            syms = self.typed_symbols[sym_type].symbols

            if not syms:
                continue

            if self.title is None:
                self.title = syms[0].display_name
            if self.comment is None:
                self.comment = Comment(name=self.source_file)
                self.comment.short_description = syms[
                    0].comment.short_description
                self.comment.title = syms[0].comment.title
            break

    # pylint: disable=no-self-use
    def __fetch_comment(self, sym, database):
        old_comment = sym.comment
        new_comment = database.get_comment(sym.unique_name)
        sym.comment = Comment(sym.unique_name)

        if new_comment:
            sym.comment = new_comment
        elif old_comment:
            if old_comment.filename not in ChangeTracker.all_stale_files:
                sym.comment = old_comment

    def __format_page_comment(self, formatter, link_resolver):
        if not self.comment:
            return

        if self.comment.short_description:
            self.short_description = formatter.format_comment(
                self.comment.short_description, link_resolver).strip()
            if self.short_description.startswith('<p>'):
                self.short_description = self.short_description[3:-4]
        if self.comment.title:
            self.title = formatter.format_comment(self.comment.title,
                                                  link_resolver).strip()
            if self.title.startswith('<p>'):
                self.title = self.title[3:-4]

        if self.title:
            self.formatted_contents += '<h1 id="%s-page">%s</h1>' % (
                id_from_text(self.title), self.title)

        self.formatted_contents += formatter.format_comment(
            self.comment, link_resolver)

    def format(self, formatter, link_resolver, output):
        """
        Banana banana
        """

        if not self.title and self.source_file:
            title = os.path.splitext(self.source_file)[0]
            self.title = os.path.basename(title).replace('-', ' ')

        self.formatted_contents = u''

        self.build_path = os.path.join(formatter.get_output_folder(self),
                                       self.link.ref)

        if self.ast:
            out, diags = cmark.ast_to_html(self.ast, link_resolver)
            for diag in diags:
                warn(diag.code,
                     message=diag.message,
                     filename=self.source_file)

            self.formatted_contents += out

        if not self.formatted_contents:
            self.__format_page_comment(formatter, link_resolver)

        self.output_attrs = defaultdict(lambda: defaultdict(dict))
        formatter.prepare_page_attributes(self)
        self.__format_symbols(formatter, link_resolver)
        self.detailed_description =\
            formatter.format_page(self)[0]

        if output:
            formatter.cache_page(self)

    # pylint: disable=no-self-use
    def get_title(self):
        """
        Banana banana
        """
        return self.title or 'unnamed'

    def __discover_title(self, meta):
        if meta is not None and 'title' in meta:
            self.title = meta['title']
        elif self.ast:
            self.title = cmark.title_from_ast(self.ast)

    def __format_symbols(self, formatter, link_resolver):
        for symbol in self.symbols:
            if symbol is None:
                continue
            debug(
                'Formatting symbol %s in page %s' %
                (symbol.unique_name, self.source_file), 'formatting')
            symbol.detailed_description = formatter.format_symbol(
                symbol, link_resolver)

    def __query_extra_symbols(self, sym, all_syms, tree, link_resolver,
                              database):
        if sym:
            self.__fetch_comment(sym, database)
            new_symbols = sum(tree.resolving_symbol_signal(self, sym), [])
            all_syms.add(sym)

            for symbol in new_symbols:
                self.__query_extra_symbols(symbol, all_syms, tree,
                                           link_resolver, database)

    def __resolve_symbol(self, symbol, link_resolver, page_path):
        symbol.resolve_links(link_resolver)

        symbol.link.ref = "%s#%s" % (page_path, symbol.unique_name)

        for link in symbol.get_extra_links():
            link.ref = "%s#%s" % (page_path, link.id_)

        tsl = self.typed_symbols.get(type(symbol))
        if tsl:
            tsl.symbols.append(symbol)

            by_parent_symbols = self.by_parent_symbols.get(symbol.parent_name)
            if not by_parent_symbols:
                by_parent_symbols = self.__get_empty_typed_symbols()
                parent_name = symbol.parent_name
                if parent_name is None:
                    parent_name = 'Others symbols'
                self.by_parent_symbols[symbol.parent_name] = by_parent_symbols
            by_parent_symbols.get(type(symbol)).symbols.append(symbol)

        self.symbols.append(symbol)

        debug(
            'Resolved symbol %s to page %s' %
            (symbol.display_name, self.link.ref), 'resolution')