plaster_pastedeploy-0.5/0000755€Déíè€bP^q0000000000013257216533021237 5ustar michaelDA\Domain Users00000000000000plaster_pastedeploy-0.5/PKG-INFO0000644€Déíè€bP^q0000002021213257216533022331 0ustar michaelDA\Domain Users00000000000000Metadata-Version: 1.2 Name: plaster_pastedeploy Version: 0.5 Summary: A loader implementing the PasteDeploy syntax to be used by plaster. Home-page: https://github.com/Pylons/plaster_pastedeploy Author: Hunter Senft-Grupp Author-email: pylons-discuss@googlegroups.com License: UNKNOWN Description: =================== plaster_pastedeploy =================== .. image:: https://img.shields.io/pypi/v/plaster_pastedeploy.svg :target: https://pypi.python.org/pypi/plaster_pastedeploy .. image:: https://img.shields.io/travis/Pylons/plaster_pastedeploy/master.svg :target: https://travis-ci.org/Pylons/plaster_pastedeploy ``plaster_pastedeploy`` is a plaster_ plugin that provides a ``plaster.Loader`` that can parse ini files according to the standard set by PasteDeploy_. It supports the ``wsgi`` plaster protocol, implementing the ``plaster.protocols.IWSGIProtocol`` interface. Usage ===== Applications should use ``plaster_pastedeploy`` to load settings from named sections in a configuration source (usually a file). - Please look at the documentation for plaster_ on how to integrate this loader into your application. - Please look at the documentation for PasteDeploy_ on the specifics of the supported INI file format. Most applications will want to use ``plaster.get_loader(uri, protocols=['wsgi'])`` to get this loader. It then exposes ``get_wsgi_app``, ``get_wsgi_app_settings``, ``get_wsgi_filter`` and ``get_wsgi_server``. .. code-block:: python import plaster loader = plaster.get_loader('development.ini', protocols=['wsgi']) # to get any section out of the config file settings = loader.get_settings('app:main') # to get settings for a WSGI app app_config = loader.get_wsgi_app_settings() # defaults to main # to get an actual WSGI app app = loader.get_wsgi_app() # defaults to main # to get a filter and compose it with an app filter = loader.get_wsgi_filter('filt') app = filter(app) # to get a WSGI server server = loader.get_wsgi_server() # defaults to main # to start the WSGI server server(app) Any ``plaster.PlasterURL`` options are forwarded as defaults to the loader. Some examples are below: - ``development.ini#myapp`` - ``development.ini?http_port=8080#main`` - ``pastedeploy+ini:///path/to/development.ini`` - ``pastedeploy+ini://development.ini#foo`` - ``egg:MyApp?debug=false#foo`` .. _PasteDeploy: https://pastedeploy.readthedocs.io/en/latest/ .. _plaster: https://docs.pylonsproject.org/projects/plaster/en/latest/ 0.5 (2018-03-29) ================ - Removed environment variable support entirely for now. The feature requires bugfixes upstream in PasteDeploy which have not been done yet and this was breaking people's environments so it is gone for now. See https://github.com/Pylons/plaster_pastedeploy/pull/15 0.4.2 (2017-11-20) ================== - Fix ``ConfigDict.copy`` so that it works. See https://github.com/Pylons/plaster_pastedeploy/pull/14 0.4.1 (2017-07-10) ================== - Disable environment variable support on Python 2. PasteDeploy does not support escaping the contents on Python 2 which means any variable with a value of the format %(foo)s would break the parser. Because this is implicit behavior it was deemed too error prone to support. See https://github.com/Pylons/plaster_pastedeploy/pull/10 - Escape environment variables such that their contents are not subject to interpolation. See https://github.com/Pylons/plaster_pastedeploy/pull/10 - Invoke ``logging.basicConfig`` when ``setup_logging`` is called and the config file doesn't contain any logging setup or the URI is using the ``egg:`` protocol. See https://github.com/Pylons/plaster_pastedeploy/pull/11 0.4 (2017-07-09) ================ - Fix ``get_settings`` for an arbitrary section to follow the same rules as PasteDeploy with regards to the handling of defaults. The goal of this package is to be compliant with PasteDeploy's format for all sections in the file such that there are no surprising format changes in various sections. Supported added for ``set default_foo = bar`` and ``get foo = default_foo`` syntax to override a default value and to pull a default value into the settings, respectively. In the above example the value ``foo = bar`` would be returned. Any other defaults not pulled into the section via either interpolation or the ``get`` syntax will be ignored. See https://github.com/Pylons/plaster_pastedeploy/pull/6 - Inject environment variables into the defaults automatically. These will be available for interpolation as ``ENV_``. For example if environment variable ``APP_DEBUG=true`` then ``%(ENV_APP_DEBUG)s`` will work within the ini file. See https://github.com/Pylons/plaster_pastedeploy/pull/7 - ``get_settings`` and ``get_wsgi_app_settings`` both return only the local config now. However, the returned object has a ``global_conf`` attribute containing the defaults as well as a ``loader`` attribute pointing at the loader instance. See https://github.com/Pylons/plaster_pastedeploy/pull/8 0.3.2 (2017-07-01) ================== - Resolve an issue in which ``NoSectionError`` would not be properly caught on Python 2.7 if the ``configparser`` module was installed from PyPI. See https://github.com/Pylons/plaster_pastedeploy/issues/5 0.3.1 (2017-06-02) ================== - Recognize the ``pastedeploy+egg`` scheme as an ``egg`` type. 0.3 (2017-06-02) ================ - Drop the ``ini`` scheme and replace with ``file+ini`` and ``pastedeploy``. Also rename ``ini+pastedeploy`` and ``egg+pastedeploy`` to ``pastedeploy+ini`` and ``pastedeploy+egg`` respectively. See https://github.com/Pylons/plaster_pastedeploy/pull/4 0.2.1 (2017-03-29) ================== - Fix a bug in 0.2 in which an exception was raised for an invalid section if the a non-config-file-based protocol was used. 0.2 (2017-03-29) ================ - No longer raise ``plaster.NoSectionError`` exceptions. Empty dictionaries are returned for missing sections and a user should check ``get_sections`` for the list of valid sections. 0.1 (2017-03-27) ================ - Initial release. Keywords: plaster pastedeploy plaster_pastedeploy ini config egg Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.* plaster_pastedeploy-0.5/CONTRIBUTING.rst0000644€Déíè€bP^q0000000621613257213544023704 0ustar michaelDA\Domain Users00000000000000.. highlight:: shell ============ Contributing ============ Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given. You can contribute in many ways: Types of Contributions ---------------------- Report Bugs ~~~~~~~~~~~ Report bugs at https://github.com/Pylons/plaster_pastedeploy/issues. If you are reporting a bug, please include: * Your operating system name and version. * Any details about your local setup that might be helpful in troubleshooting. * Detailed steps to reproduce the bug. Fix Bugs ~~~~~~~~ Look through the GitHub issues for bugs. Anything tagged with "bug" is open to whoever wants to implement it. Implement Features ~~~~~~~~~~~~~~~~~~ Look through the GitHub issues for features. Anything tagged with "feature" is open to whoever wants to implement it. Write Documentation ~~~~~~~~~~~~~~~~~~~ plaster_pastedeploy could always use more documentation, whether as part of the official plaster_pastedeploy docs, in docstrings, or even on the web in blog posts, articles, and such. Submit Feedback ~~~~~~~~~~~~~~~ The best way to send feedback is to file an issue at https://github.com/Pylons/plaster_pastedeploy/issues. If you are proposing a feature: * Explain in detail how it would work. * Keep the scope as narrow as possible, to make it easier to implement. * Remember that this is a volunteer-driven project, and that contributions are welcome :) Get Started! ------------ Ready to contribute? Here's how to set up `plaster_pastedeploy` for local development. 1. Fork the `plaster_pastedeploy` repo on GitHub. 2. Clone your fork locally:: $ git clone git@github.com:your_name_here/plaster_pastedeploy.git 3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:: $ python3 -m venv env $ env/bin/pip install -e .[testing] 4. Create a branch for local development:: $ git checkout -b name-of-your-bugfix-or-feature Now you can make your changes locally. 5. When you're done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox:: $ tox 6. Add your name to the ``CONTRIBUTORS.txt`` file in the root of the repository. 7. Commit your changes and push your branch to GitHub:: $ git add . $ git commit -m "Your detailed description of your changes." $ git push origin name-of-your-bugfix-or-feature 8. Submit a pull request through the GitHub website. Pull Request Guidelines ----------------------- Before you submit a pull request, check that it meets these guidelines: 1. The pull request should include tests. 2. If the pull request adds functionality, the docs should be updated. Put your new functionality into a function with a docstring, and add the feature to the list in README.rst. 3. The pull request should work for Python 2.7, 3.4, 3.5, 3.6 and for PyPy. Check https://travis-ci.org/Pylons/plaster_pastedeploy/pull_requests and make sure that the tests pass for all supported Python versions. Tips ---- To run a subset of tests:: $ py.test tests.test_plaster_pastedeploy plaster_pastedeploy-0.5/tests/0000755€Déíè€bP^q0000000000013257216533022401 5ustar michaelDA\Domain Users00000000000000plaster_pastedeploy-0.5/tests/conftest.py0000644€Déíè€bP^q0000000100113257213544024567 0ustar michaelDA\Domain Users00000000000000import os.path import pkg_resources import pytest import sys @pytest.fixture(scope='session') def fake_packages(): # we'd like to keep this scope more focused but it's proven really # difficult to fully monkeypatch pkg_resources and so for now we just # install the packages for the duration of the test suite test_dir = os.path.dirname(__file__) info_dir = os.path.join(test_dir, 'fake_packages', 'FakeApp') sys.path.insert(0, info_dir) pkg_resources.working_set.add_entry(info_dir) plaster_pastedeploy-0.5/tests/test_loader.py0000644€Déíè€bP^q0000000043413257213544025260 0ustar michaelDA\Domain Users00000000000000import plaster def test___repr__(): from plaster_pastedeploy import Loader uri = plaster.PlasterURL('pastedeploy+ini', 'development.ini') loader = Loader(uri) assert str(loader) == ( 'plaster_pastedeploy.Loader(uri="pastedeploy+ini://development.ini")' ) plaster_pastedeploy-0.5/tests/test_get_wsgi_app.py0000644€Déíè€bP^q0000000427613257213544026472 0ustar michaelDA\Domain Users00000000000000import os import plaster import pytest here = os.path.dirname(__file__) basic_app_relpath = 'sample_configs/basic_app.ini' basic_app_path = os.path.abspath(os.path.join(here, basic_app_relpath)) class TestSimpleURI(object): config_uri = basic_app_path @pytest.fixture(autouse=True) def loader(self, fake_packages, monkeypatch): monkeypatch.chdir(here) self.loader = plaster.get_loader(self.config_uri, protocols=['wsgi']) def test_get_wsgi_app_with_relative(self): import fakeapp.apps app = self.loader.get_wsgi_app() assert app is fakeapp.apps.basic_app def test_get_wsgi_app_main(self): import fakeapp.apps app = self.loader.get_wsgi_app('main') assert app is fakeapp.apps.basic_app same_app = self.loader.get_wsgi_app() assert same_app is fakeapp.apps.basic_app def test_invalid_name(self): with pytest.raises(LookupError): self.loader.get_wsgi_app('invalid') class TestSectionedURI(TestSimpleURI): config_uri = basic_app_path + '#main' class TestSchemeAndSectionedURI(TestSimpleURI): config_uri = 'pastedeploy+ini:' + basic_app_path + '#main' class TestRelativeURI(TestSimpleURI): config_uri = basic_app_relpath class TestRelativeSectionedURI(TestSectionedURI, TestRelativeURI): config_uri = basic_app_relpath + '#main' class TestRelativeSchemeAndSectionedURI(TestSchemeAndSectionedURI, TestRelativeURI): config_uri = 'pastedeploy+ini:' + basic_app_relpath + '#main' class TestEggURI(object): config_uri = 'egg:FakeApp#basic_app' @pytest.fixture(autouse=True) def loader(self, fake_packages): self.loader = plaster.get_loader(self.config_uri, protocols=['wsgi']) def test_it(self): import fakeapp.apps app = self.loader.get_wsgi_app() assert app is fakeapp.apps.basic_app def test_it_override_name(self): import fakeapp.configapps app = self.loader.get_wsgi_app('configed') assert isinstance(app, fakeapp.configapps.SimpleApp) def test_invalid_name(self): with pytest.raises(LookupError): self.loader.get_wsgi_app('invalid') plaster_pastedeploy-0.5/tests/test_get_wsgi_server.py0000644€Déíè€bP^q0000000343613257213544027215 0ustar michaelDA\Domain Users00000000000000import os import plaster import pytest here = os.path.dirname(__file__) test_config_path = 'sample_configs/test_config.ini' class TestSimpleURI(object): config_uri = test_config_path @pytest.fixture(autouse=True) def loader(self, fake_packages, monkeypatch): monkeypatch.chdir(here) self.loader = plaster.get_loader(self.config_uri, protocols=['wsgi']) def test_get_wsgi_server_default(self): server = self.loader.get_wsgi_server() dummy_app = object() result = server(dummy_app) assert result is dummy_app assert server.settings['foo'] == 'main' def test_invalid_name(self): with pytest.raises(LookupError): self.loader.get_wsgi_server('invalid') class TestSectionedURI(TestSimpleURI): config_uri = test_config_path + '#other' def test_get_wsgi_server_default(self): server = self.loader.get_wsgi_server() dummy_app = object() result = server(dummy_app) assert result is dummy_app assert server.settings['foo'] == 'other' class TestSchemeAndSectionedURI(TestSectionedURI): config_uri = 'pastedeploy+ini:' + test_config_path + '#other' class TestEggURI(object): config_uri = 'egg:FakeApp#fake' @pytest.fixture(autouse=True) def loader(self, fake_packages): self.loader = plaster.get_loader(self.config_uri, protocols=['wsgi']) def test_it(self): server = self.loader.get_wsgi_server() result = server('foo') assert result == 'foo' def test_it_override_name(self): server = self.loader.get_wsgi_server('fake') result = server('foo') assert result == 'foo' def test_invalid_name(self): with pytest.raises(LookupError): self.loader.get_wsgi_server('invalid') plaster_pastedeploy-0.5/tests/__init__.py0000644€Déíè€bP^q0000000000013257213544024477 0ustar michaelDA\Domain Users00000000000000plaster_pastedeploy-0.5/tests/test_get_wsgi_app_settings.py0000644€Déíè€bP^q0000000430413257213544030402 0ustar michaelDA\Domain Users00000000000000import os import plaster import pytest here = os.path.dirname(__file__) test_config_relpath = 'sample_configs/test_config.ini' test_config_path = os.path.abspath(os.path.join(here, test_config_relpath)) class TestFullURI(object): @pytest.fixture(autouse=True) def loader(self, fake_packages, monkeypatch): monkeypatch.chdir(here) self.loader = plaster.get_loader( test_config_relpath, protocols=['wsgi']) def test_get_wsgi_app_settings(self): result = self.loader.get_wsgi_app_settings('test_get') assert result == {'def1': 'a', 'foo': 'TEST'} assert result.global_conf['def1'] == 'a' assert result.global_conf['def2'] == 'TEST' assert 'basepath' in result.global_conf def test_invalid_name(self): with pytest.raises(LookupError): self.loader.get_wsgi_app_settings('invalid') def test_foreign_config(self): result = self.loader.get_wsgi_app_settings('test_foreign_config') assert result == {'another': 'FOO', 'bob': 'your uncle'} assert result.global_conf['def1'] == 'a' # NOTE this is actually different on pastedeploy tip but unreleased assert result.global_conf['def2'] == 'from include' assert result.global_conf['def3'] == 'c' assert result.global_conf['glob'] == 'override' assert 'basepath' in result.global_conf class TestSimpleURI(object): @pytest.fixture(autouse=True) def loader(self, fake_packages, monkeypatch): monkeypatch.chdir(here) self.loader = plaster.get_loader( 'sample_configs/test_filter_with.ini', protocols=['wsgi']) def test_get_wsgi_app_settings(self): conf = self.loader.get_wsgi_app_settings() assert conf['example'] == 'test' class TestEggURI(object): config_uri = 'egg:FakeApp#configed' @pytest.fixture(autouse=True) def loader(self, fake_packages): self.loader = plaster.get_loader(self.config_uri, protocols=['wsgi']) def test_it(self): conf = self.loader.get_wsgi_app_settings() assert conf == {} def test_invalid_name(self): with pytest.raises(LookupError): self.loader.get_wsgi_app_settings('invalid') plaster_pastedeploy-0.5/tests/sample_configs/0000755€Déíè€bP^q0000000000013257216533025372 5ustar michaelDA\Domain Users00000000000000plaster_pastedeploy-0.5/tests/sample_configs/basic_app.ini0000644€Déíè€bP^q0000000032312726030555030010 0ustar michaelDA\Domain Users00000000000000[application:main] use = egg:FakeApp#basic_app [application:other] use = egg:FakeApp#other [composit:remote_addr] use = egg:FakeApp#remote_addr app.1 = main addr.1 = 127.0.0.1 app.2 = other addr.2 = 0.0.0.0 plaster_pastedeploy-0.5/tests/sample_configs/test_filter.ini0000644€Déíè€bP^q0000000067012726030555030420 0ustar michaelDA\Domain Users00000000000000[app:normal] use = egg:FakeApp#basic_app [pipeline:piped] pipeline = egg:FakeApp#caps normal [filter-app:filt] use = egg:FakeApp#caps method_to_call = lower next = normal [filter:filt] use = egg:FakeApp#caps method_to_call = lower [pipeline:piped2] pipeline = egg:FakeApp#caps2 normal [filter-app:filt2] use = egg:FakeApp#caps2 method_to_call = lower next = normal [app:inv] use = egg:FakeApp#basic_app filter-with = egg:FakeApp#caps plaster_pastedeploy-0.5/tests/sample_configs/test_settings.ini0000644€Déíè€bP^q0000000027513257214066030775 0ustar michaelDA\Domain Users00000000000000[DEFAULT] default_a = default_a default_b = default_b [section1] a = a_val get c = default_b b = %(default_b)s set default_b = override_b [section2] a = a_val b = b_val c = %(default_c)s plaster_pastedeploy-0.5/tests/sample_configs/test_config.ini0000644€Déíè€bP^q0000000202613257213544030376 0ustar michaelDA\Domain Users00000000000000[DEFAULT] def1 = a def2 = b basepath = %(here)s [app:test1] use = egg:FakeApp#configed setting1 = foo setting2 = bar apppath = %(basepath)s/app [app:test2] use = egg:FakeApp#configed set def1 = test2 set another = TEST local conf = something [app:test3] use = test2 set def1 = test3 another = something more across several lines [app:test_foreign_config] use = config:test_config_included.ini set glob = override another = FOO [app:test_get] use = egg:FakeApp#configed set def2 = TEST get def1 = def1 get foo = def2 [app:test_global_conf] use = egg:FakeApp#configed test_interp = this:%(inherit)s [server:main] use = egg:FakeApp#fake foo = main [server:other] use = egg:FakeApp#fake foo = other [loggers] keys = root [handlers] keys = console [formatters] keys = generic [logger_root] level = INFO handlers = console [handler_console] class = StreamHandler args = (sys.stderr,) level = NOTSET formatter = generic [formatter_generic] format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s plaster_pastedeploy-0.5/tests/sample_configs/test_config_included.ini0000644€Déíè€bP^q0000000032513257213544032245 0ustar michaelDA\Domain Users00000000000000[DEFAULT] def2 = from include def3 = c [app:main] # Equivalent to the egg reference, but just for kicks... paste.app_factory = fakeapp.configapps:SimpleApp.make_app set glob = orig bob = your uncle another = BAR plaster_pastedeploy-0.5/tests/sample_configs/test_filter_with.ini0000644€Déíè€bP^q0000000026512726030555031453 0ustar michaelDA\Domain Users00000000000000[app:main] use = egg:FakeApp#basic_app example = test filter-with = filter1 [filter:filter1] use = egg:FakeApp#caps filter-with = filter2 [filter:filter2] use = egg:FakeApp#caps plaster_pastedeploy-0.5/tests/fake_packages/0000755€Déíè€bP^q0000000000013257216533025145 5ustar michaelDA\Domain Users00000000000000plaster_pastedeploy-0.5/tests/fake_packages/FakeApp/0000755€Déíè€bP^q0000000000013257216533026454 5ustar michaelDA\Domain Users00000000000000plaster_pastedeploy-0.5/tests/fake_packages/FakeApp/fakeapp/0000755€Déíè€bP^q0000000000013257216533030063 5ustar michaelDA\Domain Users00000000000000plaster_pastedeploy-0.5/tests/fake_packages/FakeApp/fakeapp/__init__.py0000644€Déíè€bP^q0000000000213257213544032163 0ustar michaelDA\Domain Users00000000000000# plaster_pastedeploy-0.5/tests/fake_packages/FakeApp/fakeapp/apps.py0000644€Déíè€bP^q0000000312413257213544031377 0ustar michaelDA\Domain Users00000000000000############################################################ # Apps ############################################################ def simple_app(response, environ, start_response): start_response('200 OK', [('Content-type', 'text/html')]) return ['This is ', response] def basic_app(environ, start_response): return simple_app('basic app', environ, start_response) def make_basic_app(global_conf, **conf): return basic_app ############################################################ # Filters ############################################################ def make_cap_filter(global_conf, method_to_call='upper'): def cap_filter(app): return CapFilter(app, global_conf, method_to_call) return cap_filter class CapFilter(object): def __init__(self, app, global_conf, method_to_call='upper'): self.app = app self.method_to_call = method_to_call self.global_conf = global_conf def __call__(self, environ, start_response): app_iter = self.app(environ, start_response) for item in app_iter: yield getattr(item, self.method_to_call)() if hasattr(app_iter, 'close'): app_iter.close() ############################################################ # Servers ############################################################ def make_fake_server(global_conf=None, **settings): return Server(global_conf, settings) class Server(object): def __init__(self, global_conf, settings): self.global_conf = global_conf self.settings = settings def __call__(self, app): return app plaster_pastedeploy-0.5/tests/fake_packages/FakeApp/fakeapp/configapps.py0000644€Déíè€bP^q0000000072313257213544032567 0ustar michaelDA\Domain Users00000000000000class SimpleApp(object): def __init__(self, global_conf, local_conf, name): self.global_conf = global_conf self.local_conf = local_conf self.name = name def __call__(self, environ, start_response): start_response('200 OK', [('Content-type', 'text/html')]) return ['I am: ', name] def make_app(cls, global_conf, **conf): return cls(global_conf, conf, 'basic') make_app = classmethod(make_app) plaster_pastedeploy-0.5/tests/fake_packages/FakeApp/setup.py0000644€Déíè€bP^q0000000101213257213544030157 0ustar michaelDA\Domain Users00000000000000from setuptools import setup, find_packages setup( name="FakeApp", version="1.0", packages=find_packages(), entry_points={ 'paste.app_factory': """ basic_app=fakeapp.apps:make_basic_app other=fakeapp.apps:make_basic_app2 configed=fakeapp.configapps:SimpleApp.make_app """, 'paste.filter_factory': """ caps=fakeapp.apps:make_cap_filter """, 'paste.server_factory': """ fake=fakeapp.apps:make_fake_server """, }, ) plaster_pastedeploy-0.5/tests/fake_packages/FakeApp/FakeApp.egg-info/0000755€Déíè€bP^q0000000000013257216533031455 5ustar michaelDA\Domain Users00000000000000plaster_pastedeploy-0.5/tests/fake_packages/FakeApp/FakeApp.egg-info/PKG-INFO0000644€Déíè€bP^q0000000026313257213544032552 0ustar michaelDA\Domain Users00000000000000Metadata-Version: 1.0 Name: FakeApp Version: 1.0 Summary: UNKNOWN Home-page: UNKNOWN Author: UNKNOWN Author-email: UNKNOWN License: UNKNOWN Description: UNKNOWN Platform: UNKNOWN plaster_pastedeploy-0.5/tests/fake_packages/FakeApp/FakeApp.egg-info/SOURCES.txt0000644€Déíè€bP^q0000000034013257213544033335 0ustar michaelDA\Domain Users00000000000000setup.py FakeApp.egg-info/PKG-INFO FakeApp.egg-info/SOURCES.txt FakeApp.egg-info/dependency_links.txt FakeApp.egg-info/entry_points.txt FakeApp.egg-info/top_level.txt fakeapp/__init__.py fakeapp/apps.py fakeapp/configapps.pyplaster_pastedeploy-0.5/tests/fake_packages/FakeApp/FakeApp.egg-info/entry_points.txt0000644€Déíè€bP^q0000000051013257213544034746 0ustar michaelDA\Domain Users00000000000000[paste.app_factory] basic_app=fakeapp.apps:make_basic_app other=fakeapp.apps:make_basic_app2 configed=fakeapp.configapps:SimpleApp.make_app [paste.filter_factory] caps=fakeapp.apps:make_cap_filter [paste.server_factory] fake=fakeapp.apps:make_fake_server plaster_pastedeploy-0.5/tests/fake_packages/FakeApp/FakeApp.egg-info/top_level.txt0000644€Déíè€bP^q0000000001013257213544034175 0ustar michaelDA\Domain Users00000000000000fakeapp plaster_pastedeploy-0.5/tests/fake_packages/FakeApp/FakeApp.egg-info/dependency_links.txt0000644€Déíè€bP^q0000000000113257213544035522 0ustar michaelDA\Domain Users00000000000000 plaster_pastedeploy-0.5/tests/test_setup_logging.py0000644€Déíè€bP^q0000000511413257213544026660 0ustar michaelDA\Domain Users00000000000000import os import plaster import pytest here = os.path.dirname(__file__) test_config_relpath = 'sample_configs/test_config.ini' test_config_path = os.path.abspath(os.path.join(here, test_config_relpath)) class Test_setup_logging(object): @pytest.fixture(autouse=True) def logging(self, fake_packages, monkeypatch): self.basicConfig = DummyFileConfig() self.fileConfig = DummyFileConfig() monkeypatch.setattr('logging.basicConfig', self.basicConfig) monkeypatch.setattr('plaster_pastedeploy.fileConfig', self.fileConfig) monkeypatch.chdir(here) def _makeOne(self, uri=None): if uri is None: uri = test_config_relpath return plaster.get_loader(uri) def test_it_no_global_conf(self): loader = self._makeOne() loader.setup_logging() assert self.fileConfig.called path, defaults = self.fileConfig.args assert path == test_config_relpath assert defaults['__file__'] == test_config_path assert defaults['here'] == os.path.dirname(test_config_path) def test_it_global_conf_empty(self): loader = self._makeOne() loader.setup_logging(defaults={}) assert self.fileConfig.called path, defaults = self.fileConfig.args assert path == test_config_relpath assert defaults['__file__'] == test_config_path assert defaults['here'] == os.path.dirname(test_config_path) def test_it_global_conf_not_empty(self): defaults = {'key': 'val'} loader = self._makeOne() loader.setup_logging(defaults=defaults) assert self.fileConfig.called path, defaults = self.fileConfig.args assert path == test_config_relpath assert defaults['__file__'] == test_config_path assert defaults['here'] == os.path.dirname(test_config_path) assert defaults['key'] == 'val' def test_no_logging_section(self): loader = self._makeOne() loader.get_sections = lambda *args: [] loader.setup_logging() assert self.basicConfig.called assert self.basicConfig.args == () assert self.basicConfig.kwargs == {} def test_egg_uri(self): loader = self._makeOne('egg:FakeApp#fake') loader.setup_logging() assert self.basicConfig.called assert self.basicConfig.args == () assert self.basicConfig.kwargs == {} class DummyFileConfig(object): called = False args = None kwargs = None def __call__(self, *args, **kwargs): self.called = True self.args = args self.kwargs = kwargs plaster_pastedeploy-0.5/tests/test_configdict.py0000644€Déíè€bP^q0000000163213257213544026124 0ustar michaelDA\Domain Users00000000000000""" Tests for plaster_pastedeploy.ConfigDict """ import copy # noqa: F401 import plaster import pytest @pytest.fixture def loader(): from plaster_pastedeploy import Loader uri = plaster.PlasterURL('pastedeploy+ini', 'development.ini') return Loader(uri) def dict_copy(d): return d.copy() def copy_copy(d): return copy.copy(d) @pytest.mark.parametrize('copier', [dict_copy, copy_copy], ids=lambda f: f.__name__) def test_copy(copier, loader): from plaster_pastedeploy import ConfigDict x = [] global_conf = {} configdict = ConfigDict({'x': x}, global_conf, loader) duplicate = copier(configdict) assert duplicate.items() == configdict.items() # check that we got a shallow copy assert duplicate['x'] is x assert duplicate.global_conf is global_conf assert duplicate.loader is loader plaster_pastedeploy-0.5/tests/test_get_settings.py0000644€Déíè€bP^q0000000566213257214107026515 0ustar michaelDA\Domain Users00000000000000import os import plaster import pytest here = os.path.dirname(__file__) test_settings_relpath = 'sample_configs/test_settings.ini' test_settings_path = os.path.abspath(os.path.join(here, test_settings_relpath)) class TestSimpleUri(object): config_uri = test_settings_path @pytest.fixture(autouse=True) def loader(self, fake_packages): self.loader = plaster.get_loader(self.config_uri) def test_sections(self): result = self.loader.get_sections() assert set(result) == {'section1', 'section2'} def test_missing_section(self): result = self.loader.get_settings('missing', {'a': 'b'}) assert result == {} def test_no_defaults_passed(self): result = self.loader.get_settings('section1') assert list(result.items()) == [ ('a', 'a_val'), ('c', 'override_b'), ('b', 'default_b'), ] assert result.global_conf['default_a'] == 'default_a' assert result.global_conf['default_b'] == 'override_b' assert result.loader == self.loader with pytest.raises(Exception): self.loader.get_settings('section2') def test_defaults_passed(self): defaults = {'default_c': 'default_c'} result = self.loader.get_settings('section1', defaults=defaults) assert result['a'] == 'a_val' assert result['b'] == 'default_b' assert 'default_c' not in result assert result.global_conf['default_a'] == 'default_a' assert result.global_conf['default_b'] == 'override_b' assert result.global_conf['default_c'] == 'default_c' result = self.loader.get_settings('section2', defaults=defaults) assert result['a'] == 'a_val' assert result['b'] == 'b_val' assert result['c'] == 'default_c' assert result.global_conf['default_a'] == 'default_a' assert result.global_conf['default_b'] == 'default_b' assert result.global_conf['default_c'] == 'default_c' class TestSectionedURI(TestSimpleUri): config_uri = test_settings_path + '#section1' def test_no_section_name_passed(self): result = self.loader.get_settings() assert result['a'] == 'a_val' assert result['b'] == 'default_b' assert result['c'] == 'override_b' assert 'default_b' not in result class TestFullURI(TestSectionedURI): config_uri = 'pastedeploy+ini:' + test_settings_path + '#section1' class TestEggURI(object): config_uri = 'pastedeploy+egg:FakeApp#basic_app' @pytest.fixture(autouse=True) def loader(self, fake_packages): self.loader = plaster.get_loader(self.config_uri) def test_sections(self): result = self.loader.get_sections() assert result == [] def test_settings(self): result = self.loader.get_settings() assert result == {} def test_named_settings(self): result = self.loader.get_settings('missing') assert result == {} plaster_pastedeploy-0.5/tests/test_get_wsgi_filter.py0000644€Déíè€bP^q0000000467613257213544027203 0ustar michaelDA\Domain Users00000000000000import os import plaster import pytest here = os.path.dirname(__file__) test_filter_path = 'sample_configs/test_filter.ini' class TestSimpleURI(object): config_uri = test_filter_path @pytest.fixture(autouse=True) def loader(self, fake_packages, monkeypatch): monkeypatch.chdir(here) self.loader = plaster.get_loader(self.config_uri, protocols=['wsgi']) def test_get_wsgi_filter(self): import fakeapp.apps app_filter_factory = self.loader.get_wsgi_filter('filt') other_loader = plaster.get_loader( 'sample_configs/basic_app.ini', protocols=['wsgi']) app = other_loader.get_wsgi_app() app_filter = app_filter_factory(app) assert isinstance(app_filter, fakeapp.apps.CapFilter) assert app_filter.method_to_call == 'lower' assert app_filter.app is fakeapp.apps.basic_app def test_invalid_name(self): with pytest.raises(LookupError): self.loader.get_wsgi_filter('invalid') class TestSectionedURI(TestSimpleURI): config_uri = test_filter_path + '#filt' def test_get_wsgi_filter(self): import fakeapp.apps app_filter_factory = self.loader.get_wsgi_filter() other_loader = plaster.get_loader( 'pastedeploy+ini:sample_configs/basic_app.ini#main', protocols=['wsgi']) app = other_loader.get_wsgi_app() app_filter = app_filter_factory(app) assert isinstance(app_filter, fakeapp.apps.CapFilter) assert app_filter.method_to_call == 'lower' assert app_filter.app is fakeapp.apps.basic_app class TestSchemeAndSectionedURI(TestSectionedURI): config_uri = 'pastedeploy+ini:' + test_filter_path + '#filt' class TestEggURI(object): config_uri = 'egg:FakeApp#caps' @pytest.fixture(autouse=True) def loader(self, fake_packages): self.loader = plaster.get_loader(self.config_uri, protocols=['wsgi']) def test_it(self): import fakeapp.apps filter = self.loader.get_wsgi_filter() filtered_app = filter('foo') assert isinstance(filtered_app, fakeapp.apps.CapFilter) def test_it_override_name(self): import fakeapp.apps filter = self.loader.get_wsgi_filter('caps') filtered_app = filter('foo') assert isinstance(filtered_app, fakeapp.apps.CapFilter) def test_invalid_name(self): with pytest.raises(LookupError): self.loader.get_wsgi_filter('invalid') plaster_pastedeploy-0.5/MANIFEST.in0000644€Déíè€bP^q0000000036513257213544023000 0ustar michaelDA\Domain Users00000000000000graft src graft tests include README.rst include CHANGES.rst include LICENSE.txt include CONTRIBUTING.rst include CONTRIBUTORS.txt include .coveragerc include tox.ini appveyor.yml .travis.yml rtd.txt recursive-exclude * __pycache__ *.py[cod] plaster_pastedeploy-0.5/.coveragerc0000644€Déíè€bP^q0000000037713257213544023366 0ustar michaelDA\Domain Users00000000000000[run] parallel = true source = plaster_pastedeploy tests omit = tests/fake_packages/* tests/sample_configs/* [paths] source = src/plaster_pastedeploy */site-packages/plaster_pastedeploy [report] show_missing = true precision = 2 plaster_pastedeploy-0.5/appveyor.yml0000644€Déíè€bP^q0000000101013257213544023616 0ustar michaelDA\Domain Users00000000000000environment: matrix: - PYTHON: "C:\\Python36" TOXENV: "py36" - PYTHON: "C:\\Python35" TOXENV: "py35" - PYTHON: "C:\\Python27" TOXENV: "py27" - PYTHON: "C:\\Python36-x64" TOXENV: "py36" - PYTHON: "C:\\Python35-x64" TOXENV: "py35" - PYTHON: "C:\\Python27-x64" TOXENV: "py27" cache: - '%LOCALAPPDATA%\pip\Cache' version: '{branch}.{build}' install: - "%PYTHON%\\python.exe -m pip install tox" build: off test_script: - "%PYTHON%\\Scripts\\tox.exe" plaster_pastedeploy-0.5/setup.py0000644€Déíè€bP^q0000000447013257216342022754 0ustar michaelDA\Domain Users00000000000000from setuptools import setup, find_packages def readfile(name): with open(name) as f: return f.read() readme = readfile('README.rst') changes = readfile('CHANGES.rst') install_requires = [ 'PasteDeploy >= 1.5.0', # py3 compat 'plaster >= 0.5', # file schemes ] tests_require = [ 'pytest', 'pytest-cov', ] setup( name='plaster_pastedeploy', version='0.5', description=( 'A loader implementing the PasteDeploy syntax to be used by plaster.' ), long_description=readme + '\n\n' + changes, author='Hunter Senft-Grupp', author_email='pylons-discuss@googlegroups.com', url='https://github.com/Pylons/plaster_pastedeploy', packages=find_packages('src', exclude=['tests']), package_dir={'': 'src'}, include_package_data=True, python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*', install_requires=install_requires, extras_require={ 'testing': tests_require, }, zip_safe=False, keywords='plaster pastedeploy plaster_pastedeploy ini config egg', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Natural Language :: English', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', ], entry_points={ 'plaster.loader_factory': [ 'file+ini=plaster_pastedeploy:Loader', 'egg=plaster_pastedeploy:Loader', 'pastedeploy=plaster_pastedeploy:Loader', 'pastedeploy+ini=plaster_pastedeploy:Loader', 'pastedeploy+egg=plaster_pastedeploy:Loader', ], 'plaster.wsgi_loader_factory': [ 'file+ini=plaster_pastedeploy:Loader', 'egg=plaster_pastedeploy:Loader', 'pastedeploy=plaster_pastedeploy:Loader', 'pastedeploy+ini=plaster_pastedeploy:Loader', 'pastedeploy+egg=plaster_pastedeploy:Loader', ], }, ) plaster_pastedeploy-0.5/.gitignore0000644€Déíè€bP^q0000000156612726030555023235 0ustar michaelDA\Domain Users00000000000000# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python env/ env27/ build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ *.egg-info/ .installed.cfg *.egg # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage* .cache nosetests.xml coverage.xml *,cover .hypothesis/ cover/ # Translations *.mo *.pot # Django stuff: *.log # Sphinx documentation docs/_build/ # PyBuilder target/ .idea/ .tox # Include !tests/fake_packages/FakeApp.egg/ tests/fake_packages/FakeApp.egg/EGG-INFO !tests/fake_packages/FakeApp.egg/FakeApp.egg-infoplaster_pastedeploy-0.5/tox.ini0000644€Déíè€bP^q0000000147413257213544022557 0ustar michaelDA\Domain Users00000000000000[tox] envlist = lint, py27,py34,py35,py36,pypy, coverage [testenv] basepython = py27: python2.7 py34: python3.4 py35: python3.5 py36: python3.6 pypy: pypy py2: python2.7 py3: python3.5 pypy3: pypy3 commands = pip install plaster_pastedeploy[testing] py.test --cov --cov-report= {posargs:} setenv = COVERAGE_FILE=.coverage.{envname} deps = py27: configparser [testenv:coverage] skip_install = True basepython = python3.5 commands = coverage combine coverage report --fail-under=100 deps = coverage setenv = COVERAGE_FILE=.coverage [testenv:lint] skip_install = True basepython = python3.5 commands = flake8 src/plaster_pastedeploy/ python setup.py check -r -s -m check-manifest deps = flake8 readme_renderer check-manifest plaster_pastedeploy-0.5/setup.cfg0000644€Déíè€bP^q0000000067513257216533023070 0ustar michaelDA\Domain Users00000000000000[wheel] universal = 1 [metadata] license_file = LICENSE.txt [flake8] exclude = tests/fake_packages, tests/sample_configs, show-source = True max-line-length = 80 [check-manifest] ignore = .gitignore PKG-INFO *.egg-info *.egg-info/* ignore-default-rules = true ignore-bad-ideas = tests/* [tool:pytest] python_files = test_*.py testpaths = src/plaster_pastedeploy tests [egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 plaster_pastedeploy-0.5/README.rst0000644€Déíè€bP^q0000000431513257216311022723 0ustar michaelDA\Domain Users00000000000000=================== plaster_pastedeploy =================== .. image:: https://img.shields.io/pypi/v/plaster_pastedeploy.svg :target: https://pypi.python.org/pypi/plaster_pastedeploy .. image:: https://img.shields.io/travis/Pylons/plaster_pastedeploy/master.svg :target: https://travis-ci.org/Pylons/plaster_pastedeploy ``plaster_pastedeploy`` is a plaster_ plugin that provides a ``plaster.Loader`` that can parse ini files according to the standard set by PasteDeploy_. It supports the ``wsgi`` plaster protocol, implementing the ``plaster.protocols.IWSGIProtocol`` interface. Usage ===== Applications should use ``plaster_pastedeploy`` to load settings from named sections in a configuration source (usually a file). - Please look at the documentation for plaster_ on how to integrate this loader into your application. - Please look at the documentation for PasteDeploy_ on the specifics of the supported INI file format. Most applications will want to use ``plaster.get_loader(uri, protocols=['wsgi'])`` to get this loader. It then exposes ``get_wsgi_app``, ``get_wsgi_app_settings``, ``get_wsgi_filter`` and ``get_wsgi_server``. .. code-block:: python import plaster loader = plaster.get_loader('development.ini', protocols=['wsgi']) # to get any section out of the config file settings = loader.get_settings('app:main') # to get settings for a WSGI app app_config = loader.get_wsgi_app_settings() # defaults to main # to get an actual WSGI app app = loader.get_wsgi_app() # defaults to main # to get a filter and compose it with an app filter = loader.get_wsgi_filter('filt') app = filter(app) # to get a WSGI server server = loader.get_wsgi_server() # defaults to main # to start the WSGI server server(app) Any ``plaster.PlasterURL`` options are forwarded as defaults to the loader. Some examples are below: - ``development.ini#myapp`` - ``development.ini?http_port=8080#main`` - ``pastedeploy+ini:///path/to/development.ini`` - ``pastedeploy+ini://development.ini#foo`` - ``egg:MyApp?debug=false#foo`` .. _PasteDeploy: https://pastedeploy.readthedocs.io/en/latest/ .. _plaster: https://docs.pylonsproject.org/projects/plaster/en/latest/ plaster_pastedeploy-0.5/LICENSE.txt0000644€Déíè€bP^q0000000204413257213544023061 0ustar michaelDA\Domain Users00000000000000Copyright (c) 2017 Michael Merickel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. plaster_pastedeploy-0.5/CONTRIBUTORS.txt0000644€Déíè€bP^q0000001157713257213544023747 0ustar michaelDA\Domain Users00000000000000Pylons Project Contributor Agreement ==================================== The submitter agrees by adding his or her name within the section below named "Contributors" and submitting the resulting modified document to the canonical shared repository location for this software project (whether directly, as a user with "direct commit access", or via a "pull request"), he or she is signing a contract electronically. The submitter becomes a Contributor after a) he or she signs this document by adding their name beneath the "Contributors" section below, and b) the resulting document is accepted into the canonical version control repository. Treatment of Account -------------------- Contributor will not allow anyone other than the Contributor to use his or her username or source repository login to submit code to a Pylons Project source repository. Should Contributor become aware of any such use, Contributor will immediately notify Agendaless Consulting. Notification must be performed by sending an email to webmaster@agendaless.com. Until such notice is received, Contributor will be presumed to have taken all actions made through Contributor's account. If the Contributor has direct commit access, Agendaless Consulting will have complete control and discretion over capabilities assigned to Contributor's account, and may disable Contributor's account for any reason at any time. Legal Effect of Contribution ---------------------------- Upon submitting a change or new work to a Pylons Project source Repository (a "Contribution"), you agree to assign, and hereby do assign, a one-half interest of all right, title and interest in and to copyright and other intellectual property rights with respect to your new and original portions of the Contribution to Agendaless Consulting. You and Agendaless Consulting each agree that the other shall be free to exercise any and all exclusive rights in and to the Contribution, without accounting to one another, including without limitation, the right to license the Contribution to others under the MIT License. This agreement shall run with title to the Contribution. Agendaless Consulting does not convey to you any right, title or interest in or to the Program or such portions of the Contribution that were taken from the Program. Your transmission of a submission to the Pylons Project source Repository and marks of identification concerning the Contribution itself constitute your intent to contribute and your assignment of the work in accordance with the provisions of this Agreement. License Terms ------------- Code committed to the Pylons Project source repository (Committed Code) must be governed by the MIT License or another license acceptable to Agendaless Consulting. Until Agendaless Consulting declares in writing an acceptable license other than the MIT License, only the MIT License shall be used. A list of exceptions is detailed within the "Licensing Exceptions" section of this document, if one exists. Representations, Warranty, and Indemnification ---------------------------------------------- Contributor represents and warrants that the Committed Code does not violate the rights of any person or entity, and that the Contributor has legal authority to enter into this Agreement and legal authority over Contributed Code. Further, Contributor indemnifies Agendaless Consulting against violations. Cryptography ------------ Contributor understands that cryptographic code may be subject to government regulations with which Agendaless Consulting and/or entities using Committed Code must comply. Any code which contains any of the items listed below must not be checked-in until Agendaless Consulting staff has been notified and has approved such contribution in writing. - Cryptographic capabilities or features - Calls to cryptographic features - User interface elements which provide context relating to cryptography - Code which may, under casual inspection, appear to be cryptographic. Notices ------- Contributor confirms that any notices required will be included in any Committed Code. Licensing Exceptions ==================== Code committed within the ``docs/`` subdirectory of the plaster_pastedeploy source control repository and "docstrings" which appear in the documentation generated by running "make" within this directory are licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License (http://creativecommons.org/licenses/by-nc-sa/3.0/us/). List of Contributors ==================== The below-signed are contributors to a code repository that is part of the project named "plaster_pastedeploy". Each below-signed contributor has read, understand and agrees to the terms above in the section within this document entitled "Pylons Project Contributor Agreement" as of the date beside his or her name. Contributors ------------ - Michael Merickel (2016-06-12) - Steve Piercy (2017-08-31) - Geoffrey T. Dairiki (2017-11-16) plaster_pastedeploy-0.5/CHANGES.rst0000644€Déíè€bP^q0000000712213257216325023042 0ustar michaelDA\Domain Users000000000000000.5 (2018-03-29) ================ - Removed environment variable support entirely for now. The feature requires bugfixes upstream in PasteDeploy which have not been done yet and this was breaking people's environments so it is gone for now. See https://github.com/Pylons/plaster_pastedeploy/pull/15 0.4.2 (2017-11-20) ================== - Fix ``ConfigDict.copy`` so that it works. See https://github.com/Pylons/plaster_pastedeploy/pull/14 0.4.1 (2017-07-10) ================== - Disable environment variable support on Python 2. PasteDeploy does not support escaping the contents on Python 2 which means any variable with a value of the format %(foo)s would break the parser. Because this is implicit behavior it was deemed too error prone to support. See https://github.com/Pylons/plaster_pastedeploy/pull/10 - Escape environment variables such that their contents are not subject to interpolation. See https://github.com/Pylons/plaster_pastedeploy/pull/10 - Invoke ``logging.basicConfig`` when ``setup_logging`` is called and the config file doesn't contain any logging setup or the URI is using the ``egg:`` protocol. See https://github.com/Pylons/plaster_pastedeploy/pull/11 0.4 (2017-07-09) ================ - Fix ``get_settings`` for an arbitrary section to follow the same rules as PasteDeploy with regards to the handling of defaults. The goal of this package is to be compliant with PasteDeploy's format for all sections in the file such that there are no surprising format changes in various sections. Supported added for ``set default_foo = bar`` and ``get foo = default_foo`` syntax to override a default value and to pull a default value into the settings, respectively. In the above example the value ``foo = bar`` would be returned. Any other defaults not pulled into the section via either interpolation or the ``get`` syntax will be ignored. See https://github.com/Pylons/plaster_pastedeploy/pull/6 - Inject environment variables into the defaults automatically. These will be available for interpolation as ``ENV_``. For example if environment variable ``APP_DEBUG=true`` then ``%(ENV_APP_DEBUG)s`` will work within the ini file. See https://github.com/Pylons/plaster_pastedeploy/pull/7 - ``get_settings`` and ``get_wsgi_app_settings`` both return only the local config now. However, the returned object has a ``global_conf`` attribute containing the defaults as well as a ``loader`` attribute pointing at the loader instance. See https://github.com/Pylons/plaster_pastedeploy/pull/8 0.3.2 (2017-07-01) ================== - Resolve an issue in which ``NoSectionError`` would not be properly caught on Python 2.7 if the ``configparser`` module was installed from PyPI. See https://github.com/Pylons/plaster_pastedeploy/issues/5 0.3.1 (2017-06-02) ================== - Recognize the ``pastedeploy+egg`` scheme as an ``egg`` type. 0.3 (2017-06-02) ================ - Drop the ``ini`` scheme and replace with ``file+ini`` and ``pastedeploy``. Also rename ``ini+pastedeploy`` and ``egg+pastedeploy`` to ``pastedeploy+ini`` and ``pastedeploy+egg`` respectively. See https://github.com/Pylons/plaster_pastedeploy/pull/4 0.2.1 (2017-03-29) ================== - Fix a bug in 0.2 in which an exception was raised for an invalid section if the a non-config-file-based protocol was used. 0.2 (2017-03-29) ================ - No longer raise ``plaster.NoSectionError`` exceptions. Empty dictionaries are returned for missing sections and a user should check ``get_sections`` for the list of valid sections. 0.1 (2017-03-27) ================ - Initial release. plaster_pastedeploy-0.5/.travis.yml0000644€Déíè€bP^q0000000070313257213544023347 0ustar michaelDA\Domain Users00000000000000sudo: false cache: directories: - $HOME/.cache/pip language: python matrix: include: - python: '3.6' env: TOXENV=py36 - python: '3.5' env: TOXENV=py35 - python: '3.4' env: TOXENV=py34 - python: '2.7' env: TOXENV=py27 - python: 'pypy' env: TOXENV=pypy - python: '3.5' env: TOXENV=py27,py35,coverage - python: '3.5' env: TOXENV=lint install: pip install tox script: tox plaster_pastedeploy-0.5/src/0000755€Déíè€bP^q0000000000013257216533022026 5ustar michaelDA\Domain Users00000000000000plaster_pastedeploy-0.5/src/plaster_pastedeploy.egg-info/0000755€Déíè€bP^q0000000000013257216533027603 5ustar michaelDA\Domain Users00000000000000plaster_pastedeploy-0.5/src/plaster_pastedeploy.egg-info/PKG-INFO0000644€Déíè€bP^q0000002021213257216533030675 0ustar michaelDA\Domain Users00000000000000Metadata-Version: 1.2 Name: plaster-pastedeploy Version: 0.5 Summary: A loader implementing the PasteDeploy syntax to be used by plaster. Home-page: https://github.com/Pylons/plaster_pastedeploy Author: Hunter Senft-Grupp Author-email: pylons-discuss@googlegroups.com License: UNKNOWN Description: =================== plaster_pastedeploy =================== .. image:: https://img.shields.io/pypi/v/plaster_pastedeploy.svg :target: https://pypi.python.org/pypi/plaster_pastedeploy .. image:: https://img.shields.io/travis/Pylons/plaster_pastedeploy/master.svg :target: https://travis-ci.org/Pylons/plaster_pastedeploy ``plaster_pastedeploy`` is a plaster_ plugin that provides a ``plaster.Loader`` that can parse ini files according to the standard set by PasteDeploy_. It supports the ``wsgi`` plaster protocol, implementing the ``plaster.protocols.IWSGIProtocol`` interface. Usage ===== Applications should use ``plaster_pastedeploy`` to load settings from named sections in a configuration source (usually a file). - Please look at the documentation for plaster_ on how to integrate this loader into your application. - Please look at the documentation for PasteDeploy_ on the specifics of the supported INI file format. Most applications will want to use ``plaster.get_loader(uri, protocols=['wsgi'])`` to get this loader. It then exposes ``get_wsgi_app``, ``get_wsgi_app_settings``, ``get_wsgi_filter`` and ``get_wsgi_server``. .. code-block:: python import plaster loader = plaster.get_loader('development.ini', protocols=['wsgi']) # to get any section out of the config file settings = loader.get_settings('app:main') # to get settings for a WSGI app app_config = loader.get_wsgi_app_settings() # defaults to main # to get an actual WSGI app app = loader.get_wsgi_app() # defaults to main # to get a filter and compose it with an app filter = loader.get_wsgi_filter('filt') app = filter(app) # to get a WSGI server server = loader.get_wsgi_server() # defaults to main # to start the WSGI server server(app) Any ``plaster.PlasterURL`` options are forwarded as defaults to the loader. Some examples are below: - ``development.ini#myapp`` - ``development.ini?http_port=8080#main`` - ``pastedeploy+ini:///path/to/development.ini`` - ``pastedeploy+ini://development.ini#foo`` - ``egg:MyApp?debug=false#foo`` .. _PasteDeploy: https://pastedeploy.readthedocs.io/en/latest/ .. _plaster: https://docs.pylonsproject.org/projects/plaster/en/latest/ 0.5 (2018-03-29) ================ - Removed environment variable support entirely for now. The feature requires bugfixes upstream in PasteDeploy which have not been done yet and this was breaking people's environments so it is gone for now. See https://github.com/Pylons/plaster_pastedeploy/pull/15 0.4.2 (2017-11-20) ================== - Fix ``ConfigDict.copy`` so that it works. See https://github.com/Pylons/plaster_pastedeploy/pull/14 0.4.1 (2017-07-10) ================== - Disable environment variable support on Python 2. PasteDeploy does not support escaping the contents on Python 2 which means any variable with a value of the format %(foo)s would break the parser. Because this is implicit behavior it was deemed too error prone to support. See https://github.com/Pylons/plaster_pastedeploy/pull/10 - Escape environment variables such that their contents are not subject to interpolation. See https://github.com/Pylons/plaster_pastedeploy/pull/10 - Invoke ``logging.basicConfig`` when ``setup_logging`` is called and the config file doesn't contain any logging setup or the URI is using the ``egg:`` protocol. See https://github.com/Pylons/plaster_pastedeploy/pull/11 0.4 (2017-07-09) ================ - Fix ``get_settings`` for an arbitrary section to follow the same rules as PasteDeploy with regards to the handling of defaults. The goal of this package is to be compliant with PasteDeploy's format for all sections in the file such that there are no surprising format changes in various sections. Supported added for ``set default_foo = bar`` and ``get foo = default_foo`` syntax to override a default value and to pull a default value into the settings, respectively. In the above example the value ``foo = bar`` would be returned. Any other defaults not pulled into the section via either interpolation or the ``get`` syntax will be ignored. See https://github.com/Pylons/plaster_pastedeploy/pull/6 - Inject environment variables into the defaults automatically. These will be available for interpolation as ``ENV_``. For example if environment variable ``APP_DEBUG=true`` then ``%(ENV_APP_DEBUG)s`` will work within the ini file. See https://github.com/Pylons/plaster_pastedeploy/pull/7 - ``get_settings`` and ``get_wsgi_app_settings`` both return only the local config now. However, the returned object has a ``global_conf`` attribute containing the defaults as well as a ``loader`` attribute pointing at the loader instance. See https://github.com/Pylons/plaster_pastedeploy/pull/8 0.3.2 (2017-07-01) ================== - Resolve an issue in which ``NoSectionError`` would not be properly caught on Python 2.7 if the ``configparser`` module was installed from PyPI. See https://github.com/Pylons/plaster_pastedeploy/issues/5 0.3.1 (2017-06-02) ================== - Recognize the ``pastedeploy+egg`` scheme as an ``egg`` type. 0.3 (2017-06-02) ================ - Drop the ``ini`` scheme and replace with ``file+ini`` and ``pastedeploy``. Also rename ``ini+pastedeploy`` and ``egg+pastedeploy`` to ``pastedeploy+ini`` and ``pastedeploy+egg`` respectively. See https://github.com/Pylons/plaster_pastedeploy/pull/4 0.2.1 (2017-03-29) ================== - Fix a bug in 0.2 in which an exception was raised for an invalid section if the a non-config-file-based protocol was used. 0.2 (2017-03-29) ================ - No longer raise ``plaster.NoSectionError`` exceptions. Empty dictionaries are returned for missing sections and a user should check ``get_sections`` for the list of valid sections. 0.1 (2017-03-27) ================ - Initial release. Keywords: plaster pastedeploy plaster_pastedeploy ini config egg Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.* plaster_pastedeploy-0.5/src/plaster_pastedeploy.egg-info/not-zip-safe0000644€Déíè€bP^q0000000000113066233702032024 0ustar michaelDA\Domain Users00000000000000 plaster_pastedeploy-0.5/src/plaster_pastedeploy.egg-info/SOURCES.txt0000644€Déíè€bP^q0000000272613257216533031476 0ustar michaelDA\Domain Users00000000000000.coveragerc .gitignore .travis.yml CHANGES.rst CONTRIBUTING.rst CONTRIBUTORS.txt LICENSE.txt MANIFEST.in README.rst appveyor.yml setup.cfg setup.py tox.ini src/plaster_pastedeploy/__init__.py src/plaster_pastedeploy.egg-info/PKG-INFO src/plaster_pastedeploy.egg-info/SOURCES.txt src/plaster_pastedeploy.egg-info/dependency_links.txt src/plaster_pastedeploy.egg-info/entry_points.txt src/plaster_pastedeploy.egg-info/not-zip-safe src/plaster_pastedeploy.egg-info/requires.txt src/plaster_pastedeploy.egg-info/top_level.txt tests/__init__.py tests/conftest.py tests/test_configdict.py tests/test_get_settings.py tests/test_get_wsgi_app.py tests/test_get_wsgi_app_settings.py tests/test_get_wsgi_filter.py tests/test_get_wsgi_server.py tests/test_loader.py tests/test_setup_logging.py tests/fake_packages/FakeApp/setup.py tests/fake_packages/FakeApp/FakeApp.egg-info/PKG-INFO tests/fake_packages/FakeApp/FakeApp.egg-info/SOURCES.txt tests/fake_packages/FakeApp/FakeApp.egg-info/dependency_links.txt tests/fake_packages/FakeApp/FakeApp.egg-info/entry_points.txt tests/fake_packages/FakeApp/FakeApp.egg-info/top_level.txt tests/fake_packages/FakeApp/fakeapp/__init__.py tests/fake_packages/FakeApp/fakeapp/apps.py tests/fake_packages/FakeApp/fakeapp/configapps.py tests/sample_configs/basic_app.ini tests/sample_configs/test_config.ini tests/sample_configs/test_config_included.ini tests/sample_configs/test_filter.ini tests/sample_configs/test_filter_with.ini tests/sample_configs/test_settings.iniplaster_pastedeploy-0.5/src/plaster_pastedeploy.egg-info/entry_points.txt0000644€Déíè€bP^q0000000071513257216533033104 0ustar michaelDA\Domain Users00000000000000[plaster.loader_factory] egg = plaster_pastedeploy:Loader file+ini = plaster_pastedeploy:Loader pastedeploy = plaster_pastedeploy:Loader pastedeploy+egg = plaster_pastedeploy:Loader pastedeploy+ini = plaster_pastedeploy:Loader [plaster.wsgi_loader_factory] egg = plaster_pastedeploy:Loader file+ini = plaster_pastedeploy:Loader pastedeploy = plaster_pastedeploy:Loader pastedeploy+egg = plaster_pastedeploy:Loader pastedeploy+ini = plaster_pastedeploy:Loader plaster_pastedeploy-0.5/src/plaster_pastedeploy.egg-info/requires.txt0000644€Déíè€bP^q0000000010113257216533032173 0ustar michaelDA\Domain Users00000000000000PasteDeploy >= 1.5.0 plaster >= 0.5 [testing] pytest pytest-cov plaster_pastedeploy-0.5/src/plaster_pastedeploy.egg-info/top_level.txt0000644€Déíè€bP^q0000000002413257216533032331 0ustar michaelDA\Domain Users00000000000000plaster_pastedeploy plaster_pastedeploy-0.5/src/plaster_pastedeploy.egg-info/dependency_links.txt0000644€Déíè€bP^q0000000000113257216533033651 0ustar michaelDA\Domain Users00000000000000 plaster_pastedeploy-0.5/src/plaster_pastedeploy/0000755€Déíè€bP^q0000000000013257216533026111 5ustar michaelDA\Domain Users00000000000000plaster_pastedeploy-0.5/src/plaster_pastedeploy/__init__.py0000644€Déíè€bP^q0000002377413257213631030233 0ustar michaelDA\Domain Users00000000000000from collections import OrderedDict import logging from logging.config import fileConfig import os import sys from paste.deploy import ( loadapp, loadserver, loadfilter, appconfig, ) import paste.deploy.loadwsgi as loadwsgi from plaster import ILoader from plaster.protocols import IWSGIProtocol PY2 = sys.version_info[0] == 2 if PY2: # We need to import the **same** configparser module that PasteDeploy # is using so that we can catch the NoSectionError raised by it. # # Import the py2 version first to avoid name clash with the configparser # module on PyPI. See https://github.com/Pylons/plaster_pastedeploy/issues/5 from ConfigParser import NoSectionError else: from configparser import NoSectionError class Loader(IWSGIProtocol, ILoader): """ This is a loader conforming to the required interface defined by :class:`plaster.ILoader`. Given a :class:`plaster.PlasterURL` to a configuration source, this can load and return WSGI applications, servers, filters and settings from .ini files written against the PasteDeploy spec. :ivar uri: A :class:`plaster.PlasterURL` instance. """ filepath = None def __init__(self, uri): self.uri = uri scheme = get_pastedeploy_scheme(uri) if scheme == 'config': self.filepath = os.path.abspath(uri.path) self.pastedeploy_spec = '{0}:{1}'.format(scheme, uri.path) self.relative_to = os.getcwd() def get_sections(self): """ Find all of the sections in the config file. :return: A list of the section names in the config file. """ if self.filepath is None: return [] parser = self._get_parser() return parser.sections() def get_settings(self, section=None, defaults=None): """ Gets a named section from the configuration source. :param section: a :class:`str` representing the section you want to retrieve from the configuration source. If ``None`` this will fallback to the :attr:`plaster.PlasterURL.fragment`. :param defaults: a :class:`dict` that will get passed to :class:`configparser.ConfigParser` and will populate the ``DEFAULT`` section. :return: A :class:`plaster_pastedeploy.ConfigDict` of key/value pairs. """ # This is a partial reimplementation of # ``paste.deploy.loadwsgi.ConfigLoader:get_context`` which supports # "set" and "get" options and filters out any other globals section = self._maybe_get_default_name(section) if self.filepath is None: return {} parser = self._get_parser(defaults) defaults = parser.defaults() try: raw_items = parser.items(section) except NoSectionError: return {} local_conf = OrderedDict() get_from_globals = {} for option, value in raw_items: if option.startswith('set '): name = option[4:].strip() defaults[name] = value elif option.startswith('get '): name = option[4:].strip() get_from_globals[name] = value # insert a value into local_conf to preserve the order local_conf[name] = None else: # annoyingly pastedeploy filters out all defaults unless # "get foo" is used to pull it in if option in defaults: continue local_conf[option] = value for option, global_option in get_from_globals.items(): local_conf[option] = defaults[global_option] return ConfigDict(local_conf, defaults, self) def get_wsgi_app(self, name=None, defaults=None): """ Reads the configuration source and finds and loads a WSGI application defined by the entry with name ``name`` per the PasteDeploy configuration format and loading mechanism. :param name: The named WSGI app to find, load and return. Defaults to ``None`` which becomes ``main`` inside :func:`paste.deploy.loadapp`. :param defaults: The ``global_conf`` that will be used during app instantiation. :return: A WSGI application. """ name = self._maybe_get_default_name(name) defaults = self._get_defaults(defaults) return loadapp(self.pastedeploy_spec, name=name, relative_to=self.relative_to, global_conf=defaults) def get_wsgi_server(self, name=None, defaults=None): """ Reads the configuration source and finds and loads a WSGI server defined by the server entry with the name ``name`` per the PasteDeploy configuration format and loading mechanism. :param name: The named WSGI server to find, load and return. Defaults to ``None`` which becomes ``main`` inside :func:`paste.deploy.loadserver`. :param defaults: The ``global_conf`` that will be used during server instantiation. :return: A WSGI server runner callable which accepts a WSGI app. """ name = self._maybe_get_default_name(name) defaults = self._get_defaults(defaults) return loadserver(self.pastedeploy_spec, name=name, relative_to=self.relative_to, global_conf=defaults) def get_wsgi_filter(self, name=None, defaults=None): """Reads the configuration soruce and finds and loads a WSGI filter defined by the filter entry with the name ``name`` per the PasteDeploy configuration format and loading mechanism. :param name: The named WSGI filter to find, load and return. Defaults to ``None`` which becomes ``main`` inside :func:`paste.deploy.loadfilter`. :param defaults: The ``global_conf`` that will be used during filter instantiation. :return: A callable that can filter a WSGI application. """ name = self._maybe_get_default_name(name) defaults = self._get_defaults(defaults) return loadfilter(self.pastedeploy_spec, name=name, relative_to=self.relative_to, global_conf=defaults) def get_wsgi_app_settings(self, name=None, defaults=None): """ Return an :class:`collections.OrderedDict` representing the application config for a WSGI application named ``name`` in the PasteDeploy config file specified by ``self.uri``. ``defaults``, if passed, should be a dictionary used as variable assignments like ``{'http_port': 8080}``. This is useful if e.g. ``%(http_port)s`` is used in the config file. If the ``name`` is None, this will attempt to parse the name from the ``config_uri`` string expecting the format ``inifile#name``. If no name is found, the name will default to "main". :param name: The named WSGI app for which to find the settings. Defaults to ``None`` which becomes ``main`` inside :func:`paste.deploy.loadapp`. :param defaults: The ``global_conf`` that will be used during settings generation. :return: A :class:`plaster_pastedeploy.ConfigDict` of key/value pairs. """ name = self._maybe_get_default_name(name) defaults = self._get_defaults(defaults) conf = appconfig( self.pastedeploy_spec, name=name, relative_to=self.relative_to, global_conf=defaults) return ConfigDict(conf.local_conf, conf.global_conf, self) def setup_logging(self, defaults=None): """ Set up logging via :func:`logging.config.fileConfig`. Defaults are specified for the special ``__file__`` and ``here`` variables, similar to PasteDeploy config loading. Extra defaults can optionally be specified as a dict in ``defaults``. :param defaults: The defaults that will be used when passed to :func:`logging.config.fileConfig`. :return: ``None``. """ if 'loggers' in self.get_sections(): defaults = self._get_defaults(defaults) fileConfig(self.uri.path, defaults) else: logging.basicConfig() def _get_defaults(self, defaults=None): result = {'__file__': self.filepath} if self.filepath is None: result['here'] = os.getcwd() else: result['here'] = os.path.dirname(self.filepath) result.update(self.uri.options) if defaults: result.update(defaults) return result def _get_parser(self, defaults=None): defaults = self._get_defaults(defaults) loader = loadwsgi.ConfigLoader(self.uri.path) loader.update_defaults(defaults) return loader.parser def _maybe_get_default_name(self, name): """Checks a name and determines whether to use the default name. :param name: The current name to check. :return: Either None or a :class:`str` representing the name. """ if name is None and self.uri.fragment: name = self.uri.fragment return name def __repr__(self): return 'plaster_pastedeploy.Loader(uri="{0}")'.format(self.uri) def get_pastedeploy_scheme(uri): scheme = 'config' if uri.scheme.endswith('egg'): scheme = 'egg' # elif uri.scheme.startswith('call'): # scheme = 'call' return scheme class ConfigDict(OrderedDict, loadwsgi.AttrDict): def __init__(self, local_conf, global_conf, loader): super(ConfigDict, self).__init__(local_conf) self.global_conf = global_conf self.loader = loader def __reduce__(self): initargs = list(self.items()), self.global_conf, self.loader return self.__class__, initargs def copy(self): callable, args = self.__reduce__() return callable(*args)