text:
from __future__ import unicode_literals
"""
test_layeredconfig
----------------------------------

Tests for `layeredconfig` module.
"""

import os
import logging
import sys
import codecs
from six import text_type as str
from datetime import date, datetime
import argparse
import json
from operator import itemgetter
from copy import deepcopy
try:
    from collections import OrderedDict
except ImportError:  # pragma: no cover
    # if on python 2.6
    from ordereddict import OrderedDict

if sys.version_info < (2, 7, 0):  # pragma: no cover
    import unittest2 as unittest
else:
    import unittest
import requests
# The system under test
from layeredconfig import (LayeredConfig, Defaults, INIFile, JSONFile,
                           YAMLFile, PListFile, PyFile, Environment,
                           Commandline, EtcdStore, UNIT_SEP)

class LayeredConfigHelperTests(object):

    # Testcases for less-capable sources may override this
    supported_types = (str, int, bool, list, date, datetime)
    supports_nesting = True

    def _test_config_singlesection(self, cfg):
        self.assertIs(type(cfg.home), str)
        self.assertEqual(cfg.home, 'mydata')

        int_type = int if int in self.supported_types else str
        self.assertIs(type(cfg.processes), int_type)
        self.assertEqual(cfg.processes, int_type(4))

        if bool in self.supported_types:
            self.assertEqual(cfg.force, True)
        else:
            self.assertEqual(cfg.force, "True")

        if list in self.supported_types:
            list_type = list
            list_want = ['foo', 'bar']
            self.assertIs(type(cfg.extra[0]), str)
        else:
            list_type = str
            list_want = "foo, bar"  # recommended list serialization
        self.assertIs(type(cfg.extra), list_type)
        self.assertEqual(cfg.extra, list_want)

        if date in self.supported_types:
            date_type = date
            date_want = date(2014, 10, 15)
        else:
            date_type = str
            date_want = "2014-10-15" # recommended date serialization
        self.assertIs(type(cfg.expires), date_type)
        self.assertEqual(cfg.expires, date_want)

        if datetime in self.supported_types:
            datetime_type = datetime
            datetime_want = datetime(2014, 10, 15, 14, 32, 7)
        else:
            datetime_type = str
            datetime_want = "2014-10-15 14:32:07"
        self.assertIs(type(cfg.lastrun), datetime_type)
        self.assertEqual(cfg.lastrun, datetime_want)

    def _test_config_subsections(self, cfg):
        self.assertEqual(cfg.home, 'mydata')
        with self.assertRaises(AttributeError):
            cfg.mymodule.home

        int_type = int if int in self.supported_types else str
        self.assertEqual(cfg.processes, int_type(4))
        with self.assertRaises(AttributeError):
            cfg.mymodule.processes

        if bool in self.supported_types:
            self.assertEqual(cfg.mymodule.force, False)
        else:
            self.assertEqual(cfg.mymodule.force, "False")

        if list in self.supported_types:
            list_type = list
            list_want = ['foo', 'bar']
            list_want_sub = ['foo', 'baz']
        else:
            list_type = str
            list_want = "foo, bar"
            list_want_sub = "foo, baz"
        self.assertEqual(cfg.extra, list_want)
        self.assertEqual(cfg.mymodule.extra, list_want_sub)

        if self.supports_nesting:
            self.assertEqual(cfg.mymodule.arbitrary.nesting.depth, 'works')

        with self.assertRaises(AttributeError):
            cfg.expires

        if date in self.supported_types:
            date_type = date
            date_want = date(2014, 10, 15)
        else:
            date_type = str
            date_want = "2014-10-15" # recommended date serialization
        self.assertEqual(cfg.mymodule.expires, date_want)

    def _test_layered_configs(self, cfg):
        self.assertEqual(cfg.home, 'otherdata')

        bool_type = bool if bool in self.supported_types else str
        self.assertEqual(cfg.mymodule.force, bool_type(False))

    def _test_layered_subsection_configs(self, cfg):
        if date in self.supported_types:
            date_type = date
            date_want = date(2014, 10, 15)
        else:
            date_type = str
            date_want = "2014-10-15" # recommended date serialization
        self.assertIs(type(cfg.mymodule.expires), date_type)
        self.assertEqual(cfg.mymodule.expires, date_want)

class ConfigSourceHelperTests(LayeredConfigHelperTests):

    # First, a number of straightforward tests for any
    # ConfigSource-derived object. Concrete test classes should set up
    # self.simple and self.complex instances to match these.
    def test_keys(self):
        self.assertEqual(set(self.simple.keys()),
                         set(('home', 'processes', 'force',
                              'extra', 'expires', 'lastrun')))
        self.assertEqual(set(self.complex.keys()),
                         set(('home', 'processes', 'force', 'extra')))

    def test_subsection_keys(self):
        self.assertEqual(set(self.complex.subsection('mymodule').keys()),
                         set(('force', 'extra', 'expires')))

    def test_subsections(self):
        self.assertEqual(set(self.simple.subsections()),
                         set())
        self.assertEqual(set(self.complex.subsections()),
                         set(('mymodule', 'extramodule')))

    def test_subsection_nested(self):
        subsec = self.complex.subsection('mymodule')
        self.assertEqual(set(subsec.subsections()),
                         set(('arbitrary',)))

    def test_has(self):
        for key in self.simple.keys():
            self.assertTrue(self.simple.has(key))

    def test_typed(self):
        for key in self.simple.keys():
            self.assertTrue(self.simple.typed(key))

    def test_get(self):
        # FIXME: This test should be able to look at supported_types
        # like test_singlesection and test_subsections do, so derived
        # testcase classes don't need to override it.
        self.assertEqual(self.simple.get("home"), "mydata")
        self.assertEqual(self.simple.get("processes"), 4)
        self.assertEqual(self.simple.get("force"), True)
        self.assertEqual(self.simple.get("extra"), ['foo', 'bar'])
        self.assertEqual(self.simple.get("expires"), date(2014, 10, 15))
        self.assertEqual(self.simple.get("lastrun"),
                         datetime(2014, 10, 15, 14, 32, 7))

    # Then, two validation helpers for checking a complete
    # LayeredConfig object, where validation can be performed
    # different depending on the abilities of the source (eg. typing)
    def test_config_singlesection(self):
        # each subclass is responsible for creating a self.simple
        # object of the type being tested
        cfg = LayeredConfig(self.simple)
        self._test_config_singlesection(cfg)

    def test_config_subsections(self):
        cfg = LayeredConfig(self.complex)
        self._test_config_subsections(cfg)

    def test_layered_subsections(self):
        # this testcases excercies a bug (or rather a deficency in the
        # file-based sources) -- if the highest-priority source has
        # subsections, and a lower-priority file-based source lacks
        # those subsections, bad things would happen.
        #
        # see https://github.com/staffanm/layeredconfig/issues/2
        cfg = LayeredConfig(self.complex, self.extra)
        self._test_layered_configs(cfg)

    def test_overwriting_with_missing_subsections(self):
        # this testcase tests the inverse of test_layered_subsections
        cfg = LayeredConfig(self.complex, self.extra_layered)
        self._test_layered_subsection_configs(cfg)

    DUMP_DEFAULTS = {'processes': int,
                     'force': bool,
                     'extra': list,
                     'mymodule': {
                         'force': bool,
                         'extra': list,
                         'expires': date,
                     },
                     'extramodule': {
                         'unique': bool
                     }
    }
    DUMP_WANT = {'home': 'mydata',
                 'processes': 4,
                 'force': True,
                 'extra': ['foo', 'bar'],
                 'mymodule': {
                     'force': False,
                     'extra': ['foo', 'baz'],
                     'expires': date(2014, 10, 15),
                     'arbitrary': {
                        'nesting': {
                            'depth': 'works'
                        }
                    }
                 },
                 'extramodule': {
                     'unique': True
                 }
    }
    def test_dump(self):
        want = deepcopy(self.DUMP_WANT)
        if not self.supports_nesting:
            # INIFile does not support nested sections
            del want['mymodule']['arbitrary']
        cfg = LayeredConfig(Defaults(self.DUMP_DEFAULTS), self.complex)
        got = LayeredConfig.dump(cfg)
        self.maxDiff = None
        self.assertEquals(want, got)

    def test_dump_layered(self):
        want = deepcopy(self.DUMP_WANT)
        if not self.supports_nesting:
            # INIFile does not support nested sections
            del want['mymodule']['arbitrary']
        want['home'] = 'otherdata'
        cfg = LayeredConfig(Defaults(self.DUMP_DEFAULTS), self.complex, self.extra)
        got = LayeredConfig.dump(cfg)
        self.maxDiff = None
        self.assertEquals(want, got)

# common helper
class TestINIFileHelper(object):

    def setUp(self):
        super(TestINIFileHelper, self).setUp()
        with open("simple.ini", "w") as fp:
            fp.write("""
[__root__]
home = mydata
processes = 4
force = True
extra = foo, bar
expires = 2014-10-15
lastrun = 2014-10-15 14:32:07
""")

        with open("complex.ini", "w") as fp:
            fp.write("""
[__root__]
home = mydata
processes = 4
force = True
extra = foo, bar

[mymodule]
force = False
extra = foo, baz
expires = 2014-10-15

[mymodule.arbitrary.nesting]
depth = works

[extramodule]
unique = True
""")

        with open("extra.ini", "w") as fp:
            fp.write("""
[__root__]
home = otherdata
""")

        with open("extra-layered.ini", "w") as fp:
            fp.write("""
[mymodule]
expires = 2014-10-15
""")

    def tearDown(self):
        super(TestINIFileHelper, self).tearDown()
        os.unlink("simple.ini")
        os.unlink("complex.ini")
        os.unlink("extra.ini")
        os.unlink("extra-layered.ini")

class TestDefaults(unittest.TestCase, ConfigSourceHelperTests):

    simple = Defaults({'home': 'mydata',
                       'processes': 4,
                       'force': True,
                       'extra': ['foo', 'bar'],
                       'expires': date(2014, 10, 15),
                       'lastrun': datetime(2014, 10, 15, 14, 32, 7)})

    complex = Defaults({'home': 'mydata',
                        'processes': 4,
                        'force': True,
                        'extra': ['foo', 'bar'],
                        'mymodule': {'force': False,
                                     'extra': ['foo', 'baz'],
                                     'expires': date(2014, 10, 15),
                                     'arbitrary': {
                                         'nesting': {
                                             'depth': 'works'
                                         }
                                     }
                                 },
                        'extramodule': {'unique': True}})

    extra = Defaults({'home': 'otherdata'})

    extra_layered = Defaults({'mymodule': {'force': True}})

class TestINIFile(TestINIFileHelper, unittest.TestCase,
                  ConfigSourceHelperTests):

    supported_types = (str,)
    supports_nesting = True

    def setUp(self):
        super(TestINIFile, self).setUp()
        self.simple = INIFile("simple.ini")
        self.complex = INIFile("complex.ini")
        self.extra = INIFile("extra.ini")
        self.extra_layered = INIFile("extra-layered.ini")

    # Overrides of TestHelper.test_get, .test_typed and
    # .test_subsection_nested due to limitations of INIFile
    # INIFile carries no typing information
    def test_get(self):
        self.assertEqual(self.simple.get("home"), "mydata")
        self.assertEqual(self.simple.get("processes"), "4")
        self.assertEqual(self.simple.get("force"), "True")
        self.assertEqual(self.simple.get("extra"), "foo, bar")
        self.assertEqual(self.simple.get("expires"), "2014-10-15")
        self.assertEqual(self.simple.get("lastrun"), "2014-10-15 14:32:07")

    def test_typed(self):
        for key in self.simple.keys():
            self.assertFalse(self.simple.typed(key))

    def test_inifile_default_as_root(self):
        # using a rootsection named DEFAULT triggers different
        # cascading-like behaviour in configparser.

        # load a modified version of complex.ini
        with open("complex.ini") as fp:
            ini = fp.read()

        with open("complex-otherroot.ini", "w") as fp:
            fp.write(ini.replace("[__root__]", "[DEFAULT]"))
        cfg = LayeredConfig(INIFile("complex-otherroot.ini",
                                    rootsection="DEFAULT"))

        # this is a modified/simplified version of ._test_subsections
        self.assertEqual(cfg.home, 'mydata')
        self.assertEqual(cfg.processes, '4')
        self.assertEqual(cfg.force, 'True')
        self.assertEqual(cfg.mymodule.force, 'False')
        self.assertEqual(cfg.extra, "foo, bar")
        self.assertEqual(cfg.mymodule.extra, "foo, baz")
        with self.assertRaises(AttributeError):
            cfg.expires
        self.assertEqual(cfg.mymodule.expires, "2014-10-15")

        # this is really unwanted cascading behaviour
        self.assertEqual(cfg.mymodule.home, 'mydata')
        self.assertEqual(cfg.mymodule.processes, '4')

        os.unlink("complex-otherroot.ini")

    def test_inifile_nonexistent(self):
        logging.getLogger().setLevel(logging.CRITICAL)
        cfg = LayeredConfig(INIFile("nonexistent.ini"))
        self.assertEqual([], list(cfg))

        # make sure a nonexistent inifile doesn't interfere with the
        # rest of the LayeredConfig object
        defobj = Defaults({'datadir': 'something'})
        iniobj = INIFile("nonexistent.ini")
        cfg = LayeredConfig(defobj, iniobj)
        self.assertEqual("something", cfg.datadir)

        # and make sure it's settable (should set up the INIFile
        # object and affect it, and leave the defaults dict untouched
        # as it's the lowest priority)
        cfg.datadir = "else"
        self.assertEqual("else", cfg.datadir)
        self.assertEqual("else", iniobj.get("datadir"))
        self.assertEqual("something", defobj.get("datadir"))

        # same as above, but with a "empty" INIFile object
        iniobj = INIFile()
        cfg = LayeredConfig(defobj, iniobj)
        self.assertEqual("something", cfg.datadir)
        cfg.datadir = "else"
        self.assertEqual("else", cfg.datadir)

    def test_write(self):
        cfg = LayeredConfig(INIFile("complex.ini"))
        cfg.mymodule.expires = date(2014, 10, 24)
        cfg.mymodule.extra = ['foo', 'baz', 'quux']
        # calling write for any submodule will force a write of the
        # entire config file
        LayeredConfig.write(cfg.mymodule)
        want = """[__root__]
home = mydata
processes = 4
force = True
extra = foo, bar

[mymodule]
force = False
extra = foo, baz, quux
expires = 2014-10-24

[mymodule.arbitrary.nesting]
depth = works

[extramodule]
unique = True

"""
        with open("complex.ini") as fp:
            got = fp.read().replace("\r\n", "\n")
        self.assertEqual(want, got)

class TestJSONFile(unittest.TestCase, ConfigSourceHelperTests):

    supported_types = (str, int, bool, list)

    def setUp(self):
        with open("simple.json", "w") as fp:
            fp.write("""
{"home": "mydata",
 "processes": 4,
 "force": true,
 "extra": ["foo", "bar"],
 "expires": "2014-10-15",
 "lastrun": "2014-10-15 14:32:07"}
""")

        with open("complex.json", "w") as fp:
            fp.write("""
{"home": "mydata",
 "processes": 4,
 "force": true,
 "extra": ["foo", "bar"],
 "mymodule": {"force": false,
              "extra": ["foo", "baz"],
              "expires": "2014-10-15",
              "arbitrary": {
                  "nesting": {
                      "depth": "works"
                  }
              }
          },
 "extramodule": {"unique": true}
}
""")
        with open("extra.json", "w") as fp:
            fp.write('{"home": "otherdata"}')

        with open("extra-layered.json", "w") as fp:
            fp.write('{"mymodule": {"force": true}}')

        self.simple = JSONFile("simple.json")
        self.complex = JSONFile("complex.json")
        self.extra = JSONFile("extra.json")
        self.extra_layered = JSONFile("extra-layered.json")

    def tearDown(self):
        os.unlink("simple.json")
        os.unlink("complex.json")
        os.unlink("extra.json")
        os.unlink("extra-layered.json")

    def test_get(self):
        self.assertEqual(self.simple.get("home"), "mydata")
        self.assertEqual(self.simple.get("processes"), 4)
        self.assertEqual(self.simple.get("force"), True)
        self.assertEqual(self.simple.get("extra"), ['foo', 'bar'])
        self.assertEqual(self.simple.get("expires"), "2014-10-15")
        self.assertEqual(self.simple.get("lastrun"), "2014-10-15 14:32:07")

    def test_typed(self):
        for key in self.simple.keys():
            # JSON can type ints, bools and lists
            if key in ("processes", "force", "extra"):
                self.assertTrue(self.simple.typed(key))
            else:
                self.assertFalse(self.simple.typed(key))

    def test_write(self):
        self.maxDiff = None
        cfg = LayeredConfig(self.complex)
        cfg.mymodule.expires = date(2014, 10, 24)
        cfg.mymodule.extra.append("quux")
        # calling write for any submodule will force a write of the
        # entire config file
        LayeredConfig.write(cfg.mymodule)
        want = """{
    "extra": [
        "foo",
        "bar"
    ],
    "extramodule": {
        "unique": true
    },
    "force": true,
    "home": "mydata",
    "mymodule": {
        "arbitrary": {
            "nesting": {
                "depth": "works"
            }
        },
        "expires": "2014-10-24",
        "extra": [
            "foo",
            "baz",
            "quux"
        ],
        "force": false
    },
    "processes": 4
}"""
        with open("complex.json") as fp:
            got = fp.read().replace("\r\n", "\n")
        self.assertEqual(want, got)

class TestYAMLFile(unittest.TestCase,
                   ConfigSourceHelperTests):
    def setUp(self):
        with open("simple.yaml", "w") as fp:
            fp.write("""
home: mydata
processes: 4
force: true
extra:
- foo
- bar
expires: 2014-10-15
lastrun: 2014-10-15 14:32:07
""")
        with open("complex.yaml", "w") as fp:
            fp.write("""
home: mydata
processes: 4
force: true
extra:
- foo
- bar
mymodule:
    force: false
    extra:
    - foo
    - baz
    expires: 2014-10-15
    arbitrary:
        nesting:
            depth: works
extramodule:
    unique: true
""")
        with open("extra.yaml", "w") as fp:
            fp.write("""
home: otherdata
""")

        with open("extra-layered.yaml", "w") as fp:
            fp.write("""
mymodule:
    force: true
""")

        self.simple = YAMLFile("simple.yaml")
        self.complex = YAMLFile("complex.yaml")
        self.extra = YAMLFile("extra.yaml")
        self.extra_layered = YAMLFile("extra-layered.yaml")

    def tearDown(self):
        os.unlink("simple.yaml")
        os.unlink("complex.yaml")
        os.unlink("extra.yaml")
        os.unlink("extra-layered.yaml")

    # Also, strings are unicode when they need to be,
    # str otherwise.
    def test_i18n(self):
        with codecs.open("i18n.yaml", "w", encoding="utf-8") as fp:
            fp.write("shrimpsandwich: Räksmörgås")
        cfg = LayeredConfig(YAMLFile("i18n.yaml"))
        self.assertEqual("Räksmörgås", cfg.shrimpsandwich)
        os.unlink("i18n.yaml")

    def test_write(self):
        cfg = LayeredConfig(self.complex)
        cfg.mymodule.expires = date(2014, 10, 24)
        cfg.mymodule.extra.append('quux')
        # calling write for any submodule will force a write of the
        # entire config file
        LayeredConfig.write(cfg.mymodule)
        # note that pyyaml sorts keys alphabetically and has specific
        # ideas on how to format the result (controllable through
        # mostly-undocumented args to dump())
        want = """
extra:
- foo
- bar
extramodule:
  unique: true
force: true
home: mydata
mymodule:
  arbitrary:
    nesting:
      depth: works
  expires: 2014-10-24
  extra:
  - foo
  - baz
  - quux
  force: false
processes: 4
""".lstrip()
        with open("complex.yaml") as fp:
            got = fp.read().replace("\r\n", "\n")
        self.assertEqual(want, got)

class TestPListFile(unittest.TestCase, ConfigSourceHelperTests):

    supported_types = (str, int, bool, list, datetime)

    def setUp(self):
        with open("simple.plist", "w") as fp:
            fp.write("""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>expires</key>
        <string>2014-10-15</string>
        <key>extra</key>
        <array>
                <string>foo</string>
                <string>bar</string>
        </array>
        <key>force</key>
        <true/>
        <key>home</key>
        <string>mydata</string>
        <key>lastrun</key>
        <date>2014-10-15T14:32:07Z</date>
        <key>processes</key>
        <integer>4</integer>
</dict>
</plist>
""")
        with open("complex.plist", "w") as fp:
            fp.write("""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>extra</key>
        <array>
                <string>foo</string>
                <string>bar</string>
        </array>
        <key>extramodule</key>
        <dict>
                <key>unique</key>
                <true/>
        </dict>
        <key>force</key>
        <true/>
        <key>home</key>
        <string>mydata</string>
        <key>mymodule</key>
        <dict>
                <key>arbitrary</key>
                <dict>
                        <key>nesting</key>
                        <dict>
                                <key>depth</key>
                                <string>works</string>
                        </dict>
                </dict>
                <key>expires</key>
                <string>2014-10-15</string>
                <key>extra</key>
                <array>
                        <string>foo</string>
                        <string>baz</string>
                </array>
                <key>force</key>
                <false/>
        </dict>
        <key>processes</key>
        <integer>4</integer>
</dict>
</plist>
""")
        with open("extra.plist", "w") as fp:
            fp.write("""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>home</key>
        <string>otherdata</string>
</dict>
</plist>
""")

        with open("extra-layered.plist", "w") as fp:
            fp.write("""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>mymodule</key>
        <dict>
                <key>force</key>
                <true/>
        </dict>
</dict>
</plist>
""")
        self.simple = PListFile("simple.plist")
        self.complex = PListFile("complex.plist")
        self.extra = PListFile("extra.plist")
        self.extra_layered = PListFile("extra-layered.plist")

    def tearDown(self):
        os.unlink("simple.plist")
        os.unlink("complex.plist")
        os.unlink("extra.plist")
        os.unlink("extra-layered.plist")

    # override only because plists cannot handle date objects (only datetime)
    def test_get(self):
        self.assertEqual(self.simple.get("home"), "mydata")
        self.assertEqual(self.simple.get("processes"), 4)
        self.assertEqual(self.simple.get("force"), True)
        self.assertEqual(self.simple.get("extra"), ['foo', 'bar'])
        self.assertEqual(self.simple.get("expires"), "2014-10-15")
        self.assertEqual(self.simple.get("lastrun"),
                         datetime(2014, 10, 15, 14, 32, 7))

    def test_write(self):
        self.maxDiff = None
        cfg = LayeredConfig(self.complex)
        cfg.mymodule.expires = date(2014, 10, 24)
        cfg.mymodule.extra.append('quux')
        # calling write for any submodule will force a write of the
        # entire config file
        LayeredConfig.write(cfg.mymodule)
        # note: plistlib creates files with tabs, not spaces.
        want = """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>extra</key>
	<array>
		<string>foo</string>
		<string>bar</string>
	</array>
	<key>extramodule</key>
	<dict>
		<key>unique</key>
		<true/>
	</dict>
	<key>force</key>
	<true/>
	<key>home</key>
	<string>mydata</string>
	<key>mymodule</key>
	<dict>
		<key>arbitrary</key>
		<dict>
			<key>nesting</key>
			<dict>
				<key>depth</key>
				<string>works</string>
			</dict>
		</dict>
		<key>expires</key>
		<string>2014-10-24</string>
		<key>extra</key>
		<array>
			<string>foo</string>
			<string>baz</string>
			<string>quux</string>
		</array>
		<key>force</key>
		<false/>
	</dict>
	<key>processes</key>
	<integer>4</integer>
</dict>
</plist>
"""
        if sys.version_info < (2,7,0): # pragma: no cover
            # on py26, the doctype includes "Apple Computer" not "Apple"...
            want = want.replace("//Apple//", "//Apple Computer//")
        with open("complex.plist") as fp:
            got = fp.read().replace("\r\n", "\n")
        self.assertEqual(want, got)

    def test_typed(self):
        for key in self.simple.keys():
            # PList can type ints, bools, lists and datetimes (but not dates)
            if key in ("processes", "force", "extra", "lastrun"):
                self.assertTrue(self.simple.typed(key))
            else:
                self.assertFalse(self.simple.typed(key))

class TestPyFile(unittest.TestCase, ConfigSourceHelperTests):

    def setUp(self):
        with open("simple.py", "w") as fp:
            fp.write("""from __future__ import unicode_literals
import datetime

expires = datetime.date(2014,10,15)
extra = ['foo', 'bar']
force = True
home = 'mydata'
lastrun = datetime.datetime(2014,10,15,14,32,7)
processes = 4
""")
        with open("complex.py", "w") as fp:
            fp.write("""from __future__ import unicode_literals
import datetime

extra = ['foo', 'bar']
force = True
home = 'mydata'
processes = 4

mymodule = Subsection()
mymodule.expires = datetime.date(2014,10,15)
mymodule.extra = ['foo', 'baz']
mymodule.force = False
mymodule.arbitrary = Subsection()
mymodule.arbitrary.nesting = Subsection()
mymodule.arbitrary.nesting.depth = 'works'

extramodule = Subsection()
extramodule.unique = True
""")

        with open("extra.py", "w") as fp:
            fp.write("""from __future__ import unicode_literals

home = 'otherdata'
""")

        with open("extra-layered.py", "w") as fp:
            fp.write("""from __future__ import unicode_literals

mymodule = Subsection()
mymodule.force = True
""")
        self.simple = PyFile("simple.py")
        self.complex = PyFile("complex.py")
        self.extra = PyFile("extra.py")
        self.extra_layered = PyFile("extra-layered.py")

    def tearDown(self):
        os.unlink("simple.py")
        os.unlink("complex.py")
        os.unlink("extra.py")
        os.unlink("extra-layered.py")

class TestCommandline(unittest.TestCase, ConfigSourceHelperTests):

    # Note: bool is "half-way" supported. Only value-less parameters
    # are typed as bool (eg "--force", not "--force=True")
    supported_types = (str, list, bool)

    simple_cmdline = ['--home=mydata',
                      '--processes=4',
                      '--force',  # note implicit boolean typing
                      '--extra=foo',
                      '--extra=bar',
                      '--expires=2014-10-15',
                      '--lastrun=2014-10-15 14:32:07']

    complex_cmdline = ['--home=mydata',
                       '--processes=4',
                       '--force=True',
                       '--extra=foo',
                       '--extra=bar',
                       '--mymodule-force=False',
                       '--mymodule-extra=foo',
                       '--mymodule-extra=baz',
                       '--mymodule-expires=2014-10-15',
                       '--mymodule-arbitrary-nesting-depth=works',
                       '--extramodule-unique']

    def setUp(self):
        super(TestCommandline, self).setUp()
        # this means we lack typing information
        self.simple = Commandline(self.simple_cmdline)
        self.complex = Commandline(self.complex_cmdline)

    # Overrides of TestHelper.test_get, .test_typed and and due to
    # limitations of Commandline (carries almost no typeinfo)
    def test_get(self):
        self.assertEqual(self.simple.get("home"), "mydata")
        self.assertEqual(self.simple.get("processes"), "4")
        self.assertEqual(self.simple.get("force"), True)
        self.assertEqual(self.simple.get("extra"), ['foo','bar'])  # note typed!
        self.assertEqual(self.simple.get("expires"), "2014-10-15")
        self.assertEqual(self.simple.get("lastrun"), "2014-10-15 14:32:07")

    def test_typed(self):
        for key in self.simple.keys():
            # these should be typed as bool and list, respectively
            if key in ("force", "extra"):
                self.assertTrue(self.simple.typed(key))
            else:
                self.assertFalse(self.simple.typed(key))

    def test_config_subsections(self):
        # this case uses valued parameter for --force et al, which
        # cannot be reliably converted to bools using only intrinsic
        # information
        self.supported_types = (str, list)
        super(TestCommandline, self).test_config_subsections()

    def test_layered_subsections(self):
        pass  # this test has no meaning for Command line arguments
              # (can't have two sets of them)

    def test_overwriting_with_missing_subsections(self):
        pass  # this test has no meaning for Command line arguments
              # (can't have two sets of them)

    def test_dump_layered(self):
        pass

    def test_set(self):
        self.simple.set("home", "away from home")
        self.assertEqual(self.simple.get("home"), "away from home")

    def test_custom_sectionsep(self):
        # https://github.com/staffanm/layeredconfig/issues/9 -- we
        # want to make sure that cfg.db.host returns a simple string,
        # not a 1-element array of strings, even when not using the
        # default section separator '-'.
        cmdline = ['--dbhost=string', '--db_host=array_of_strings']
        src = Commandline(cmdline, sectionsep="_")
        cfg = LayeredConfig(src)
        self.assertIsInstance(cfg.dbhost, str)
        self.assertEquals(cfg.dbhost, 'string')
        self.assertIsInstance(cfg.db.host, str)
        self.assertEquals(cfg.db.host, 'array_of_strings')

    def test_custom_sectionsep_2(self):
        # https://github.com/staffanm/layeredconfig/issues/13
        cmdline = ['--log.rotation_size=100']
        src = Commandline(cmdline, sectionsep=".")
        cfg = LayeredConfig(src)
        self.assertIsInstance(cfg.log.rotation_size, str)
        self.assertEquals(cfg.log.rotation_size, '100')

class TestCommandlineConfigured(TestCommandline):

    supported_types = (str, int, bool, date, datetime, list)
    def setUp(self):
        super(TestCommandlineConfigured, self).setUp()
        simp = argparse.ArgumentParser(description="This is a simple program")
        simp.add_argument('--home', help="The home directory of the app")
        simp.add_argument('--processes', type=int, help="Number of simultaneous processes")
        simp.add_argument('--force', type=LayeredConfig.boolconvert, nargs='?', const=True)
        simp.add_argument('--extra', action='append')
        simp.add_argument('--expires', type=LayeredConfig.dateconvert)
        simp.add_argument('--lastrun', type=LayeredConfig.datetimeconvert)
        simp.add_argument('--unused')
        self.simple = Commandline(self.simple_cmdline,
                                  parser=simp)

        comp = argparse.ArgumentParser(description="This is a complex program")
        comp.add_argument('--home', help="The home directory of the app")
        comp.add_argument('--processes', type=int, help="Number of simultaneous processes")
        comp.add_argument('--force', type=LayeredConfig.boolconvert, nargs='?', const=True)
        comp.add_argument('--extra', action='append')
        comp.add_argument('--mymodule-force', type=LayeredConfig.boolconvert, nargs='?', const=True, dest='mymodule'+UNIT_SEP+'force')
        comp.add_argument('--mymodule-extra', action='append', dest='mymodule'+UNIT_SEP+'extra')
        comp.add_argument('--mymodule-expires', type=LayeredConfig.dateconvert, dest='mymodule'+UNIT_SEP+'expires')
        comp.add_argument('--mymodule-arbitrary-nesting-depth', dest='mymodule'+UNIT_SEP+'arbitrary'+UNIT_SEP+"nesting"+UNIT_SEP+"depth")
        comp.add_argument('--extramodule-unique', nargs='?', const=True, dest='extramodule'+UNIT_SEP+'unique')
        self.complex = Commandline(self.complex_cmdline,
                                   parser=comp)

    def test_get(self):
        # re-enable the original impl of test_get
        ConfigSourceHelperTests.test_get(self)

    def test_config_subsections(self):
        # re-enable the original impl of test_config_subsections
        ConfigSourceHelperTests.test_config_subsections(self)

    def test_typed(self):
        # re-enable the original impl of test_get
        ConfigSourceHelperTests.test_typed(self)

class TestEnvironment(unittest.TestCase, ConfigSourceHelperTests):

    supported_types = (str,)

    simple = Environment({'MYAPP_HOME': 'mydata',
                          'MYAPP_PROCESSES': '4',
                          'MYAPP_FORCE': 'True',
                          'MYAPP_EXTRA': 'foo, bar',
                          'MYAPP_EXPIRES': '2014-10-15',
                          'MYAPP_LASTRUN': '2014-10-15 14:32:07'},
                         prefix="MYAPP_")
    complex = Environment({'MYAPP_HOME': 'mydata',
                           'MYAPP_PROCESSES': '4',
                           'MYAPP_FORCE': 'True',
                           'MYAPP_EXTRA': 'foo, bar',
                           'MYAPP_MYMODULE_FORCE': 'False',
                           'MYAPP_MYMODULE_EXTRA': "foo, baz",
                           'MYAPP_MYMODULE_EXPIRES': '2014-10-15',
                           'MYAPP_MYMODULE_ARBITRARY_NESTING_DEPTH': 'works',
                           'MYAPP_EXTRAMODULE_UNIQUE': 'True'},
                          prefix="MYAPP_")

    def test_get(self):
        self.assertEqual(self.simple.get("home"), "mydata")
        self.assertEqual(self.simple.get("processes"), "4")
        self.assertEqual(self.simple.get("force"), "True")
        self.assertEqual(self.simple.get("extra"), "foo, bar")
        self.assertEqual(self.simple.get("expires"), "2014-10-15")
        self.assertEqual(self.simple.get("lastrun"), "2014-10-15 14:32:07")

    def test_layered_subsections(self):
        pass  # this test has no meaning for environment variables
              # (can't have two sets of them)

    def test_overwriting_with_missing_subsections(self):
        pass  # this test has no meaning for environment variables
              # (can't have two sets of them)

    def test_dump_layered(self):
        pass

    def test_typed(self):
        for key in self.simple.keys():
            self.assertFalse(self.simple.typed(key))

# NB: This assumes that an etcd daemon is running with default
# settings
ETCD_BASE = "http://127.0.0.1:2379/v2/keys"

@unittest.skipIf("APPVEYOR" in os.environ,
                 "Not running etcd dependent tests on Appveyor")
class TestEtcdStore(unittest.TestCase, ConfigSourceHelperTests):
    maxDiff = None
    def strlower(value):
        return str(value).lower()

    supported_types = (str,)

    def _clear_server(self):
        resp = requests.get(ETCD_BASE + "/")
        resp.raise_for_status()
        json = resp.json()
        if 'nodes' in json['node']:
            for node in json['node']['nodes']:
                resp = requests.delete(ETCD_BASE + "%s?recursive=true" % node['key'])

    @property
    def simple(self):
        self._clear_server()
        requests.put(ETCD_BASE + "/home", data={'value': 'mydata'})
        requests.put(ETCD_BASE + "/processes", data={'value': '4'})
        requests.put(ETCD_BASE + "/force", data={'value': "True"})
        requests.put(ETCD_BASE + "/extra", data={'value': "foo, bar"})
        requests.put(ETCD_BASE + "/expires", data={'value': "2014-10-15"})
        requests.put(ETCD_BASE + "/lastrun", data={'value': "2014-10-15 14:32:07"})
        return EtcdStore()

    @property
    def complex(self):
        self._clear_server()
        requests.put(ETCD_BASE + "/home", data={'value': "mydata"})
        requests.put(ETCD_BASE + "/processes", data={'value': "4"})
        requests.put(ETCD_BASE + "/force", data={'value': "True"})
        requests.put(ETCD_BASE + "/extra", data={'value': "foo, bar"})
        requests.put(ETCD_BASE + "/mymodule/force", data={'value': "False"})
        requests.put(ETCD_BASE + "/mymodule/extra", data={'value': "foo, baz"})
        requests.put(ETCD_BASE + "/mymodule/expires", data={'value': "2014-10-15"})
        requests.put(ETCD_BASE + "/mymodule/arbitrary/nesting/depth", data={'value': "works"})
        requests.put(ETCD_BASE + "/extramodule/unique", data={'value': "True"})
        return EtcdStore()

    def test_layered_subsections(self):
        pass  # this test has no meaning for etcd stores, as a single
              # server cannot have two sets of configuration to layere
              # (however, we could concievably have two distinct
              # servers -- but that isn't supported on ground of being
              # too complicated)

    def test_overwriting_with_missing_subsections(self):
        pass  # ditto

    def test_dump_layered(self):
        pass

    def test_typed(self):
        for key in self.simple.keys():
            self.assertFalse(self.simple.typed(key))

    def test_get(self):
        # FIXME: This test should be able to look at supported_types
        # like test_singlesection and test_subsections do, so derived
        # testcase classes don't need to override it.
        conf = self.simple
        self.assertEqual(conf.get("home"), "mydata")
        self.assertEqual(conf.get("processes"), "4")
        self.assertEqual(conf.get("force"), "True")
        self.assertEqual(conf.get("extra"), "foo, bar")
        self.assertEqual(conf.get("expires"), "2014-10-15")
        self.assertEqual(conf.get("lastrun"), "2014-10-15 14:32:07")

    def test_write(self):
        def indexfilter(node):
            # remove keys like createdIdex / modifiedIndex whose
            # values always changes
            if isinstance(node, dict):
                for key in list(node.keys()):
                    if key == "nodes":
                        indexfilter(node[key])
                    elif key.endswith("Index"):
                        del node[key]
            else:
                node[:] = sorted(node, key=itemgetter('key'))
                for subnode in node:
                    indexfilter(subnode)

        cfg = LayeredConfig(self.complex)
        cfg.extra = ['foo', 'value with space']
        cfg.mymodule.expires = date(2014, 10, 24)
        cfg.mymodule.extra = ['foo', 'baz', 'quux']
        # note that this will write the entire config incl cfg.extra,
        # not just the values in the 'mymodule' subsection.
        LayeredConfig.write(cfg.mymodule)
        want = """
{
    "dir": true,
    "nodes": [
        {
            "createdIndex": 4627,
            "key": "/home",
            "modifiedIndex": 4627,
            "value": "mydata"
        },
        {
            "createdIndex": 4628,
            "key": "/processes",
            "modifiedIndex": 4628,
            "value": "4"
        },
        {
            "createdIndex": 4629,
            "key": "/force",
            "modifiedIndex": 4629,
            "value": "True"
        },
        {
            "createdIndex": 4630,
            "key": "/extra",
            "modifiedIndex": 4630,
            "value": "['foo', 'value with space']"
        },
        {
            "createdIndex": 4631,
            "dir": true,
            "key": "/mymodule",
            "modifiedIndex": 4631,
            "nodes": [
                {
                    "createdIndex": 4631,
                    "key": "/mymodule/force",
                    "modifiedIndex": 4631,
                    "value": "False"
                },
                {
                    "createdIndex": 4632,
                    "key": "/mymodule/extra",
                    "modifiedIndex": 4632,
                    "value": "foo, baz, quux"
                },
                {
                    "createdIndex": 4633,
                    "key": "/mymodule/expires",
                    "modifiedIndex": 4633,
                    "value": "2014-10-24"
                },
                {
                    "createdIndex": 4634,
                    "dir": true,
                    "key": "/mymodule/arbitrary",
                    "modifiedIndex": 4634,
                    "nodes": [
                        {
                            "createdIndex": 4634,
                            "dir": true,
                            "key": "/mymodule/arbitrary/nesting",
                            "modifiedIndex": 4634,
                            "nodes": [
                                {
                                    "createdIndex": 4634,
                                    "key": "/mymodule/arbitrary/nesting/depth",
                                    "modifiedIndex": 4634,
                                    "value": "works"
                                }
                            ]
                        }
                    ]
                }
            ]
        },
        {
            "createdIndex": 4635,
            "dir": true,
            "key": "/extramodule",
            "modifiedIndex": 4635,
            "nodes": [
                {
                    "createdIndex": 4635,
                    "key": "/extramodule/unique",
                    "modifiedIndex": 4635,
                    "value": "True"
                }
            ]
        }
    ]
}"""
        want = json.loads(want)
        indexfilter(want)
        got = requests.get("http://localhost:2379/v2/keys/?recursive=true").json()['node']
        indexfilter(got)
        self.assertEqual(want, got)

class TestTyping(unittest.TestCase, LayeredConfigHelperTests):
    types = {'home': str,
             'processes': int,
             'force': bool,
             'extra': list,
             'mymodule': {'force': bool,
                          'extra': list,
                          'expires': date,
                          'lastrun': datetime,
                      }
             }

    def test_typed_commandline(self):
        cmdline = ['--home=mydata',
                   '--processes=4',
                   '--force=True',
                   '--extra=foo',
                   '--extra=bar',
                   '--implicitboolean',
                   '--mymodule-force=False',
                   '--mymodule-extra=foo',
                   '--mymodule-extra=baz',
                   '--mymodule-expires=2014-10-15',
                   '--mymodule-arbitrary-nesting-depth=works',
                   '--extramodule-unique']
        cfg = LayeredConfig(Defaults(self.types), Commandline(cmdline))
        self._test_config_subsections(cfg)
        self.assertTrue(cfg.implicitboolean)
        self.assertIs(type(cfg.implicitboolean), bool)

    def test_typed_novalue(self):
        # this cmdline only sets some of the settings. The test is
        # that the rest should raise AttributeError (not return None,
        # as was the previous behaviour), and that __iter__ should not
        # include them.
        cmdline = ['--processes=4', '--force=False']
        cfg = LayeredConfig(Defaults(self.types), Commandline(cmdline))
        self.assertEqual(4, cfg.processes)
        self.assertIsInstance(cfg.processes, int)
        with self.assertRaises(AttributeError):
            cfg.home
        with self.assertRaises(AttributeError):
            cfg.extra
        self.assertEqual(set(['processes', 'force']),
                         set(list(cfg)))

    def test_typed_override(self):
        # make sure this auto-typing isn't run for bools
        types = {'logfile': True}
        cmdline = ["--logfile=out.log"]
        cfg = LayeredConfig(Defaults(types), Commandline(cmdline))
        self.assertEqual(cfg.logfile, "out.log")

    def test_typed_commandline_cascade(self):
        # the test here is that __getattribute__ must determine that
        # subconfig.force is not typed in itself, and fetch type
        # information from the root of defaults

        defaults = {'force': True,
                    'lastdownload': datetime,
                    'mymodule': {}}
        cmdline = ['--mymodule-force=False']
        cfg = LayeredConfig(Defaults(defaults), Commandline(cmdline),
                            cascade=True)
        subconfig = getattr(cfg, 'mymodule')
        self.assertIs(type(subconfig.force), bool)
        self.assertEqual(subconfig.force, False)

        # test typed config values that have no actual value. Since
        # they have no value, they should raise AtttributeError
        with self.assertRaises(AttributeError):
            self.assertEqual(cfg.lastdownload, None)
        with self.assertRaises(AttributeError):
            self.assertEqual(subconfig.lastdownload, None)

    def test_commandline_implicit_typing(self):
        # The big test here is really the partially-configured
        # ArgumentParser (handles one positional argument but not the
        # optional --force)
        defaults = {'force': False}
        cmdline = ['command', '--force']
        parser = argparse.ArgumentParser()
        parser.add_argument("positional")
        cmdlinesrc = Commandline(cmdline, parser=parser)
        cfg = LayeredConfig(Defaults(defaults), cmdlinesrc)
        self.assertEqual(cfg.force, True)

        # try again with explicit argument
        parser = argparse.ArgumentParser()
        parser.add_argument("positional")
        cmdlinesrc = Commandline(['command', '--force=True'], parser=parser)
        cfg = LayeredConfig(Defaults(defaults), cmdlinesrc)
        self.assertEqual(cfg.force, True)

        # once again without the optional typing source
        parser = argparse.ArgumentParser()
        parser.add_argument("positional")
        cmdlinesrc = Commandline(['command', '--force'], parser=parser)
        cfg = LayeredConfig(Defaults({}), cmdlinesrc)
        self.assertEqual(cfg.force, True)

    def test_layered_typing_for_none_values_in_lower_priority(self):
        source1 = Defaults({'key': None})
        source2 = Environment({'KEY': 3})
        config = LayeredConfig(source1, source2)
        self.assertEquals(config.key, 3)

class TestTypingINIFile(TestINIFileHelper,
                        LayeredConfigHelperTests,
                        unittest.TestCase):
    types = {'home': str,
             'processes': int,
             'force': bool,
             'extra': list,
             'mymodule': {'force': bool,
                          'extra': list,
                          'expires': date,
                          'lastrun': datetime,
                      }
             }

    # FIXME: find a neat way to run the tests in
    # test_config_subsections with a LayeredConfig object that uses a
    # Default object for typing
    def test_typed_inifile(self):
        cfg = LayeredConfig(Defaults(self.types), INIFile("complex.ini"))
        self.supported_types = (str, bool, int, list, date, datetime)
        self.supports_nesting = False
        self._test_config_subsections(cfg)

class TestLayered(TestINIFileHelper, unittest.TestCase):
    def test_layered(self):
        defaults = {'home': 'someplace'}
        cmdline = ['--home=anotherplace']
        env = {'MYAPP_HOME': 'yourdata'}
        cfg = LayeredConfig(Defaults(defaults))
        self.assertEqual(cfg.home, 'someplace')
        cfg = LayeredConfig(Defaults(defaults), INIFile("simple.ini"))
        self.assertEqual(cfg.home, 'mydata')
        cfg = LayeredConfig(Defaults(defaults), INIFile("simple.ini"),
                            Environment(env, prefix="MYAPP_"))
        self.assertEqual(cfg.home, 'yourdata')
        cfg = LayeredConfig(Defaults(defaults), INIFile("simple.ini"),
                            Environment(env, prefix="MYAPP_"),
                           Commandline(cmdline))
        self.assertEqual(cfg.home, 'anotherplace')
        self.assertEqual(['home', 'processes', 'force', 'extra', 'expires',
                          'lastrun'], list(cfg))

    def test_layered_subsections(self):
        defaults = OrderedDict((('force', False),
                                ('home', 'thisdata'),
                                ('loglevel', 'INFO')))
        cmdline = ['--mymodule-home=thatdata', '--mymodule-force']
        cfg = LayeredConfig(Defaults(defaults), Commandline(cmdline),
                            cascade=True)
        self.assertEqual(cfg.mymodule.force, True)
        self.assertEqual(cfg.mymodule.home, 'thatdata')
        self.assertEqual(cfg.mymodule.loglevel, 'INFO')

        # second test is more difficult: the lower-priority Defaults
        # source only contains a subsection, while the higher-priority
        # Commandline source contains no such subsection. Our
        # sub-LayeredConfig object will only have a Defaults source,
        # not a Commandline source (which will cause the
        # __getattribute__ lookup_resource to look in the Defaults
        # object in the sub-LayeredConfig object, unless we do
        # something smart.
        defaults = {'mymodule': defaults}
        cmdline = ['--home=thatdata', '--force']

        o = Commandline(cmdline)
        o.subsection("mymodule").keys()
        cfg = LayeredConfig(Defaults(defaults), Commandline(cmdline),
                            cascade=True)
        self.assertEqual(cfg.mymodule.force, True)
        self.assertEqual(cfg.mymodule.home, 'thatdata')
        self.assertEqual(cfg.mymodule.loglevel, 'INFO')
        self.assertEqual(['force', 'home', 'loglevel'], list(cfg.mymodule))

class TestSubsections(unittest.TestCase):
    def test_list(self):
        defaults = {'home': 'mydata',
                    'subsection': {'processes': 4}}
        cfg = LayeredConfig(Defaults(defaults),
                            cascade=True)
        self.assertEqual(set(['home', 'processes']),
                         set(cfg.subsection))

    def test_subsection_respects_subclass(self):
        defaults = {
            'subsection': {
                'processes': 4
            }
        }

        class SubclassedLayeredConfig(LayeredConfig):
            pass

        cfg = SubclassedLayeredConfig(Defaults(defaults))
        self.assertIsInstance(cfg.subsection, SubclassedLayeredConfig)

    def test_cascading_parent_subsections(self):
        defaults = {'home': 'mydata',
                    'subsection': {'processes': 4}}
        cfg = LayeredConfig(Defaults(defaults),
                            cascade=True)
        # if the DictSource has a bug in its has() implementatation,
        # and we use cascade, any subsection will have an automatic
        # subsection with the same name of its own, and which will
        # yield a raw dict
        with self.assertRaises(AttributeError):
            cfg.subsection.subsection

class TestLayeredSubsections(unittest.TestCase):

    def _test_subsection(self, primary, secondary, cls):
        with open("primary.txt", "w") as fp:
            fp.write(primary)
        with open("secondary.txt", "w") as fp:
            fp.write(secondary)
        try:
            srcs = [cls('primary.txt'), cls('secondary.txt')]
            cfg = LayeredConfig(*srcs)
            self.assertEqual(cfg.somevar, 'value')
            self.assertEqual(cfg.a.b, 'b')
        finally:
            os.unlink("primary.txt")
            os.unlink("secondary.txt")

    def test_layered_yaml(self):
        self._test_subsection("""a:
  b: b
        """, "somevar: value", YAMLFile)

    def test_layered_ini(self):
        self._test_subsection("""
[__root__]

[a]

b = b
""", """
[__root__]
somevar = value
""", INIFile)

    def test_layered_json(self):
        self._test_subsection('{"a": {"b": "b"} }',
                              '{"somevar": "value"}',
                              JSONFile)

    def test_layered_plist(self):
        self._test_subsection("""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>a</key>
        <dict>
        	<key>b</key>
        	<string>b</string>
        </dict>
</dict>
</plist>""", """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>somevar</key>
        <string>value</string>
</dict>
</plist>""", PListFile)

class TestLayeredWithSingleSource(unittest.TestCase):
    # generalization of the issue demonstrated by
    # https://github.com/staffanm/layeredconfig/issues/8 -- sources
    # that cannot be duplicated/layered by themselves (Environment,
    # Commandline, EtcdStore) should be tested with other sources,
    # particularly with subsections

    def setUp(self):
        with open("simple.yaml", "w") as fp:
            fp.write("""
section:
   subsection:
      key: value
""")
        self.yamlsource = YAMLFile("simple.yaml")

    def tearDown(self):
        os.unlink("simple.yaml")

    def test_commandline(self):
        cfg = LayeredConfig(self.yamlsource, Commandline())
        self.assertEqual("value", cfg.section.subsection.key)

        cmdline = ["./foo.py", "--foo=bar"]
        cfg = LayeredConfig(self.yamlsource, Commandline(cmdline))
        self.assertEqual("value", cfg.section.subsection.key)

        cmdline = ["./foo.py", "--foo=bar", "--section-subsection-key=other"]
        cfg = LayeredConfig(self.yamlsource, Commandline(cmdline))
        self.assertEqual("other", cfg.section.subsection.key)

    def test_environment(self):
        cfg = LayeredConfig(self.yamlsource, Environment())
        self.assertEqual("value", cfg.section.subsection.key)

        env = {'MYAPP_FOO': 'bar'}
        cfg = LayeredConfig(self.yamlsource, Environment(env, prefix="MYAPP_"))
        self.assertEqual("value", cfg.section.subsection.key)

        env = {'MYAPP_FOO': 'bar',
               'MYAPP_SECTION_SUBSECTION_KEY': 'other'}
        cfg = LayeredConfig(self.yamlsource, Environment(env, prefix="MYAPP_"))
        self.assertEqual("other", cfg.section.subsection.key)

class TestModifications(TestINIFileHelper, unittest.TestCase):
    def test_modified(self):
        defaults = {'lastdownload': None}
        cfg = LayeredConfig(Defaults(defaults))
        now = datetime.now()
        cfg.lastdownload = now
        self.assertEqual(cfg.lastdownload, now)

    def test_modified_subsections(self):
        defaults = {'force': False,
                    'home': 'thisdata',
                    'loglevel': 'INFO'}
        cmdline = ['--mymodule-home=thatdata', '--mymodule-force']
        cfg = LayeredConfig(Defaults(defaults),
                            INIFile("complex.ini"),
                            Commandline(cmdline),
                            cascade=True)
        cfg.mymodule.expires = date(2014, 10, 24)

    def test_modified_singlesource_subsection(self):
        self.globalconf = LayeredConfig(
            Defaults({'download_text': None,
                      'base': {}}),
            cascade=True)
        # this should't raise an AttributeError
        self.globalconf.base.download_text
        # this shouldn't, either
        self.globalconf.base.download_text = "WHAT"

    def test_write_noconfigfile(self):
        cfg = LayeredConfig(Defaults({'lastrun':
                                      datetime(2012, 9, 18, 15, 41, 0)}))
        cfg.lastrun = datetime(2013, 9, 18, 15, 41, 0)
        LayeredConfig.write(cfg)

    def test_set_novalue(self):
        # it should be possible to set values that are defined in any
        # of the configsources, even though only typing information
        # exists there.
        cfg = LayeredConfig(Defaults({'placeholder': int}),
                            Commandline([]))
        cfg.placeholder = 42

        # but it shouldn't be possible to set values that hasn't been
        # defined anywhere.
        with self.assertRaises(AttributeError):
            cfg.nonexistent = 43

class TestAccessors(TestINIFileHelper, unittest.TestCase):

    def test_set(self):
        # a value is set in a particular underlying source, and the
        # dirty flag isn't set.
        cfg = LayeredConfig(INIFile("simple.ini"))
        LayeredConfig.set(cfg, 'expires', date(2013, 9, 18),
                          "inifile")
        # NOTE: For this config, where no type information is
        # available for key 'expires', INIFile.set will convert the
        # date object to a string, at which point typing is lost.
        # Therefore this commmented-out test will fail
        # self.assertEqual(date(2013, 9, 18), cfg.expires)
        self.assertEqual("2013-09-18", cfg.expires)
        self.assertFalse(cfg._sources[0].dirty)

    def test_get(self):
        cfg = LayeredConfig(Defaults({'codedefaults': 'yes',
                                      'force': False,
                                      'home': '/usr/home'}),
                            INIFile('simple.ini'))
        # and then do a bunch of get() calls with optional fallbacks
        self.assertEqual("yes", LayeredConfig.get(cfg, "codedefaults"))
        self.assertEqual("mydata", LayeredConfig.get(cfg, "home"))
        self.assertEqual(None, LayeredConfig.get(cfg, "nonexistent"))
        self.assertEqual("NO!", LayeredConfig.get(cfg, "nonexistent", "NO!"))

class TestDump(unittest.TestCase):
    def test_dump(self):
        defaults = {
            'home': 'mydata',
            'processes': 4,
            'force': True,
            'extra': ['foo', 'bar'],
            'mymodule': {
                'force': False,
                'extra': ['foo', 'baz'],
                'arbitrary': {
                    'nesting': {
                        'depth': 'works'
                    }
                }
            },
            'extramodule': {
                'unique': True
            }
        }

        config = LayeredConfig(Defaults(defaults))
        self.assertEquals(defaults, LayeredConfig.dump(config))

if __name__ == '__main__':
    unittest.main()

redpajama_set_name: RedPajamaGithub


text:
Thursday 02 December 2021 10:10 am
Fidelity chief exec Anne Richards to chair TheCityUK board
By: Farah Ghouri
The chief executive of Fidelity International has today been named as the next board chair of the Square Mile's most influential lobbying body.
Dame Anne Richards will take over the position from Mark Tucker, chairman of HSBC Holdings, who will step down at the end of May 2022 after three years in the role.
TheCityUK: London at risk of losing global financial status in next five years
Richards will work closely with the group's leadership council chairman Sir Adrian Montague while leading the board and the executive team to "champion and support the success of the UK-based financial and related professional services industry," TheCityUK said in a statement.
Speaking about her priorities as the new chair, Richards said: "As we emerge from the pandemic, new ways of working, technological innovation and heightened expectations will continue to revolutionise how we operate and serve our customers."
"We must also play our part in accelerating a just and sustainable transition to a low carbon economy," she continued.
TheCityUK is an lobbying body that represents financial and related professional services in the UK. Earlier this year the body conducted research which found that the City generated nearly £100bn in taxes last year, highlighting the degree to which the government relies on finance, law and accountancy firms for cash.
The financial, legal and accountancy sectors contributed nearly £13 for every £100 in taxes, according to lobby group.
But the group has also warned that the City is at risk of losing its status as a global financial powerhouse within the next five years.
Richards, who has worked in the asset management sector for almost three decades, was made CEO of Fidelity International in 2018 after starting her career as a research fellow at CERN, the European Organisation for Nuclear Research.
A board member of the Institute of International Finance (IIF) since last year, Richards was appointed a Dame Commander (DBE) this summer for services to financial services, women, education and science.
Magic Circle: Slaughter & May poaches first COO from Freshfields amid executive reshuffle
Crypto AM shines its spotlight on Sundaeswap and the Cardano 2022 scaling roadmap
Four day work week trial shows 100:80:100 model is taking off in UK but same job in less time may power stress and anxiety
London law firms hired record number of partners in 2021
Court orders ex-chairman of Kazakh paper company to return £120m worth of cash and luxury London properties
Two-fifths of London SMEs plan to shed workers as furlough ends and pandemic restrictions return
PLAN B CHAOS
London First lobby group to change its name to catch up with govt 'levelling up' agenda
Nftcracker: Natalia Osipova auctions off NFTs to fund new dance company
Revealed: London businesses the most profitable in the country
London on Top
Ministers warned that failing to solve £360m in pandemic rent arrears could lead to 'mass homelessness'
While you were asleep: Two children and two women die in house fire in Bexleyheath

redpajama_set_name: RedPajamaCommonCrawl


If you've been involved in an accident, DUI, or you've been injured on the job, you may be asked to take a drug test to test for the presence of alcohol or other illegal substances. In these cases, blood drug testing is usually performed because this is the only accurate method for determining legal intoxication. If you've been involved in a work-related accident and your blood drug test is requested by an insurance agency, you'll probably be taking a urine drug test as well.
Blood drug testing has limitations and the process is considered to be invasive by many people. This method for testing offers a small window of time for detection. This type of test has to be given by a qualified individual in a controlled setting in order to be valid. Additionally, the expense involved with blood drug tests make administration less practical for general use in employment screenings.
Drug blood tests are designed to test for the presence of drugs at the time your test is taken. These tests can also be used to determine whether or not you have current health issues in conjunction with screen for drugs. Some conditions commonly tested for include, cholesterol levels, hepatitis, HIV, AIDS, and diabetes. This type of test can allow for more flexibility in the types of tests and detection of the levels of substances. This can offer more insight into how often someone uses a specific substance.
Blood drug tests have a much shorter time for drug detection than other types of drug tests. This test detects the presence of drugs, not drug metabolites that the body creates. In most cases, drugs are only present in the blood for a very short period of time. The time that drugs remain present in your blood can be as little as a few hours to a few days.
Of course, there are exceptions. Long term use of marijuana can be detected in the blood for as much as 7 days. Nicotine and opiates can also be detected for several days.
Blood drug tests can have different cutoff levels for detection which can affect the length of time that the drug can be detected in your system. It's impossible to know the sensitivity levels of the test used by each lab; betting on the minimum time for detection may not be an effective method for avoiding a positive result. Because of this limitation, blood drug testing is not widely used for employment.


text:
Russia ready to resume gas supplies to Europe via Yamal-Europe pipeline -Novak
© Reuters. FILE PHOTO: Model of natural gas pipeline, EU and Russia flags, July 18, 2022. REUTERS/Dado Ruvic/Illustration
GAZP
(Reuters) -Moscow is ready to resume gas supplies to Europe through the Yamal-Europe Pipeline, Russian Deputy Prime Minister Alexander Novak told state TASS news agency.
"The European market remains relevant, as the gas shortage persists, and we have every opportunity to resume supplies," TASS cited Novak as saying in remarks published by the agency on Sunday.
"For example, the Yamal-Europe Pipeline, which was stopped for political reasons, remains unused."
The Yamal-Europe Pipeline usually flows westward, but has been mostly reversed since December of 2021 as Poland turned away from buying from Russia in favour of drawing on stored gas in Germany.
In May, Warsaw terminated its agreement with Russia, after earlier rejecting Moscow's demand that it pays in roubles.
Russian supplier Gazprom (MCX:GAZP) responded by cutting off supply and also said it would no longer be able to export gas via Poland after Moscow imposed sanctions against the firm that owns the Polish section of the Yamal-Europe pipeline.
Novak also reiterated that Moscow is discussing additional gas supplies through Turkey after a creation of a hub there.
He also said that Moscow expects it will have shipped 21 billion cubic metres (bcm) of liquefied natural gas (LNG) to Europe in 2022.
"This year we were able to significantly increase LNG supplies to Europe," Novak said. "In the 11 months of 2022 they increased to 19.4 bcm, by the end of the year 21 bcm are expected."
(Reporting in Melbourne by Lidia Kelly; Editing by Leslie Adler and Nick Zieminski)
Belarus says Russia-deployed Iskander missile systems ready for use


It is time to start the discussion of our next novel from The Bestseller Code 100 list, The White Tiger by Aravind Adiga.
Summary: An example of an epistolary novel, main character Balram Halwai writes about his rags to riches story as he leaves behind his impoverished Indian village to establish his own taxi business.
Although Aravind Adiga was only 33 when he published this debut novel, it won the Man Booker Prize in 2008.
Have you read The White Tiger by Aravind Adiga? We'd love to hear your thoughts.
Have you written about The White Tiger by Aravind Adiga? Feel free to add a link to your review here.


text:
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Naif.Blog.Framework;
using Naif.Blog.Services;

#pragma warning disable 1998

namespace Naif.Blog.ViewComponents
{
    public class GoogleAnalyticsViewComponent : BaseViewComponent
    {
        public GoogleAnalyticsViewComponent(IBlogRepository blogRepository, IApplicationContext appContext) : base(
            blogRepository, appContext)
        {
        }

        public async Task<IViewComponentResult> InvokeAsync()
        {
            // ReSharper disable once Mvc.ViewComponentViewNotResolved
            return View(Blog);
        }

    }
}


text:
SportChevron Right IconAthletics
McDermott wins high jump in Canberra
John Salvado
Nicola McDermott has made a flying start to the 2021 season. Credit: AAP
Commonwealth Games bronze medallist Nicola McDermott has made a flying start to her 2021 campaign with a dominant high jump victory at the Summer Series meet in Canberra.
Competing for the first time in more than five months, McDermott sailed over the bar at 1.96m, before making two unsuccessful attempts at what would have been a new Australian and Oceania record of 2m.
McDermott's big domestic rival, 2014 Commonwealth Games champion and national record holder Eleanor Patterson, skipped the Canberra meet but is expected to return to action within a fortnight.
The pair are pushing each other hard in the race to become the first Australian woman to clear the two-metre barrier.
"When I did the 1.96 and I saw the clearance I thought 'let's not mess around, let's go for the two (metres)' and I was just so excited to be attempting it today," said the 24-year-old McDermott.
"I attempted two metres twice in Europe (last year) but when I stare at that bar there's so much emotion attached to it.
"I thought the attempts weren't quite at the level they could be.
"But the technique is coming along really well and I just need more comps."
With COVID-19 playing havoc with elite sport in 2020, McDermott was one of only a handful of Australian athletes who chose to head to Europe for the northern hemisphere summer season.
The 2018 Commonwealth Games bronze medallist was rewarded with a PB of 1.98m in Germany and the promise of even better to come in 2021.
She had a scare in training a few weeks ago when she felt tightness in her Achilles during a bad takeoff at training.
"That was in the back of my mind and I was a bit hesitant and really trying to overcome that today," said McDermott.
"The 1.96 means more to me than I could possibly put into words.
"For the two metres we are just getting a bit more aggressive at the takeoff , more lean, more acceleration.
"I know I've got more in store."
McDermott and Patterson are likely to resume their head-to-head rivalry at the Canberra Track Classic on March 11.
Reigning Commonwealth champion Brandon Starc won the men's high jump on Thursday evening with 2.27m.
In other action at the Summer Series meet, Jack Hale won the men's 100m in 10.21 seconds.
Fast-improving Hana Basic dominated the women's 100m in a winning time of 11.25 but was denied a personal best because the wind reading of 2.1m per second was just above the legal limit.


text:
What can octopus brains tell us about human brains? • Earth.com
What can octopus brains tell us about human brains?
ByAlison Bosman
Earth.com staff writer
Octopuses are considered to be very intelligent – for invertebrates, that is. Along with other cephalopods, such as cuttlefish and squids, octopuses have the most complex brains and nervous systems of any invertebrate animals. Scientists have often wondered why these mollusks were the only ones to develop more neurological complexity, while this phenomenon characterizes most vertebrates.
Looking way back in evolutionary history, humans and octopuses have a common ancestor – a primitive, worm-like creature with minimal intelligence and simple eyespots. Its descendants subsequently gave rise to the two large branches of the animal kingdom, the vertebrates (with backbones) and the invertebrates (without). While the vertebrates evolved to have large and complex brains with considerable cognitive abilities, the invertebrates did not – except for the cephalopods, that is.
A new study by researchers from the Max Delbrück Center and Dartmouth College in the United States has now uncovered a way in which octopus brains are similar to the brains of higher vertebrates, such as humans. Their findings, published in the journal Science Advances, show that octopuses have a large variety of different genes that code for microRNAs (miRNAs) in their brains and nervous tissue, which is similar to the trend observed during the evolution of vertebrates.
"So, this is what connects us to the octopus!" said study co-author Professor Nikolaus Rajewsky. He explained that this finding probably means miRNAs play a fundamental role in the development of complex brains.
Consisting of no more than 23 nucleotides, miRNAs are small, single-stranded, non-coding RNA molecules that are found in plant and animal cells. They play important roles in regulating gene expression, mostly by targeting messenger RNA molecules and preventing them from leaving the nucleus to be involved in protein synthesis.
In 2019, Professor Rajewsky read a publication about genetic analyses conducted on octopuses. Scientists had discovered that a lot of RNA editing occurs in these cephalopods – meaning that they make extensive use of certain enzymes that can change the coding of their RNA. "This got me thinking that octopuses may not only be good at editing, but could have other RNA tricks up their sleeve too," said Rajewsky.
He began a collaboration with scientists from the Stazione Zoologica Anton Dohrn marine research station in Naples, who sent him samples of 18 different tissue types from dead octopuses. The research team profiled all the small RNA molecules in these tissues and found a massive expansion in the types of miRNA molecules present, when compared with those in other invertebrates. In particular, 42 new families of the genes that code for miRNAs were present in the octopus tissues.
"This is the third-largest expansion of microRNA families in the animal world, and the largest outside of vertebrates," said study lead author Dr. Grygoriy Zolotarov. "To give you an idea of the scale, oysters, which are also mollusks, have acquired just five new microRNA families since the last ancestors they shared with octopuses – while the octopuses have acquired 90! Oysters," adds Zolotarov, "aren't exactly known for their intelligence."
Currently, the source and selective pressures for the rise of these novel miRNA genes is not known but, given that they have been conserved during cephalopod evolution, the team concluded they are clearly beneficial to the animals and are therefore functionally important. Further analysis of late stage embryonic octopus cells indicated that many of these novel miRNAs were primarily expressed in nerve cells and tissues, during development. These findings led the researchers to propose that the miRNAs were necessary for, and intimately linked to, the evolution of complex animal brains.
The findings of the team therefore suggest that cephalopods evolved greater brain complexity in the same way as vertebrate brains did, by using a lot more regulatory miRNAs to control gene activity. However, further research is needed to understand exactly how the miRNA molecules work and what they do during neuronal development.
"Since octopuses aren't typical model organisms, our molecular-biological tools were very limited," said Dr. Zolotarov. "So we don't yet know exactly which types of cell express the new microRNAs." The researchers are now planning to apply a technique, developed in Rajewsky's lab, which will make the cells in octopus tissue visible at a molecular level.
By Alison Bosman, Earth.com Staff Writer
Check us out on EarthSnap, a free app brought to you by Eric Ralls and Earth.com.
Machine learning may solve the mystery of bird movements
Large carnivore attacks are increasing as human impacts expand
Ocean plastic can be used to make pharmaceuticals
319-million-year-old fish holds clues about brain evolution
Fireworks have long lasting impacts on wildlife


text:
Importance Of A Lift Access System For Elevator Safety And Security
Why is a lift access system important for elevator safety and security?
Secures tenants and guests
Prevents intruders
Helps in evacuation
Gives peace of mind
Technology is an interesting concept. Because of it, we are now experiencing the convenience of riding an elevator instead of walking up through numerous flights of stairs. While it has made life easier for many, it was also seen as an opportunity by trouble makers that want to intrude on both private and commercial buildings for a quick buck. Because of this, the lift access system was invented. If you're interested in learning more about the importance of elevator safety and security, keep on reading!
A lift access system can enhance the safety and security of an establishment. It does this by giving access cards to only the tenants and authorized guests. Cards can be customized to have basic user details, so the owner can monitor whose cards are used with each entry. With Elid there are also anti-passback options so only one passenger per card will be allowed.
Guests who visit can also be given an access card, but it will expire within a few hours or a day so it can't be used by outsiders. Even staff who lose their card will only be given a temporary card while the old one will be removed from the database. Because all who enter are cardholders, you will be able to monitor where they go and when they exit your establishment.
This gives you a record of who goes where and when. It also limits any unauthorized access to restricted areas, because cards can be customized to only gain entry on specific floors.
Most lift access systems work with other security solutions to protect a whole establishment. Because of this intruders can't even enter through the main door itself unless they are given authority by the lobby staff. This can also deter a lot of criminals so most of them will not even try going in.
Other lift access systems can still be overcome by pretentious troublemakers who mimic the looks and uniforms of tenants. Then they tailgate a person with authorized access to ride the elevator. Most people wouldn't think twice about helping these strangers. But with the Elid Anti-tailgate system, this can be prevented.
In the worst-case scenario when an intruder still forces his way in by tampering with card readers, an automatic intruder detection system will alert you of the incident. Through this, you can contact the police immediately. The software may also even allow you to automatically initiate a lockdown to trap an intruder from getting out.
A lift access system can help you respond immediately to emergencies that involve the safety and security of your building's tenants. For example, if you receive a report of a missing person, you can easily access the database for the last card access named after them. This will lead you to the elevator used, and the floor from which they exited.
If your building undergoes disasters such as flooding and fire, your response will be faster. Advanced software can count the number of logged-in tenants and guests in a building and even have a feature to record who successfully evacuated. This will assist you in your rescue operations.
Without all these, finding missing persons or evacuating a whole building will be a difficult task. You have to do it manually and search every nook and cranny of the whole building without any idea as to where to find the missing people.
A safe and secured elevator will give peace of mind to both tenants and guests in your building. They will see it as a haven, and immediately feel comfortable upon entering the premises. Whether it's their office or home, they can rest assured that they will be safe from any intruders.
The presence of an access control system will also make your establishment look more professional and modern, which can impress not just potential clients, but also stockholders and investors. Even visitors who stay for a short while will feel safe and may even return in the future to do business with you.
Aside from all these, it will also make your property value go up. If you're renting an apartment or office space, clients will be willing to pay more for the added security. All because it will give them peace of mind.
A lift access system can improve the safety and security of your building. This is important because it can secure your tenants and guests, prevent intruders or deal with them, evacuate people in times of emergencies, and give peace of mind to everyone who enters.
If you're interested in access control systems, you may send a message here. You can also browse Elid's products here.


Well at long last I greet you all with the last blog on this Marquetry Wine Box Saga!!
Keeping my 93 year old father company (these past two day) while he recovers from a nasty lung infection, has given me ample opportunity to catch up on computer stuff. And now I can devote a few relaxing hours to the composition of this final blog!
Well it's time to put a lid on this whole thing and cap her up in fine style!
The only part I'm cheating on here is the use of a previously made lid base … left over from my Old Wine Box days! It was the perfect size, but definitely needed beefing up and beautifying. I cut a piece of Cedar plank (given to me from Paul's stash and which he so kindly planed to my requirements for another wine box I intend to create.) Ah yes! A future blog!!
This piece of Cedar will attach to the bottom part of the lid base … and because my (indelible ink) signature exists on the underside of my OWBox lid, I had a sudden spurt of inspiration deciding to incorporate my 'John Henry' in this style.
What's with the red wine in a bottle?! Well it's all about 'presentation', and it's just very unfortunate that my home-made cheesy onion bread and cheese plate, etc. has all but obliterated a vision of Paul's beautiful Marquetry design on this very special gift he offered months back … feeling that he was 'short-changing' me on our arrangement of veneer/cedar planking exchange. If he doesn't come into my 'veneer-candy-store-room' more often, I'm afraid he'll want this beautiful tray back!! Nah … not Paul. He's such a sweet guy!!
Feeling the glow of wine infuse my grey matter … the most I could concentrate upon (after Paul left) was to throw a few loose thoughts together. What do I want the lid to look like? Certainly not plain and simple like the poor OWBox lid. I want pizazz!!! And that's about as far as my thoughts would go for that day!
It is amazing how the mind takes over at times when you least expect it. In the middle of that night I awoke, knowing my dreams had been playing around with lid-thoughts. My eyes opened, and ideas flooded straight through them into my brain. I'm sure I'm not alone with that miracle feeling of inspiration that makes you want to leap from the bed … or stop the car to jot down the idea before it's lost!! I couldn't wait to get back in the shop the next morning. However a few days passed before I was able to formulate that mind-thought.
In the meantime another visit from Paul took me back to the workshop for a brief but enjoyable moment while we discussed some possible veneer choices to depict water for his most recent project.
Even though days past, my mind remained actively involved with ideas that finally came together with my next workshop day. Exploring with NGR stains to portray a Rosewood look onto solid stock Cedar seemed to work just fine … and so I cut more Cedar for the top of the lid, having one particular reason for this in mind. I didn't have solid stock Rosewood! And I needed solid wood to carry out my idea of 'inlaying' the Marquetry flower with Intarsia formation. Something I have never done before … or even thought to do!
The flower center was glued onto the cut stock piece after being filled.
The flower petals and leaves were cut out individually, leaving a template for me to scribe onto the other section of lid. All these parts were sanded and shaped … by hand because they were way too small for tooling!
I like!! But decided against elevation of various parts as the veneered surface bumped the design just enough.
NGR stain was applied to both pieces that would comprise the lid. Walking away from the workshop that afternoon, I was happy with the results so far.
......... then sanded to shape. When it came to sand shading the edges, butterflies fluttered … never having done this kind of shading before. I had to use my specialized piano tweezers in order to grip that thickness over the heat … a bit hot to handle but it worked!!
Then they were set in order for staining, and lacquering … before assembling what will become a free standing Intarsia handle!!
In the meantime … I had qualms about the 'Rosewood' Cedar … it didn't look just right. I kick myself for not thinking of this right off the bat … but you know what they say about hindsight! The surface was sanded completely free of NGR stain … don't ask me why I did that because I didn't need to. I guess my mind was in a quandary over my next step, and so I needed extra time to ponder! Maybe that's why it takes so long for me to get things done!!!
I decided to veneer over the Cedar with Rosewood. Duh! ... why didn't I think of that before now?!! But before I could do that I had to do a 'rub' of the recess area in the cedar.
Both Rosewood sections were padded together, and cut along the inside of the penciled rub. Inside … because you want a tiny bit of excess to trim off, instead of the cut being too large. The handy-dandy Dremel will clean things up!
And because I've now applied a layer of veneer over my solid stock portions of the lid-to-be, effectively eliminating the elevation of my Marquetry Intarsia-ed flower, that section cut from the Rosewood is glued into the recess … elevation solved!!
I can read your minds … OMG!! what is happening now?!! Yes, those are paint stir-sticks from Cloverdale. Perfect for my little dream-inspired notion! Rosewood glued onto sticks … then sticks separated … sanded ….
.............. these miter-cornered trim pieces were glued in place around the semi-finished lid … before the insertion of flowers, etc. so I had a flat surface to work with.
Strangely enough I didn't take photos of the miter-cutting process which was done on my bandsaw table set at the most ungainly angle!! My mind was on the horrendous task of concentration … mitered corners!!!
See them pretty mitered corners!!! The stir-sticks give the accent I had in mind! ... and now the lid is ready for a few coats of lacquer sanding sealer with recesses protected. Actually at this stage, the top has already been given a few coats … before the trim was applied. The surface shows up much lighter in this photo than it really is.
I was so impressed with myself, I made more 'Rosewood sticks'. Stick around and you'll see how they were used!!
OH NOOOOOOOOOO!! In my hast to spray one more coat of sealer onto the box so I could stop for lunch, my precious article of excessive hours slid off the spray table and landed with a crash while I had turned to pick up the spray gun. I froze … afraid to look!!
So much for being impressed with myself. Puff up those feathers, and something bad is bound to happen! It's either that … or my stomach was protesting over lack of regularly scheduled nutrition!!
Have I ever mentioned those special spirits I have in my workshop? ... watching over my every move?? Well … somebody up there loves me, because the damage (although to the upper front corner) was easy to fix!
One smart smack, a bit of glue … and a dab of touch-up pen was a very quick fix indeed. With only preliminary lacquering at this stage, the added coats will hide all signs of distress. Thank you my Workshop Spirits!!
Hummmmm! ... You would think I could have at least shown the repaired injury!! I guess you'll just have to trust me that nobody will ever notice the boo-boo … But did you happen to notice the Rosewood-stir-stick trim around the bottom of the box? I think that's what I was trying to capture in this photo for you all to see!! I also forgot to show the cork bottom on this box, to prevent scratching our countertop.
Well my LumberJock Buddies I've come to the end of this series of blogs on my Marquetry Wine Box Saga. I know … I know!! You're screaming: "What? Where's the finished lid??!" Even after enduring this very lengthy blog, you still want more?!!
I'm always ending blogs with thanks … and this one is no exception!!
AGAIN I thank you all for joining me from start to finish. It's been a wonderful journey, made more so because of your involvement! Each time I pour myself a glass of wine from Nouveau Gal … I shall think of you all.
Elaine, you are truly a creative genius sometimes.
That is some nice lid!!
Do the folks at Cloverdale Paint ask many questions when you just come in for stir sticks?
Great project and wonderful blog.
HI Elaine, thanks for a great blog, a glimpse into marquetry and for sharing your project build with us. I look forward to seeing your posted project. Is Nouveau Gal base on an Alphonse Mucha picture?
Thanks for the great blog, I learned and enjoyed it. However now I am addicted and your leaving us cold turkey. How about Nouveau Man, or boy, dog, something. Looking forward to your next project.
Hi Elaine, what an amazing journey! An awesome project! I'm looking forward to seeing the photos of the finished box lid and all on your project page. I love the way you have signed your piece. Great idea!
Yes Peter … you are absolutely right! When I was searching for an Art Nouveau design, that's all I googled and up popped a plethora of designs without any credits given … just the images. My thanks to you for his name which I immediately googled … and found my Nouveau Gal!! ... along with Alphonse Mocha's many beautiful Art Nouveau paintings.
Tom … actually I'll soon start working upon Nouveau Lady for our granddaughter's 13th birthday. That blog will be short and sweet as most of it was already blogged in the Wine Box Saga … but you'll have to wait until the end of June for that blog to happen. Can you hold off that long?!
Thanks Anna … glad you liked the signature. I thought it was pretty cool myself, and hope to carry the idea through to future pieces!
OK most of the time.
That was a wonderful ride Elaine. Full of excitements and pizazz.
I Will be waiting for your project with anticipation; I got to see the lid:).
Thank you for this great blog series.
I'm really looking forward to your project post when you reveal the finished lid. And I'll be sure to check for your blog in late June on your granddaughter's birthday present.
I hope your dad is soon fully recovered. We'll be traveling to see my folks soon (94 and 95) and know how precious the time with parents can be.
I very much enjoyed your witty, amusing blog on this beautiful wine box Elaine and I learned a lot too. I always read your blog at least three times. The first time for the fun of it. The second time to get my head around what you have actually done, and finally a third time to appreciate and understand the artistic choices you have made to give your work the wow factor! I also really love the signature you devised, very artistic and cool. I'm sure your father will be glad to get you back now, but we will surely miss you while you are away. Thanks for sharing with us.
I felt for you and the box, but you carried on.
Thank you again for just doing this! The project is certainly beautiful and following the progress is inspiring to each of us; your candid, honest blog is entertaining as well as educational. Its been a fun trip. I hope you take us along again. Best wishes to you and your family.
Elaine, you do absolutely beautiful work and I loved the pictures and explanation of it all. I surely want to see more of what you do and how you do it.
I've somehow missed seeing your work before, but I'm adding you to my buddies list, so that doesn't happen again!
Great series, and has left us like many of our TV shows do at spring time, wanting and waiting for more episodes!


text:
AgentReal Estate
Topeka lures out-of-state buyers with charm, financial incentives
Choose Topeka incentivizing out of state buyers to relocate
November 12, 2021, 4:58 pm By Brooklee Han
Topeka, Kansas, the sunflower state's capital city, is not quite as bustling and metropolitan as some of the state's larger cities, namely Kansas City and Wichita. But according to local Prestige Real Estate agent Kylie Edington, that's the selling point.
"You get a small town feel here," Edington said. "Everyone says that the people are super friendly and it's such a centralized location because we are still close to Kansas City and Lawrence and Emporia. You can get to the bigger areas within an hour. But we have all the shopping and restaurants you need here and we've had a lot of downtown revitalization."
The attraction of Topeka's big city amenities and small town vibe has driven up demand in the city, catapulting it to eighth place on Realtor.com's list of the hottest housing markets in September.
While home prices in the city remain very affordable, especially compared to other popular metros, September's median list price of $159,900 represents a 12.2% year-over-year increase, according to Realtor.com.
Agents told Realtrends that it's a mix of local and out-of-state buyers driving the strong demand.
"We are seeing a lot of local first-time homebuyers and a lot of move-up buyers," local eXp agent Karey Brown said. "We are also getting a lot of people from California. Most of our relocations are coming from California, but we are also seeing people from other places."
Edington has seen similar trends with most of her out of state buyers coming from California, but she has also worked with several buyers from Las Vegas, Colorado and the East Coast.
The low home prices are certainly one factor driving interest from out of state buyers, but the city's Choose Topeka program, which provides monetary incentives for homebuyers who relocate to the area, is another.
The applications to the program are open to both on site and remote workers who move to the area and 60 candidates will be selected each year for up $15,000 in incentive pay.
"I send the Choose Topeka program to all of my out of state buyers," Edington said. "They are basically paying people to move here."
Although the market in Topeka has let up a bit since its peak in the spring, local agents said it is still running strong.
"We are still having some homes get multiple offers, but we are actually starting to get to the point where a few homes are on the market long enough that we can actually hold an open house," Brown said. "So it is definitely slowing down a little. Before you would just put it on the market in the morning and by evening you'd have 12 offers come in."
Edington attributed the slowdown to typical seasonal patterns, but she said that for her, things have sped back up in the past few weeks. "November is shaping up to be my busiest month this year," she said.
As the market has cooled the number of bidding wars has also dropped, slowing the rapid price increases.
"Earlier in the year I had a client put in an offer for $40,000 over asking and they still didn't get it," Edington said. "But now we are seeing things go for full list price or a little over."
Like countless other metros nationwide, inventory is low in Topeka. According the Kansas Association of Realtors, statewide, in the month of September, the number of active listings was down 17.7% year over year.
"Inventory was a problem even before COVID," Brown said. "But it became really pronounced when COVID happened and it has just been getting worse. I think lately, though we are seeing a few more listings as we are seeing some homes sit on the market for a few days."
Due to low the inventory and continued strong demand, homes are not sitting on the market for very long.
"Our average days on market right now is about 13 and our median days on market is even lower," Amanda Lewis, a local Coldwell Banker Griffith & Blair American Home agent said.
Looking to the future, agents expect the hot market conditions to continue into next spring.
"As long as nothing drastic happens with the fed raising rates overnight or something like that, I think we will stay steady at where we are at," Lewis said.


If you are like me, you have tried a lot of products, workouts, and diets that have not helped you Build Muscle . Fifteen years ago, I started working out and I was totally clueless. I wasted a lot of time with bs diets and workout plans and I was never able acquire a significant amount of muscle mass WITHOUT getting fat.
After years of trial and error, I finally found the few secrets to gaining muscle mass fast WITHOUT getting fat fat! I do not want you to have go through years of trial and error! I am going to give you all of Muscle Building secrets you will ever need to know!
Building muscle mass WITHOUT getting fat is not as complex as people make it out to be. In fact it is quite simple! Here are a few things you will learn from this book that will help you burn fat FAST.
This book is a collection of some of the best methods I know to Build Muscle Mass in the fastest amount of time possible. I have been a personal trainer for over 10 years. I have worked for many of the top gyms in New York City. I have trained professional athletes and top models. I have also worked as a fitness model for Nike, Adidas, Jordan, Puma, and others. I say all that to say this: I know what I am talking about.
I have used every technique written here on myself and my clients over the years. They all work!
For a limited time, you will also get 5 FREE bonus chapters!!!
P.S. Scroll up and click the "Buy" button now before the price raises!
Muscle Building Tips That Will Work Starting Today!
Are You Maximizing Your Workouts To Build Muscle?
FITSHAPE AMINO 2200 – #1 BCAA Branced Chain Aminio Acids Supplements – Gains Muscle mass – Burns Fat and fast recovery.