├── .gitattributes ├── docs ├── swissparAPY_diagram.pdf └── swissparAPY_diagram.png ├── examples ├── glimpse.py ├── filter.py ├── list_all_tables_and_properties.py ├── filter_query.py ├── slice.py ├── filter_advanced.py ├── pagination.py ├── download_votes_in_batches.py └── Swiss Parliament API.ipynb ├── .gitignore ├── dev_setup.sh ├── .pre-commit-config.yaml ├── setup.cfg ├── validate.sh ├── swissparlpy ├── errors.py ├── __init__.py └── client.py ├── tests ├── swissparlpy_test.py ├── conftest.py ├── client_test.py └── fixtures │ └── business_2.json ├── .github └── workflows │ ├── publish_python.yml │ └── build.yml ├── pyproject.toml ├── LICENSE.md ├── CONTRIBUTING.md ├── CHANGELOG.md └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /docs/swissparAPY_diagram.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metaodi/swissparlpy/HEAD/docs/swissparAPY_diagram.pdf -------------------------------------------------------------------------------- /docs/swissparAPY_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metaodi/swissparlpy/HEAD/docs/swissparAPY_diagram.png -------------------------------------------------------------------------------- /examples/glimpse.py: -------------------------------------------------------------------------------- 1 | import swissparlpy 2 | 3 | glimpse = swissparlpy.get_glimpse("Canton", 10) 4 | for r in glimpse: 5 | print(r) 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | swissparlpy.egg-info 2 | *.pyc 3 | *.swp 4 | .coverage 5 | pyenv 6 | .env 7 | dist/ 8 | examples/voting50/ 9 | examples/.ipynb_checkpoints/ 10 | -------------------------------------------------------------------------------- /dev_setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | [ ! -d pyenv ] && python -m venv pyenv 4 | source pyenv/bin/activate 5 | 6 | pip install --upgrade pip 7 | pip install flit 8 | pre-commit install 9 | flit install -s 10 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/psf/black 3 | rev: 23.7.0 4 | hooks: 5 | - id: black 6 | language_version: python3.8 7 | - repo: https://github.com/pycqa/flake8 8 | rev: 6.0.0 9 | hooks: 10 | - id: flake8 11 | -------------------------------------------------------------------------------- /examples/filter.py: -------------------------------------------------------------------------------- 1 | import swissparlpy as spp 2 | from pprint import pprint 3 | 4 | subjects = spp.get_data( 5 | table="SubjectBusiness", BusinessShortNumber="05.057", Language="DE" 6 | ) 7 | 8 | print(f"Total rows: {len(subjects)}") 9 | for subject in subjects: 10 | pprint(subject) 11 | -------------------------------------------------------------------------------- /examples/list_all_tables_and_properties.py: -------------------------------------------------------------------------------- 1 | import swissparlpy 2 | 3 | # print all tables with their properties 4 | 5 | overview = swissparlpy.get_overview() 6 | for table, props in overview.items(): 7 | print(table) 8 | for prop in props: 9 | print(f" + {prop}") 10 | print("") 11 | -------------------------------------------------------------------------------- /examples/filter_query.py: -------------------------------------------------------------------------------- 1 | import swissparlpy as spp 2 | import pandas as pd 3 | 4 | persons = spp.get_data( 5 | table="Person", 6 | filter="(FirstName eq 'Stefan' or LastName eq 'Seiler') and Language eq 'DE'", 7 | ) 8 | 9 | df = pd.DataFrame(persons) 10 | print(df[["FirstName", "LastName"]]) 11 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-complexity = 10 3 | exclude = .git,__pycache__,pyenv,.pytest_cache 4 | # set to true to check all ignored errors 5 | disable_noqa = False 6 | 7 | # adaptions for black 8 | max-line-length = 88 9 | extend-ignore = E203 10 | 11 | [tool:pytest] 12 | addopts = --cov=swissparlpy 13 | -------------------------------------------------------------------------------- /examples/slice.py: -------------------------------------------------------------------------------- 1 | import swissparlpy as spp 2 | from pprint import pprint 3 | 4 | sessions = spp.get_data(table="Session") 5 | 6 | print(f"Total rows: {len(sessions)}") 7 | for session in sessions[5:10]: 8 | pprint(session) 9 | 10 | 11 | # print any element 12 | print("") 13 | pprint(sessions[587]) 14 | -------------------------------------------------------------------------------- /examples/filter_advanced.py: -------------------------------------------------------------------------------- 1 | import swissparlpy as spp 2 | import pandas as pd 3 | 4 | 5 | def name_filter(e): 6 | return spp.filter.or_(e.FirstName == "Stefan", e.LastName == "Seiler") 7 | 8 | 9 | persons = spp.get_data("Person", filter=name_filter, Language="DE") 10 | 11 | df = pd.DataFrame(persons) 12 | print(df[["FirstName", "LastName"]]) 13 | -------------------------------------------------------------------------------- /validate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | function cleanup { 6 | exit $? 7 | } 8 | 9 | trap "cleanup" EXIT 10 | 11 | # Check black code style 12 | python -m black --check --diff swissparlpy examples tests 13 | 14 | # Check PEP-8 code style and McCabe complexity 15 | python -m flake8 --count --show-source --statistics . 16 | 17 | # run tests with test coverage 18 | python -m pytest tests/ 19 | -------------------------------------------------------------------------------- /examples/pagination.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import swissparlpy 3 | from pprint import pprint 4 | 5 | 6 | # setup logger to see debug messages from swissparlpy 7 | spp_logger = logging.getLogger("swissparlpy.client") 8 | spp_logger.setLevel(logging.DEBUG) 9 | 10 | logging.basicConfig( 11 | format="%(asctime)s %(levelname)-10s %(name)s: %(message)s", 12 | datefmt="%Y-%m-%d %H:%M:%S", 13 | ) 14 | logging.captureWarnings(True) 15 | 16 | 17 | business = swissparlpy.get_data("Business", Language="DE") 18 | print(f"Count: {business.count})") 19 | print(f"Internal data: {len(business.data)}") 20 | 21 | pprint(business) 22 | pprint(business[1]) 23 | pprint(business[1001]) 24 | -------------------------------------------------------------------------------- /swissparlpy/errors.py: -------------------------------------------------------------------------------- 1 | class SwissParlError(Exception): 2 | """ 3 | General SwissParl error class to provide a superclass for all other errors 4 | """ 5 | 6 | 7 | class NoMoreRecordsError(SwissParlError): 8 | """ 9 | Error to indicate, that there are no more records in the result. 10 | """ 11 | 12 | 13 | class SwissParlWarning(Warning): 14 | """ 15 | General SwissParl warning class to provide a superclass for all warnings 16 | """ 17 | 18 | 19 | class ResultVeryLargeWarning(SwissParlWarning): 20 | """ 21 | A warning to indicate, that a result is very large. 22 | The query should be split up to reduce memory usage. 23 | """ 24 | -------------------------------------------------------------------------------- /tests/swissparlpy_test.py: -------------------------------------------------------------------------------- 1 | import mock 2 | import os 3 | from conftest import fixture_content 4 | 5 | __location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__))) 6 | 7 | 8 | class SwissParlTestCase: 9 | def setUp(self): 10 | self.session_mock = mock.MagicMock() 11 | self._setup_session_mock(self.session_mock) 12 | 13 | def _setup_session_mock(self, session_mock, filename=None): 14 | if not filename: 15 | filename = self._testMethodName + ".json" 16 | 17 | content = fixture_content(filename) 18 | session_mock.return_value.get.return_value = mock.MagicMock( 19 | content=content 20 | ) # noqa 21 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import os 3 | 4 | __location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__))) 5 | 6 | 7 | def fixture_content(filename): 8 | path = os.path.join(__location__, "fixtures", filename) 9 | if not os.path.exists(path): 10 | return "" 11 | with open(path) as f: 12 | return f.read() 13 | 14 | 15 | @pytest.fixture 16 | def metadata(): 17 | """OData metadata fixture""" 18 | return fixture_content("metadata.xml") 19 | 20 | 21 | @pytest.fixture 22 | def business_page1(): 23 | """OData business data fixture""" 24 | return fixture_content("business_1.json") 25 | 26 | 27 | @pytest.fixture 28 | def business_page2(): 29 | """OData business data fixture""" 30 | return fixture_content("business_2.json") 31 | -------------------------------------------------------------------------------- /.github/workflows/publish_python.yml: -------------------------------------------------------------------------------- 1 | name: Upload Python Package 2 | 3 | on: 4 | push: 5 | # Sequence of patterns matched against refs/tags 6 | tags: 7 | - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 8 | 9 | jobs: 10 | deploy: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v1 14 | - name: Set up Python 15 | uses: actions/setup-python@v4 16 | with: 17 | python-version: '3.9' 18 | - name: Install dependencies 19 | run: | 20 | python -m pip install --upgrade pip 21 | pip install flit 22 | - name: Build and publish 23 | env: 24 | FLIT_USERNAME: ${{ secrets.PYPI_USERNAME }} 25 | FLIT_PASSWORD: ${{ secrets.PYPI_PASSWORD }} 26 | run: | 27 | python -m flit publish 28 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["flit_core >=3.2,<4"] 3 | build-backend = "flit_core.buildapi" 4 | 5 | [project] 6 | name = "swissparlpy" 7 | authors = [{name = "Stefan Oderbolz", email = "odi@metaodi.ch"}] 8 | readme = "README.md" 9 | requires-python = ">=3.7" 10 | classifiers = ["License :: OSI Approved :: MIT License"] 11 | dynamic = ["version", "description"] 12 | dependencies = [ 13 | "requests", 14 | "pyodata>=1.10.0", 15 | ] 16 | 17 | [project.optional-dependencies] 18 | test = [ 19 | "flake8", 20 | "mock", 21 | "responses", 22 | "pytest", 23 | "pytest-cov", 24 | ] 25 | dev = [ 26 | "flit", 27 | "jupyter", 28 | "pandas", 29 | "black", 30 | "pre-commit", 31 | ] 32 | 33 | 34 | [project.urls] 35 | Home = "https://github.com/metaodi/swissparlpy" 36 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build Python 2 | on: 3 | push: 4 | branches: [main, develop] 5 | pull_request: 6 | branches: [main, develop] 7 | workflow_dispatch: 8 | jobs: 9 | build_python: 10 | runs-on: ubuntu-latest 11 | timeout-minutes: 10 12 | strategy: 13 | matrix: 14 | python-version: ["3.8", "3.9", "3.10", "3.11"] 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | 19 | - name: Set up Python ${{ matrix.python-version }} 20 | uses: actions/setup-python@v4 21 | with: 22 | python-version: ${{ matrix.python-version }} 23 | 24 | - name: Install dependencies 25 | run: | 26 | python -m pip install --upgrade pip 27 | pip install flit 28 | flit install -s 29 | 30 | - run: ./validate.sh 31 | -------------------------------------------------------------------------------- /swissparlpy/__init__.py: -------------------------------------------------------------------------------- 1 | """Client for Swiss parliament API""" 2 | 3 | __version__ = "0.3.0" 4 | __all__ = ["client", "errors"] 5 | 6 | from .errors import SwissParlError # noqa 7 | from .client import SwissParlClient 8 | from pyodata.v2.service import GetEntitySetFilter as filter # noqa 9 | 10 | 11 | def get_tables(): 12 | client = SwissParlClient() 13 | return client.get_tables() 14 | 15 | 16 | def get_variables(table): 17 | client = SwissParlClient() 18 | return client.get_variables(table) 19 | 20 | 21 | def get_overview(): 22 | client = SwissParlClient() 23 | return client.get_overview() 24 | 25 | 26 | def get_glimpse(table, rows=5): 27 | client = SwissParlClient() 28 | return client.get_glimpse(table, rows) 29 | 30 | 31 | def get_data(table, filter=None, **kwargs): # noqa 32 | client = SwissParlClient() 33 | return client.get_data(table, filter, **kwargs) 34 | -------------------------------------------------------------------------------- /examples/download_votes_in_batches.py: -------------------------------------------------------------------------------- 1 | import swissparlpy as spp 2 | import pandas as pd 3 | import os 4 | 5 | 6 | __location__ = os.path.realpath(os.getcwd()) 7 | path = os.path.join(__location__, "voting50") 8 | 9 | 10 | # download votes of one session and save as pickled DataFrame 11 | def save_votes_of_session(id, path): 12 | if not os.path.exists(path): 13 | os.mkdir(path) 14 | data = spp.get_data("Voting", Language="DE", IdSession=id) 15 | print(f"{data.count} rows loaded.") 16 | df = pd.DataFrame(data) 17 | pickle_path = os.path.join(path, f"{id}.pks") 18 | df.to_pickle(pickle_path) 19 | print(f"Saved pickle at {pickle_path}") 20 | 21 | 22 | # get all session of the 50 legislative period 23 | sessions50 = spp.get_data("Session", Language="DE", LegislativePeriodNumber=50) 24 | sessions50.count 25 | 26 | for session in sessions50: 27 | print(f"Loading session {session['ID']}") 28 | save_votes_of_session(session["ID"], path) 29 | 30 | # Combine to one dataframe 31 | df_voting50 = pd.concat( 32 | [pd.read_pickle(os.path.join(path, x)) for x in os.listdir(path)] 33 | ) 34 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Stefan Oderbolz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | If you want to participate in this project, please follow this guidline. 4 | 5 | Fork and clone this repository: 6 | 7 | ```bash 8 | git clone git@github.com:your-username/swissparlpy.git 9 | ``` 10 | 11 | Install the dependencies using `flit`: 12 | 13 | ```bash 14 | pip install flit 15 | flit install -s 16 | ``` 17 | 18 | Make sure the tests pass: 19 | 20 | ```bash 21 | pytest 22 | ``` 23 | 24 | To ensure a good quality of the code use `flake8` to check the code style: 25 | 26 | ```bash 27 | flake8 --install-hook git 28 | ``` 29 | 30 | ## Create a pull request 31 | 32 | 1. Choose the `develop` branch as a target for new/changed functionality, `main` should only be targeted for urgent bugfixes. 33 | 2. While it's not strictly required, it's highly recommended to create a new branch on your fork for each pull request. 34 | 3. Push to your fork and [submit a pull request][pr]. 35 | 4. Check if the [build ran successfully][ci] and try to improve your code if not. 36 | 37 | At this point you're waiting for my review. 38 | I might suggest some changes or improvements or alternatives. 39 | 40 | Some things that will increase the chance that your pull request is accepted: 41 | 42 | * Write tests. 43 | * Follow the Python style guide ([PEP-8][pep8]). 44 | * Write a [good commit message][commit]. 45 | 46 | [pr]: https://github.com/metaodi/swissparlpy/compare/ 47 | [ci]: https://github.com/metaodi/swissparlpy/actions 48 | [pep8]: https://www.python.org/dev/peps/pep-0008/ 49 | [commit]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html 50 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project follows [Semantic Versioning](http://semver.org/). 4 | 5 | ## [Unreleased] 6 | 7 | ## [0.3.0] - 2023-08-31 8 | ### Added 9 | - Support for server-side pagination (transparent to the user) 10 | - `ResultVeryLargeWarning` to warn developers about very large queries 11 | - Logging to help with debugging 12 | - Add pre-commit configuration 13 | 14 | ### Changed 15 | - Use `black` code style 16 | 17 | ## [0.2.1] - 2022-01-31 18 | ### Fixed 19 | - In order to fix issue #17 a bug in pyodata had to be fixed. pyodata 1.9.0 contains the bugfix and is now specified as the minimum version. 20 | 21 | ## [0.2.0] - 2021-10-14 22 | ### Added 23 | - Jupyter notebook with examples 24 | - New examples for advanced filters 25 | - Support for more advanced filters 26 | 27 | ### Changed 28 | - Update README with examples 29 | 30 | ## [0.1.1] - 2021-09-27 31 | ### Fixed 32 | - Typo in publish workflow 33 | 34 | ## [0.1.0] - 2021-09-27 35 | ### Added 36 | - Test with fixtures 37 | - Linter for all code 38 | - Usage example in README 39 | 40 | ### Fixed 41 | - Fixed `get_variables` call 42 | - Make sure `get_tables` returns a list 43 | 44 | 45 | ## [0.0.2] - 2021-09-27 46 | ### Added 47 | - Added CHANGELOG file 48 | 49 | ### Changed 50 | - Use flit to manage pypi package 51 | 52 | 53 | ## [0.0.1] - 2021-09-26 54 | ### Added 55 | - Initial release of swissparlpy 56 | 57 | 58 | # Categories 59 | - `Added` for new features. 60 | - `Changed` for changes in existing functionality. 61 | - `Deprecated` for once-stable features removed in upcoming releases. 62 | - `Removed` for deprecated features removed in this release. 63 | - `Fixed` for any bug fixes. 64 | - `Security` to invite users to upgrade in case of vulnerabilities. 65 | 66 | [Unreleased]: https://github.com/metaodi/swissparlpy/compare/v0.3.0...HEAD 67 | [0.3.0]: https://github.com/metaodi/swissparlpy/compare/v0.2.1...v0.3.0 68 | [0.2.1]: https://github.com/metaodi/swissparlpy/compare/v0.2.0...v0.2.1 69 | [0.2.0]: https://github.com/metaodi/swissparlpy/compare/v0.1.1...v0.2.0 70 | [0.1.1]: https://github.com/metaodi/swissparlpy/compare/v0.1.0...v0.1.1 71 | [0.1.0]: https://github.com/metaodi/swissparlpy/compare/v0.0.2...v0.1.0 72 | [0.0.2]: https://github.com/metaodi/swissparlpy/compare/v0.0.1...v0.0.2 73 | [0.0.1]: https://github.com/metaodi/swissparlpy/releases/tag/v0.0.1 74 | -------------------------------------------------------------------------------- /tests/client_test.py: -------------------------------------------------------------------------------- 1 | from swissparlpy_test import SwissParlTestCase 2 | from swissparlpy.client import SwissParlClient 3 | from swissparlpy.client import SwissParlResponse 4 | import responses 5 | 6 | SERVICE_URL = "https://ws.parlament.ch/odata.svc" 7 | 8 | 9 | class TestClient(SwissParlTestCase): 10 | @responses.activate 11 | def test_get_overview(self, metadata): 12 | responses.add( 13 | responses.GET, 14 | f"{SERVICE_URL}/$metadata", 15 | content_type="text/xml", 16 | body=metadata, 17 | status=200, 18 | ) 19 | client = SwissParlClient() 20 | overview = client.get_overview() 21 | assert isinstance(overview, dict), "Overview is not a dict" 22 | assert len(overview) == 44 23 | 24 | @responses.activate 25 | def test_get_data(self, metadata, business_page1, business_page2): 26 | with responses.RequestsMock() as rsps: 27 | rsps.add( 28 | responses.GET, 29 | f"{SERVICE_URL}/$metadata", 30 | content_type="text/xml", 31 | body=metadata, 32 | status=200, 33 | ) 34 | rsps.add( 35 | responses.GET, 36 | f"{SERVICE_URL}/Business?%24filter=Language+eq+%27DE%27&%24inlinecount=allpages", # noqa 37 | content_type="text/xml", 38 | body=business_page1, 39 | status=200, 40 | ) 41 | rsps.add( 42 | responses.GET, 43 | f"{SERVICE_URL}/Business?$filter=Language%20eq%20'DE'&$inlinecount=allpages&$skiptoken=19943083,'DE'", # noqa 44 | content_type="text/xml", 45 | body=business_page2, 46 | status=200, 47 | ) 48 | client = SwissParlClient() 49 | business = client.get_data("Business", Language="DE") 50 | assert isinstance( 51 | business, SwissParlResponse 52 | ), "business is not a SwissParlResponse" 53 | assert business.count == 52 54 | assert isinstance(business[1], dict), "business[1] is not a dict" 55 | assert business[1]["Title"] == "BV. Unternehmensrecht (Jelmini)" 56 | 57 | # trigger the 2nd page to load 58 | assert isinstance(business[-1], dict), "business[-1] is not a dict" 59 | assert business[-1]["Title"] == "Ausdruck der Abstimmungsergebnisse" 60 | -------------------------------------------------------------------------------- /swissparlpy/client.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import warnings 3 | import requests 4 | import pyodata 5 | from . import errors 6 | 7 | SERVICE_URL = "https://ws.parlament.ch/odata.svc/" 8 | log = logging.getLogger(__name__) 9 | 10 | 11 | class SwissParlClient(object): 12 | def __init__(self, session=None, url=SERVICE_URL): 13 | if not session: 14 | session = requests.Session() 15 | self.url = url 16 | self.client = pyodata.Client(url, session) 17 | self.cache = {} 18 | self.get_overview() 19 | 20 | def get_tables(self): 21 | if self.cache: 22 | return list(self.cache.keys()) 23 | return [es.name for es in self.client.schema.entity_sets] 24 | 25 | def get_variables(self, table): 26 | if self.cache and table in self.cache: 27 | return self.cache[table] 28 | return [p.name for p in self.client.schema.entity_type(table).proprties()] 29 | 30 | def get_overview(self): 31 | log.debug("Load tables and variables from OData...") 32 | if self.cache: 33 | return self.cache 34 | self.cache = {} 35 | for t in self.get_tables(): 36 | self.cache[t] = self.get_variables(t) 37 | return self.cache 38 | 39 | def get_glimpse(self, table, rows=5): 40 | entities = self._get_entities(table) 41 | return SwissParlResponse( 42 | entities.top(rows).count(inline=True), self.get_variables(table) 43 | ) 44 | 45 | def get_data(self, table, filter=None, **kwargs): 46 | entities = self._get_entities(table) 47 | if filter and callable(filter): 48 | entities = entities.filter(filter(entities)) 49 | elif filter: 50 | entities = entities.filter(filter) 51 | 52 | if kwargs: 53 | entities = entities.filter(**kwargs) 54 | return SwissParlResponse(entities.count(inline=True), self.get_variables(table)) 55 | 56 | def _get_entities(self, table): 57 | return getattr(self.client.entity_sets, table).get_entities() 58 | 59 | 60 | class SwissParlResponse(object): 61 | def __init__(self, entity_request, variables): 62 | self.variables = variables 63 | self.data = [] 64 | self.entity_request = entity_request 65 | entities = self.load() 66 | self._parse_data(entities) 67 | 68 | def load(self, next_url=None): 69 | log.debug(f"Load data, next_url={next_url}") 70 | if next_url: 71 | entities = self.entity_request.next_url(next_url).execute() 72 | else: 73 | entities = self.entity_request.execute() 74 | 75 | return entities 76 | 77 | def _load_new_data_until(self, limit): 78 | if limit >= 10000: 79 | warnings.warn( 80 | """ 81 | More than 10'000 items are loaded, this will use a lot of memory. 82 | Consider to query a subset of the data to improve performance. 83 | """, 84 | errors.ResultVeryLargeWarning, 85 | ) 86 | log.debug(f"Load new data, limit={limit}") 87 | while limit >= len(self.data): 88 | try: 89 | self._load_new_data() 90 | log.debug( 91 | f""" 92 | New data loaded: 93 | - limit={limit} 94 | - len(data)={len(self.data)} 95 | - count={self.count} 96 | """ 97 | ) 98 | except errors.NoMoreRecordsError: 99 | break 100 | 101 | def _load_new_data(self): 102 | if self.next_url is None: 103 | raise errors.NoMoreRecordsError() 104 | entities = self.load(next_url=self.next_url) 105 | self._parse_data(entities) 106 | 107 | def _parse_data(self, entities): 108 | self.count = entities.total_count 109 | self._setup_proxies(entities) 110 | self.next_url = entities.next_url 111 | 112 | def _setup_proxies(self, entities): 113 | for e in entities: 114 | self.data.append(SwissParlDataProxy(e)) 115 | 116 | def __len__(self): 117 | return self.count 118 | 119 | def __iter__(self): 120 | # use while loop since self.data could grow while iterating 121 | i = 0 122 | while True: 123 | # load new data when near end 124 | if i == len(self.data): 125 | try: 126 | self._load_new_data() 127 | except errors.NoMoreRecordsError: 128 | break 129 | yield {k: self.data[i](k) for k in self.variables} 130 | i += 1 131 | 132 | def __getitem__(self, key): 133 | if isinstance(key, slice): 134 | limit = max(key.start or 0, key.stop or self.count) 135 | self._load_new_data_until(limit) 136 | count = len(self.data) 137 | return [ 138 | {k: self.data[i](k) for k in self.variables} 139 | for i in range(*key.indices(count)) 140 | ] 141 | 142 | if not isinstance(key, int): 143 | raise TypeError("Index must be an integer or slice") 144 | 145 | limit = key 146 | if limit < 0: 147 | # if we get a negative index, load all data 148 | limit = self.count 149 | self._load_new_data_until(limit) 150 | return {k: self.data[key](k) for k in self.variables} 151 | 152 | 153 | class SwissParlDataProxy(object): 154 | def __init__(self, proxy): 155 | self.proxy = proxy 156 | 157 | def __call__(self, attribute): 158 | return getattr(self.proxy, attribute) 159 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![PyPI Version][pypi-image]][pypi-url] 2 | [![Build Status][build-image]][build-url] 3 | [![Code style: black][black-image]][black-url] 4 | [![pre-commit][pre-commit-image]][pre-commit-url] 5 | 6 | 7 | swissparlpy 8 | =========== 9 | 10 | This module provides easy access to the data of the [OData webservice](https://ws.parlament.ch/odata.svc/) of the [Swiss parliament](https://www.parlament.ch/en). 11 | 12 | ## Table of Contents 13 | 14 | * [Installation](#installation) 15 | * [Usage](#usage) 16 | * [Get tables and their variables](#get-tables-and-their-variables) 17 | * [Get data of a table](#get-data-of-a-table) 18 | * [Use together with `pandas`](#use-together-with-pandas) 19 | * [Substrings](#substrings) 20 | * [Date ranges](#date-ranges) 21 | * [Advanced filter](#advanced-filter) 22 | * [Large queries](#large-queries) 23 | * [API documentation](#documentation) 24 | * [Similar libraries for other languages](#similar-libraries-for-other-languages) 25 | * [Credits](#credits) 26 | * [Development](#development) 27 | * [Release](#release) 28 | 29 | ## Installation 30 | 31 | [swissparlpy is available on PyPI](https://pypi.org/project/swissparlpy/), so to install it simply use: 32 | 33 | ``` 34 | $ pip install swissparlpy 35 | ``` 36 | 37 | ## Usage 38 | 39 | See the [`examples` directory](/examples) for more scripts. 40 | 41 | ### Get tables and their variables 42 | 43 | ```python 44 | >>> import swissparlpy as spp 45 | >>> spp.get_tables()[:5] # get first 5 tables 46 | ['MemberParty', 'Party', 'Person', 'PersonAddress', 'PersonCommunication'] 47 | >>> spp.get_variables('Party') # get variables of table `Party` 48 | ['ID', 'Language', 'PartyNumber', 'PartyName', 'StartDate', 'EndDate', 'Modified', 'PartyAbbreviation'] 49 | ``` 50 | 51 | ### Get data of a table 52 | 53 | ```python 54 | >>> import swissparlpy as spp 55 | >>> data = spp.get_data('Canton', Language='DE') 56 | >>> data 57 | 58 | >>> data.count 59 | 26 60 | >>> data[0] 61 | {'ID': 2, 'Language': 'DE', 'CantonNumber': 2, 'CantonName': 'Bern', 'CantonAbbreviation': 'BE'} 62 | >>> [d['CantonName'] for d in data] 63 | ['Bern', 'Neuenburg', 'Genf', 'Wallis', 'Uri', 'Schaffhausen', 'Jura', 'Basel-Stadt', 'St. Gallen', 'Obwalden', 'Appenzell A.-Rh.', 'Solothurn', 'Waadt', 'Zug', 'Aargau', 'Basel-Landschaft', 'Luzern', 'Thurgau', 'Freiburg', 'Appenzell I.-Rh.', 'Schwyz', 'Graubünden', 'Glarus', 'Tessin', 'Zürich', 'Nidwalden'] 64 | ``` 65 | 66 | The return value of `get_data` is iterable, so you can easily loop over it. Or you can use indices to access elements, e.g. `data[1]` to get the second element, or `data[-1]` to get the last one. 67 | 68 | Even [slicing](https://python-reference.readthedocs.io/en/latest/docs/brackets/slicing.html) is supported, so you can do things like only iterate over the first 5 elements using 69 | 70 | ```python 71 | for rec in data[:5]: 72 | print(rec) 73 | ``` 74 | 75 | ### Use together with `pandas` 76 | 77 | To create a pandas DataFrame from `get_data` simply pass the return value to the constructor: 78 | 79 | ```python 80 | >>> import swissparlpy as spp 81 | >>> import pandas as pd 82 | >>> parties = spp.get_data('Party', Language='DE') 83 | >>> parties_df = pd.DataFrame(parties) 84 | >>> parties_df 85 | ID Language PartyNumber ... EndDate Modified PartyAbbreviation 86 | 0 12 DE 12 ... 2000-01-01 00:00:00+00:00 2010-12-26 13:05:26.430000+00:00 SP 87 | 1 13 DE 13 ... 2000-01-01 00:00:00+00:00 2010-12-26 13:05:26.430000+00:00 SVP 88 | 2 14 DE 14 ... 2000-01-01 00:00:00+00:00 2010-12-26 13:05:26.430000+00:00 CVP 89 | 3 15 DE 15 ... 2000-01-01 00:00:00+00:00 2010-12-26 13:05:26.430000+00:00 FDP-Liberale 90 | 4 16 DE 16 ... 2000-01-01 00:00:00+00:00 2010-12-26 13:05:26.430000+00:00 LDP 91 | .. ... ... ... ... ... ... ... 92 | 78 1582 DE 1582 ... 2000-01-01 00:00:00+00:00 2015-12-03 08:48:38.250000+00:00 BastA 93 | 79 1583 DE 1583 ... 2000-01-01 00:00:00+00:00 2019-03-07 17:24:15.013000+00:00 CVPO 94 | 80 1584 DE 1584 ... 2000-01-01 00:00:00+00:00 2019-11-08 17:28:43.947000+00:00 Al 95 | 81 1585 DE 1585 ... 2000-01-01 00:00:00+00:00 2019-11-08 17:41:39.513000+00:00 EàG 96 | 82 1586 DE 1586 ... 2000-01-01 00:00:00+00:00 2021-08-12 07:59:22.627000+00:00 M-E 97 | 98 | [83 rows x 8 columns] 99 | ``` 100 | 101 | ### Substrings 102 | 103 | If you want to query for substrings there are two main operators to use: 104 | 105 | **`__startswith`**: 106 | 107 | ```python 108 | >>> import swissparlpy as spp 109 | >>> persons = spp.get_data("Person", Language="DE", LastName__startswith='Bal') 110 | >>> persons.count 111 | 12 112 | ``` 113 | 114 | **`__contains`** 115 | ```python 116 | >>> import swissparlpy as spp 117 | >>> co2_business = spp.get_data("Business", Title__contains="CO2", Language = "DE") 118 | >>> co2_business.count 119 | 265 120 | ``` 121 | 122 | You can suffix any field with those operators to query the data. 123 | 124 | ### Date ranges 125 | 126 | To query for date ranges you can use the operators... 127 | 128 | * `__gt` (greater than) 129 | * `__gte` (greater than or equal) 130 | * `__lt` (less than) 131 | * `__lte` (less than or equal) 132 | 133 | ...in combination with a `datetime` object. 134 | 135 | ```python 136 | >>> import swissparlpy as spp 137 | >>> from datetime import datetime 138 | >>> business = spp.get_data( 139 | ... "Business", 140 | ... Language="DE", 141 | ... SubmissionDate__gt=datetime.fromisoformat('2019-09-30'), 142 | ... SubmissionDate__lte=datetime.fromisoformat('2019-10-31') 143 | ... ) 144 | >>> business.count 145 | 22 146 | ``` 147 | 148 | ### Advanced filter 149 | 150 | **Text query** 151 | 152 | It's possible to write text queries using operators like `eq` (equals), `ne` (not equals), `lt`/`lte` (less than/less than or equals), `gt` / `gte` (greater than/greater than or equals), `startswith()` and `contains`: 153 | 154 | ```python 155 | import swissparlpy as spp 156 | import pandas as pd 157 | 158 | persons = spp.get_data( 159 | "Person", 160 | filter="(startswith(FirstName, 'Ste') or LastName eq 'Seiler') and Language eq 'DE'" 161 | ) 162 | 163 | df = pd.DataFrame(persons) 164 | print(df[['FirstName', 'LastName']]) 165 | ``` 166 | 167 | **Callable Filter** 168 | 169 | You can provide a callable as a filter which allows for more advanced filters. 170 | 171 | `swissparlpy.filter` provides `or_` and `and_`. 172 | 173 | ```python 174 | import swissparlpy as spp 175 | import pandas as pd 176 | 177 | # filter by FirstName = 'Stefan' OR LastName == 'Seiler' 178 | def filter_by_name(ent): 179 | return spp.filter.or_( 180 | ent.FirstName == 'Stefan', 181 | ent.LastName == 'Seiler' 182 | ) 183 | 184 | persons = spp.get_data("Person", filter=filter_by_name, Language='DE') 185 | 186 | df = pd.DataFrame(persons) 187 | print(df[['FirstName', 'LastName']]) 188 | ``` 189 | 190 | ### Large queries 191 | 192 | Large queries (especially the tables Voting and Transcripts) may result in server-side errors (500 Internal Server Error). In these cases it is recommended to download the data in smaller batches, save the individual blocks and combine them after the download. 193 | 194 | This is an [example script](/examples/download_votes_in_batches.py) to download all votes of the legislative period 50, session by session, and combine them afterwards in one `DataFrame`: 195 | 196 | ```python 197 | import swissparlpy as spp 198 | import pandas as pd 199 | import os 200 | 201 | __location__ = os.path.realpath(os.getcwd()) 202 | path = os.path.join(__location__, "voting50") 203 | 204 | # download votes of one session and save as pickled DataFrame 205 | def save_votes_of_session(id, path): 206 | if not os.path.exists(path): 207 | os.mkdir(path) 208 | data = spp.get_data("Voting", Language="DE", IdSession=id) 209 | print(f"{data.count} rows loaded.") 210 | df = pd.DataFrame(data) 211 | pickle_path = os.path.join(path, f'{id}.pks') 212 | df.to_pickle(pickle_path) 213 | print(f"Saved pickle at {pickle_path}") 214 | 215 | 216 | # get all session of the 50 legislative period 217 | sessions50 = spp.get_data("Session", Language="DE", LegislativePeriodNumber=50) 218 | sessions50.count 219 | 220 | for session in sessions50: 221 | print(f"Loading session {session['ID']}") 222 | save_votes_of_session(session['ID'], path) 223 | 224 | # Combine to one dataframe 225 | df_voting50 = pd.concat([pd.read_pickle(os.path.join(path, x)) for x in os.listdir(path)]) 226 | ``` 227 | 228 | ### Documentation 229 | 230 | The referencing table has been created and is available [here](docs/swissparAPY_diagram.pdf). It contains the dependency diagram between all of the tables as well, some exhaustive descriptions as well as the code needed to generate such interactive documentation. 231 | The documentation can indeed be recreated using [dbdiagram.io](https://dbdiagram.io/home). 232 | 233 | Below is a first look of what the dependencies are between the tables contained in the API: 234 | 235 | ![db diagram of swiss parliament API](/docs/swissparAPY_diagram.png "db diagram of swiss parliament API") 236 | 237 | ### Similar libraries for other languages 238 | 239 | * R: [zumbov2/swissparl](https://github.com/zumbov2/swissparl) 240 | * JavaScript: [michaelschoenbaechler/swissparl](https://github.com/michaelschoenbaechler/swissparl) 241 | 242 | ## Credits 243 | 244 | This library is inspired by the R package [swissparl](https://github.com/zumbov2/swissparl) of [David Zumbach](https://github.com/zumbov2). 245 | [Ralph Straumann](https://twitter.com/rastrau) initial [asked about a Python version of `swissparl` on Twitter](https://twitter.com/rastrau/status/1441048778740432902), which led to this project. 246 | 247 | ## Development 248 | 249 | To develop on this project, install `flit`: 250 | 251 | ``` 252 | pip install flit 253 | flit install -s 254 | ``` 255 | 256 | ## Release 257 | 258 | To create a new release, follow these steps (please respect [Semantic Versioning](http://semver.org/)): 259 | 260 | 1. Adapt the version number in `swissparlpy/__init__.py` 261 | 1. Update the CHANGELOG with the version 262 | 1. Create a [pull request to merge `develop` into `main`](https://github.com/metaodi/swissparlpy/compare/main...develop?expand=1) (make sure the tests pass!) 263 | 1. Create a [new release/tag on GitHub](https://github.com/metaodi/swissparlpy/releases) (on the main branch) 264 | 1. The [publication on PyPI](https://pypi.python.org/pypi/swissparlpy) happens via [GitHub Actions](https://github.com/metaodi/swissparlpy/actions?query=workflow%3A%22Upload+Python+Package%22) on every tagged commit 265 | 266 | 267 | 268 | [pypi-image]: https://img.shields.io/pypi/v/swissparlpy 269 | [pypi-url]: https://pypi.org/project/swissparlpy/ 270 | [build-image]: https://github.com/metaodi/swissparlpy/actions/workflows/build.yml/badge.svg 271 | [build-url]: https://github.com/metaodi/swissparlpy/actions/workflows/build.yml 272 | [black-image]: https://img.shields.io/badge/code%20style-black-000000.svg 273 | [black-url]: https://github.com/psf/black 274 | [pre-commit-image]: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit 275 | [pre-commit-url]: https://github.com/pre-commit/pre-commit 276 | -------------------------------------------------------------------------------- /examples/Swiss Parliament API.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "670c0b4a", 6 | "metadata": {}, 7 | "source": [ 8 | "# Usage examples of `swissparlpy`" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "id": "60b39167", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import swissparlpy as spp\n", 19 | "import requests\n", 20 | "import pandas as pd\n", 21 | "import os\n", 22 | "import urllib3\n", 23 | "from datetime import datetime, timezone" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": null, 29 | "id": "be673d98", 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "urllib3.disable_warnings()\n", 34 | "__location__ = os.path.realpath(os.getcwd())" 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "id": "dcb93cce", 40 | "metadata": {}, 41 | "source": [ 42 | "## Create client with custom session\n", 43 | "\n", 44 | "Sometimes it's necessary to tweak the requests Session (e.g. to provide authentication or disable SSL verification).\n", 45 | "For this purpose a custom session can be passed to `SwissParlClient`." 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": null, 51 | "id": "8b025514", 52 | "metadata": {}, 53 | "outputs": [], 54 | "source": [ 55 | "session = requests.Session()\n", 56 | "session.verify = False # disable SSL verification\n", 57 | "client = spp.SwissParlClient(session=session)" 58 | ] 59 | }, 60 | { 61 | "cell_type": "markdown", 62 | "id": "688454dc", 63 | "metadata": {}, 64 | "source": [ 65 | "For most common cases, this is not necessary and you don't even have to create your own `SwissParlClient`.\n", 66 | "\n", 67 | "Simply use the shorthand methods to get the data:" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": null, 73 | "id": "bb8d2861", 74 | "metadata": {}, 75 | "outputs": [], 76 | "source": [ 77 | "tables = spp.get_tables()\n", 78 | "glimpse_df = pd.DataFrame(spp.get_glimpse(tables[0]))\n", 79 | "glimpse_df" 80 | ] 81 | }, 82 | { 83 | "cell_type": "markdown", 84 | "id": "90daa5c0", 85 | "metadata": {}, 86 | "source": [ 87 | "## Get metadata of tables and variables" 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "execution_count": null, 93 | "id": "98bd4380", 94 | "metadata": {}, 95 | "outputs": [], 96 | "source": [ 97 | "client.get_tables() # get list of all tables" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": null, 103 | "id": "8e806d59", 104 | "metadata": {}, 105 | "outputs": [], 106 | "source": [ 107 | "client.get_variables('Party') # get list of variables of a table" 108 | ] 109 | }, 110 | { 111 | "cell_type": "markdown", 112 | "id": "ea10ec83", 113 | "metadata": {}, 114 | "source": [ 115 | "## Load data in `pandas` DataFrame" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": null, 121 | "id": "40ff9c5d", 122 | "metadata": {}, 123 | "outputs": [], 124 | "source": [ 125 | "parties = client.get_data('Party', Language='DE')\n", 126 | "parties_df = pd.DataFrame(parties)\n", 127 | "parties_df" 128 | ] 129 | }, 130 | { 131 | "cell_type": "markdown", 132 | "id": "0e8dc714", 133 | "metadata": {}, 134 | "source": [ 135 | "## Use substring operators to query data (`__startswith`, `__contains`)" 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": null, 141 | "id": "ae6fc080", 142 | "metadata": {}, 143 | "outputs": [], 144 | "source": [ 145 | "persons = client.get_data(\"Person\", Language=\"DE\", LastName__startswith='Bal')\n", 146 | "persons.count" 147 | ] 148 | }, 149 | { 150 | "cell_type": "code", 151 | "execution_count": null, 152 | "id": "0ddc4859", 153 | "metadata": {}, 154 | "outputs": [], 155 | "source": [ 156 | "person_df = pd.DataFrame(persons)\n", 157 | "person_df" 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": null, 163 | "id": "2a992abb", 164 | "metadata": {}, 165 | "outputs": [], 166 | "source": [ 167 | "co2_business = client.get_data(\"Business\", Title__contains=\"CO2\", Language = \"DE\")\n", 168 | "co2_business.count" 169 | ] 170 | }, 171 | { 172 | "cell_type": "code", 173 | "execution_count": null, 174 | "id": "1f41475a", 175 | "metadata": {}, 176 | "outputs": [], 177 | "source": [ 178 | "co2_df = pd.DataFrame(co2_business)\n", 179 | "co2_df" 180 | ] 181 | }, 182 | { 183 | "cell_type": "markdown", 184 | "id": "45d34f77", 185 | "metadata": {}, 186 | "source": [ 187 | "## Query with date ranges" 188 | ] 189 | }, 190 | { 191 | "cell_type": "code", 192 | "execution_count": null, 193 | "id": "b49d0a3a", 194 | "metadata": {}, 195 | "outputs": [], 196 | "source": [ 197 | "utc_start_date = datetime.fromisoformat('2019-10-01').astimezone(timezone.utc)\n", 198 | "utc_end_Date = datetime.fromisoformat('2019-10-31').astimezone(timezone.utc)\n", 199 | "business_oct19 = client.get_data(\n", 200 | " \"Business\",\n", 201 | " Language=\"DE\",\n", 202 | " SubmissionDate__gte=utc_start_date,\n", 203 | " SubmissionDate__lt=utc_end_Date\n", 204 | ")\n", 205 | "business_oct19.count" 206 | ] 207 | }, 208 | { 209 | "cell_type": "code", 210 | "execution_count": null, 211 | "id": "90e0cb05", 212 | "metadata": {}, 213 | "outputs": [], 214 | "source": [ 215 | "busi_oct19 = pd.DataFrame(business_oct19)\n", 216 | "busi_oct19 = busi_oct19.sort_values(by=['SubmissionDate']).reset_index(drop=True)\n", 217 | "busi_oct19[['SubmissionDate', 'Title']]" 218 | ] 219 | }, 220 | { 221 | "cell_type": "markdown", 222 | "id": "60aa1b13", 223 | "metadata": {}, 224 | "source": [ 225 | "## Download large query in batches\n", 226 | "\n", 227 | "This script shows how to download votes from the `Voting` table by iterating over each session in a legislative period.\n", 228 | "The chunks are then saved in a directory as pickled DataFrames.\n", 229 | "\n", 230 | "Later on, those chunks can easily be combined together as a single DataFrame containing all the votes of a legislative period." 231 | ] 232 | }, 233 | { 234 | "cell_type": "code", 235 | "execution_count": null, 236 | "id": "d815c0b1", 237 | "metadata": {}, 238 | "outputs": [], 239 | "source": [ 240 | "path = os.path.join(__location__, \"voting50\")\n", 241 | "\n", 242 | "def save_votes_of_session(id):\n", 243 | " if not os.path.exists(path):\n", 244 | " os.mkdir(path)\n", 245 | " pickle_path = os.path.join(path, f'{id}.pks')\n", 246 | " \n", 247 | " if os.path.exists(pickle_path):\n", 248 | " print(f\"File {pickle_path} already exists, skipping\")\n", 249 | " return\n", 250 | " \n", 251 | " print(f\"Loading votes of session {id}...\")\n", 252 | " data = client.get_data(\"Voting\", Language=\"DE\", IdSession=id)\n", 253 | " print(f\"{data.count} rows loaded.\")\n", 254 | " df = pd.DataFrame(data)\n", 255 | " \n", 256 | " df.to_pickle(pickle_path)\n", 257 | " print(f\"Saved pickle at {pickle_path}\")\n", 258 | " print(\"\")\n", 259 | "\n", 260 | "\n", 261 | "# get all session of the 50 legislative period\n", 262 | "sessions50 = client.get_data(\"Session\", Language=\"DE\", LegislativePeriodNumber=50)\n", 263 | "sessions50.count\n", 264 | "\n", 265 | "for session in sessions50:\n", 266 | " print(f\"Loading session {session['ID']}\")\n", 267 | " save_votes_of_session(session['ID'])\n", 268 | "\n", 269 | "# Combine to one dataframe\n", 270 | "path = os.path.join(__location__, \"voting50\")\n", 271 | "df_voting50 = pd.concat([pd.read_pickle(os.path.join(path, x)) for x in os.listdir(path)])\n", 272 | "df_voting50" 273 | ] 274 | }, 275 | { 276 | "cell_type": "code", 277 | "execution_count": null, 278 | "id": "fea8e8b1", 279 | "metadata": {}, 280 | "outputs": [], 281 | "source": [ 282 | "df_5005 = pd.read_pickle(os.path.join(__location__, \"voting50\", '5005.pks'))\n", 283 | "df_5005" 284 | ] 285 | }, 286 | { 287 | "cell_type": "code", 288 | "execution_count": null, 289 | "id": "88747639", 290 | "metadata": {}, 291 | "outputs": [], 292 | "source": [ 293 | "# Combine to one dataframe\n", 294 | "path = os.path.join(__location__, \"voting50\")\n", 295 | "df_voting50 = pd.concat([pd.read_pickle(os.path.join(path, x)) for x in os.listdir(path)])\n", 296 | "df_voting50" 297 | ] 298 | }, 299 | { 300 | "cell_type": "markdown", 301 | "id": "9dc1854c-9f97-4bd4-bc21-50b361efa54b", 302 | "metadata": {}, 303 | "source": [ 304 | "## Queries with lots of results (server-side pagination)\n", 305 | "\n", 306 | "There is a server-side limit of 1000 items that are being returned.\n", 307 | "swissparlpy handles this server-side pagination transparently, so a user of the library should not worry about it." 308 | ] 309 | }, 310 | { 311 | "cell_type": "code", 312 | "execution_count": null, 313 | "id": "408f6b47-c352-49ac-ac0a-b4fbaa00b7cc", 314 | "metadata": {}, 315 | "outputs": [], 316 | "source": [ 317 | "business = client.get_data(\"Business\", Language = \"DE\")\n", 318 | "business.count" 319 | ] 320 | }, 321 | { 322 | "cell_type": "markdown", 323 | "id": "b6b842d0-ebd5-44a2-9169-0d91128f3da3", 324 | "metadata": {}, 325 | "source": [ 326 | "As we can see, there are over 50k results.\n", 327 | "Initially only the first 1000 are loaded:" 328 | ] 329 | }, 330 | { 331 | "cell_type": "code", 332 | "execution_count": null, 333 | "id": "8b463504-3a2e-417d-b302-47adb70d23a9", 334 | "metadata": {}, 335 | "outputs": [], 336 | "source": [ 337 | "len(business.data)" 338 | ] 339 | }, 340 | { 341 | "cell_type": "code", 342 | "execution_count": null, 343 | "id": "02717c13-01a6-4772-b492-c56afdddac85", 344 | "metadata": {}, 345 | "outputs": [], 346 | "source": [ 347 | "business[1]" 348 | ] 349 | }, 350 | { 351 | "cell_type": "markdown", 352 | "id": "49fd8ec7-e5d8-4b10-ba03-1543bf52b81e", 353 | "metadata": {}, 354 | "source": [ 355 | "But as soon as a next element is accessed, new data is (lazy) loaded:" 356 | ] 357 | }, 358 | { 359 | "cell_type": "code", 360 | "execution_count": null, 361 | "id": "fafc6266-cc43-4975-9e39-2866f29ef713", 362 | "metadata": {}, 363 | "outputs": [], 364 | "source": [ 365 | "business[1001]" 366 | ] 367 | }, 368 | { 369 | "cell_type": "code", 370 | "execution_count": null, 371 | "id": "54556cc8-e076-4ea7-bb10-63aaf9f80e10", 372 | "metadata": {}, 373 | "outputs": [], 374 | "source": [ 375 | "len(business.data)" 376 | ] 377 | }, 378 | { 379 | "cell_type": "markdown", 380 | "id": "19628322-4a7f-4720-a910-e2d72c1d744c", 381 | "metadata": {}, 382 | "source": [ 383 | "If the last element is needed, all the data is loaded (NOTE: this uses quite some memory):" 384 | ] 385 | }, 386 | { 387 | "cell_type": "code", 388 | "execution_count": null, 389 | "id": "bcdb29ce-30ba-428c-9162-b2c843020227", 390 | "metadata": {}, 391 | "outputs": [], 392 | "source": [ 393 | "business[-1]" 394 | ] 395 | }, 396 | { 397 | "cell_type": "code", 398 | "execution_count": null, 399 | "id": "79adb078-dffc-46a2-8746-2b54238b3718", 400 | "metadata": {}, 401 | "outputs": [], 402 | "source": [ 403 | "len(business.data)" 404 | ] 405 | } 406 | ], 407 | "metadata": { 408 | "kernelspec": { 409 | "display_name": "Python 3 (ipykernel)", 410 | "language": "python", 411 | "name": "python3" 412 | }, 413 | "language_info": { 414 | "codemirror_mode": { 415 | "name": "ipython", 416 | "version": 3 417 | }, 418 | "file_extension": ".py", 419 | "mimetype": "text/x-python", 420 | "name": "python", 421 | "nbconvert_exporter": "python", 422 | "pygments_lexer": "ipython3", 423 | "version": "3.8.10" 424 | } 425 | }, 426 | "nbformat": 4, 427 | "nbformat_minor": 5 428 | } 429 | -------------------------------------------------------------------------------- /tests/fixtures/business_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "d": { 3 | "results": [ 4 | { 5 | "__metadata": { 6 | "id": "https://ws.parlament.ch/OData.svc/Business(ID=19943084,Language='DE')", 7 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943084,Language='DE')", 8 | "type": "itsystems.Pd.DataServices.DataModel.Business" 9 | }, 10 | "BusinessResponsibilities": { 11 | "__deferred": { 12 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943084,Language='DE')/BusinessResponsibilities" 13 | } 14 | }, 15 | "RelatedBusinesses": { 16 | "__deferred": { 17 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943084,Language='DE')/RelatedBusinesses" 18 | } 19 | }, 20 | "BusinessRoles": { 21 | "__deferred": { 22 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943084,Language='DE')/BusinessRoles" 23 | } 24 | }, 25 | "Publications": { 26 | "__deferred": { 27 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943084,Language='DE')/Publications" 28 | } 29 | }, 30 | "LegislativePeriods": { 31 | "__deferred": { 32 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943084,Language='DE')/LegislativePeriods" 33 | } 34 | }, 35 | "Sessions": { 36 | "__deferred": { 37 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943084,Language='DE')/Sessions" 38 | } 39 | }, 40 | "Preconsultations": { 41 | "__deferred": { 42 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943084,Language='DE')/Preconsultations" 43 | } 44 | }, 45 | "Bills": { 46 | "__deferred": { 47 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943084,Language='DE')/Bills" 48 | } 49 | }, 50 | "Councils": { 51 | "__deferred": { 52 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943084,Language='DE')/Councils" 53 | } 54 | }, 55 | "BusinessTypes": { 56 | "__deferred": { 57 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943084,Language='DE')/BusinessTypes" 58 | } 59 | }, 60 | "Votes": { 61 | "__deferred": { 62 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943084,Language='DE')/Votes" 63 | } 64 | }, 65 | "SubjectsBusiness": { 66 | "__deferred": { 67 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943084,Language='DE')/SubjectsBusiness" 68 | } 69 | }, 70 | "BusinessStates": { 71 | "__deferred": { 72 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943084,Language='DE')/BusinessStates" 73 | } 74 | }, 75 | "Council": { 76 | "__deferred": { 77 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943084,Language='DE')/Council" 78 | } 79 | }, 80 | "Transcripts": { 81 | "__deferred": { 82 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943084,Language='DE')/Transcripts" 83 | } 84 | }, 85 | "ID": 19943084, 86 | "Language": "DE", 87 | "BusinessShortNumber": "94.3084", 88 | "BusinessType": 8, 89 | "BusinessTypeName": "Interpellation", 90 | "BusinessTypeAbbreviation": "Ip.", 91 | "Title": "Vernehmlassungsverfahren", 92 | "Description": null, 93 | "InitialSituation": null, 94 | "Proceedings": null, 95 | "DraftText": null, 96 | "SubmittedText": "

Ich frage den Bundesrat, ob er für Vorhaben von erheblicher Tragweite nicht neue Formen der Vernehmlassung, namentlich bei den Kantonen, prüfen und beschliessen könnte.

Das geltende Verfahren, das auf schriftlichen Stellungnahmen beruht, gestattet keine aktive Präsentation derselben durch die Kantone und verunmöglicht somit die Kenntnisnahme seitens der anderen Kantone.

Diese Mängel könnten mit einem Anhörungsverfahren (Hearing) oder mit einer gemeinsamen Stellungnahme der Kantone, in welcher übereinstimmende sowie abweichende Standpunkte gekennzeichnet würden, beseitigt werden.

Der Vorschlag eines Kantons könnte somit auch die Zustimmung anderer Kantone finden, etwas, das bisher eher unwahrscheinlich scheint. Eine Zusammenstellung der Ergebnisse, jedoch nicht in einer tabellarischen Form, die die Interpretation der Verwaltung widerspiegelt, könnte für das Parlament und vor allem für seine Kommissionen von grossem Nutzen sein.

Hearings mit Simultanübersetzung von den und in die drei Landessprachen könnten das gegenseitige Verständnis fördern und würden ausserdem die Kantone in vermehrtem Mass in die politische Entscheidfindung auf Bundesebene einbeziehen.

", 97 | "ReasonText": null, 98 | "DocumentationText": null, 99 | "MotionText": null, 100 | "FederalCouncilResponseText": null, 101 | "FederalCouncilProposal": null, 102 | "FederalCouncilProposalText": null, 103 | "FederalCouncilProposalDate": null, 104 | "SubmittedBy": "Camponovo Geo", 105 | "BusinessStatus": 229, 106 | "BusinessStatusText": "Erledigt", 107 | "BusinessStatusDate": "/Date(762998400000)/", 108 | "ResponsibleDepartment": 10, 109 | "ResponsibleDepartmentName": "Bundeskanzlei", 110 | "ResponsibleDepartmentAbbreviation": "BK", 111 | "IsLeadingDepartment": true, 112 | "Tags": null, 113 | "Category": null, 114 | "Modified": "/Date(1688206412070)/", 115 | "SubmissionDate": "/Date(762998400000)/", 116 | "SubmissionCouncil": 1, 117 | "SubmissionCouncilName": "Nationalrat", 118 | "SubmissionCouncilAbbreviation": "NR", 119 | "SubmissionSession": 4413, 120 | "SubmissionLegislativePeriod": 44, 121 | "FirstCouncil1": 1, 122 | "FirstCouncil1Name": "Nationalrat", 123 | "FirstCouncil1Abbreviation": "NR", 124 | "FirstCouncil2": null, 125 | "FirstCouncil2Name": null, 126 | "FirstCouncil2Abbreviation": null, 127 | "TagNames": null 128 | }, 129 | { 130 | "__metadata": { 131 | "id": "https://ws.parlament.ch/OData.svc/Business(ID=19943085,Language='DE')", 132 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943085,Language='DE')", 133 | "type": "itsystems.Pd.DataServices.DataModel.Business" 134 | }, 135 | "BusinessResponsibilities": { 136 | "__deferred": { 137 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943085,Language='DE')/BusinessResponsibilities" 138 | } 139 | }, 140 | "RelatedBusinesses": { 141 | "__deferred": { 142 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943085,Language='DE')/RelatedBusinesses" 143 | } 144 | }, 145 | "BusinessRoles": { 146 | "__deferred": { 147 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943085,Language='DE')/BusinessRoles" 148 | } 149 | }, 150 | "Publications": { 151 | "__deferred": { 152 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943085,Language='DE')/Publications" 153 | } 154 | }, 155 | "LegislativePeriods": { 156 | "__deferred": { 157 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943085,Language='DE')/LegislativePeriods" 158 | } 159 | }, 160 | "Sessions": { 161 | "__deferred": { 162 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943085,Language='DE')/Sessions" 163 | } 164 | }, 165 | "Preconsultations": { 166 | "__deferred": { 167 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943085,Language='DE')/Preconsultations" 168 | } 169 | }, 170 | "Bills": { 171 | "__deferred": { 172 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943085,Language='DE')/Bills" 173 | } 174 | }, 175 | "Councils": { 176 | "__deferred": { 177 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943085,Language='DE')/Councils" 178 | } 179 | }, 180 | "BusinessTypes": { 181 | "__deferred": { 182 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943085,Language='DE')/BusinessTypes" 183 | } 184 | }, 185 | "Votes": { 186 | "__deferred": { 187 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943085,Language='DE')/Votes" 188 | } 189 | }, 190 | "SubjectsBusiness": { 191 | "__deferred": { 192 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943085,Language='DE')/SubjectsBusiness" 193 | } 194 | }, 195 | "BusinessStates": { 196 | "__deferred": { 197 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943085,Language='DE')/BusinessStates" 198 | } 199 | }, 200 | "Council": { 201 | "__deferred": { 202 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943085,Language='DE')/Council" 203 | } 204 | }, 205 | "Transcripts": { 206 | "__deferred": { 207 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943085,Language='DE')/Transcripts" 208 | } 209 | }, 210 | "ID": 19943085, 211 | "Language": "DE", 212 | "BusinessShortNumber": "94.3085", 213 | "BusinessType": 8, 214 | "BusinessTypeName": "Interpellation", 215 | "BusinessTypeAbbreviation": "Ip.", 216 | "Title": "Intensivierung des Eisenbahnverkehrs Schweiz-Italien", 217 | "Description": null, 218 | "InitialSituation": null, 219 | "Proceedings": null, 220 | "DraftText": null, 221 | "SubmittedText": "

Eine Koordinierung der Entwicklung zwischen Norditalien und der Schweiz im allgemeinen und zwischen der Lombardei und dem Kanton Tessin im besonderen ist für unsere Wirtschaft und unsere Umwelt von sehr grossem Interesse.

Der Wirtschaftsraum Norditalien gehört zu den technologisch fortschrittlichsten und dynamischsten Regionen in Europa.

Die Annahme der Alpen-Initiative zwingt die Schweiz, die Bemühungen zur Lösung der Probleme im Bereich der Bahntransporte und des multimodalen Verkehrs zwischen den beiden Ländern fortzusetzen. Die Entwicklung unserer Nachbarregionen kann durch Absatzschwierigkeiten gefährdet und unser Einbezug in die Entwicklungsdynamik, wie sie die Lombardei, Bayern und die Region Lyon kennen, gebremst werden, wenn nicht neue Lösungen gefunden werden.

Ich ersuche darum den Bundesrat um Auskunft auf die folgenden Fragen:

- Beabsichtigt er, die Kontakte mit Rom zu verstärken, um die Politik zur Entwicklung des Bahnverkehrs zu intensivieren?

- Gedenkt er den Kanton Tessin in den Bemühungen zur Konkretisierung seiner grenzübergreifenden Politik zu unterstützen?

- Ist er bereit, die Realisierung der \"Regione Insubrica\" (Insubrische Region, die den Kanton Tessin und die Provinzen Como, Varese und Novara umfasst) zu unterstützen?

- Will er nicht umgehend eine Lösung zur Weiterführung der Eisenbahnschnellverbindung durch den Gotthard bis zur italienischen Grenze mit Anschluss an die italienischen Bahnstrukturen und Einrichtungen für den multimodalen Verkehr vorschlagen?

", 222 | "ReasonText": null, 223 | "DocumentationText": null, 224 | "MotionText": null, 225 | "FederalCouncilResponseText": null, 226 | "FederalCouncilProposal": null, 227 | "FederalCouncilProposalText": null, 228 | "FederalCouncilProposalDate": null, 229 | "SubmittedBy": "Camponovo Geo", 230 | "BusinessStatus": 229, 231 | "BusinessStatusText": "Erledigt", 232 | "BusinessStatusDate": "/Date(762998400000)/", 233 | "ResponsibleDepartment": 9, 234 | "ResponsibleDepartmentName": "Departement für Umwelt, Verkehr, Energie und Kommunikation", 235 | "ResponsibleDepartmentAbbreviation": "UVEK", 236 | "IsLeadingDepartment": true, 237 | "Tags": null, 238 | "Category": null, 239 | "Modified": "/Date(1690529341910)/", 240 | "SubmissionDate": "/Date(762998400000)/", 241 | "SubmissionCouncil": 1, 242 | "SubmissionCouncilName": "Nationalrat", 243 | "SubmissionCouncilAbbreviation": "NR", 244 | "SubmissionSession": 4413, 245 | "SubmissionLegislativePeriod": 44, 246 | "FirstCouncil1": 1, 247 | "FirstCouncil1Name": "Nationalrat", 248 | "FirstCouncil1Abbreviation": "NR", 249 | "FirstCouncil2": null, 250 | "FirstCouncil2Name": null, 251 | "FirstCouncil2Abbreviation": null, 252 | "TagNames": null 253 | }, 254 | { 255 | "__metadata": { 256 | "id": "https://ws.parlament.ch/OData.svc/Business(ID=19943086,Language='DE')", 257 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943086,Language='DE')", 258 | "type": "itsystems.Pd.DataServices.DataModel.Business" 259 | }, 260 | "BusinessResponsibilities": { 261 | "__deferred": { 262 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943086,Language='DE')/BusinessResponsibilities" 263 | } 264 | }, 265 | "RelatedBusinesses": { 266 | "__deferred": { 267 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943086,Language='DE')/RelatedBusinesses" 268 | } 269 | }, 270 | "BusinessRoles": { 271 | "__deferred": { 272 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943086,Language='DE')/BusinessRoles" 273 | } 274 | }, 275 | "Publications": { 276 | "__deferred": { 277 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943086,Language='DE')/Publications" 278 | } 279 | }, 280 | "LegislativePeriods": { 281 | "__deferred": { 282 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943086,Language='DE')/LegislativePeriods" 283 | } 284 | }, 285 | "Sessions": { 286 | "__deferred": { 287 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943086,Language='DE')/Sessions" 288 | } 289 | }, 290 | "Preconsultations": { 291 | "__deferred": { 292 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943086,Language='DE')/Preconsultations" 293 | } 294 | }, 295 | "Bills": { 296 | "__deferred": { 297 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943086,Language='DE')/Bills" 298 | } 299 | }, 300 | "Councils": { 301 | "__deferred": { 302 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943086,Language='DE')/Councils" 303 | } 304 | }, 305 | "BusinessTypes": { 306 | "__deferred": { 307 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943086,Language='DE')/BusinessTypes" 308 | } 309 | }, 310 | "Votes": { 311 | "__deferred": { 312 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943086,Language='DE')/Votes" 313 | } 314 | }, 315 | "SubjectsBusiness": { 316 | "__deferred": { 317 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943086,Language='DE')/SubjectsBusiness" 318 | } 319 | }, 320 | "BusinessStates": { 321 | "__deferred": { 322 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943086,Language='DE')/BusinessStates" 323 | } 324 | }, 325 | "Council": { 326 | "__deferred": { 327 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943086,Language='DE')/Council" 328 | } 329 | }, 330 | "Transcripts": { 331 | "__deferred": { 332 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943086,Language='DE')/Transcripts" 333 | } 334 | }, 335 | "ID": 19943086, 336 | "Language": "DE", 337 | "BusinessShortNumber": "94.3086", 338 | "BusinessType": 8, 339 | "BusinessTypeName": "Interpellation", 340 | "BusinessTypeAbbreviation": "Ip.", 341 | "Title": "Eidg. Alkoholverwaltung", 342 | "Description": null, 343 | "InitialSituation": null, 344 | "Proceedings": null, 345 | "DraftText": null, 346 | "SubmittedText": "

Die Finanzkommission des Ständerates hat dem Bundesrat die drei folgenden Empfehlungen übermittelt:

\"1. Bei der Alkoholverwaltung fallen für die brennlose Verwertung von Obst und Kartoffeln Kosten von jährlich ungefähr 100 Millionen Franken an. Zur unverzüglichen Senkung dieser Kosten sind die garantierten Preise für Obst und Kartoffeln aufzuheben und durch Richtpreise zu ersetzen, die nach der Grösse der Ernte bestimmt werden.

2. Der Bundesrat wird eingeladen, in das nächste Sanierungsprogramm eine Änderung von Artikel 32bis Absatz 2 der Bundesverfassung sowie des Artikels 25 des Alkoholgesetzes aufzunehmen mit dem Ziel, den Aufkauf der Brennapparate einzustellen.

3. Der Bundesrat wird eingeladen, das Alkoholmonopol auf seine Berechtigung hin zu überprüfen und die finanzielle Unterstützung der brennlosen Verwertung von Obst und Kartoffeln zu streichen sowie die verfassungsrechtlichen und gesetzlichen Grundlagen entsprechend zu ändern. Nötigenfalls sieht er vor, dass die Alkoholverwaltung in die allgemeine Bundesverwaltung eingegliedert und rationalisiert wird.\"

Ich frage den Bundesrat:

1. ob er bei der Prüfung dieser Empfehlungen nur die Meinung der Alkoholverwaltung berücksichtigen wird oder ob er vor hat, auch die Meinung eines aussenstehenden Sachverständigengremiums einzuholen;

2. bis wann und wie er zu diesen Empfehlungen Stellung zu nehmen gedenkt.

", 347 | "ReasonText": null, 348 | "DocumentationText": null, 349 | "MotionText": null, 350 | "FederalCouncilResponseText": null, 351 | "FederalCouncilProposal": null, 352 | "FederalCouncilProposalText": null, 353 | "FederalCouncilProposalDate": null, 354 | "SubmittedBy": "Camponovo Geo", 355 | "BusinessStatus": 229, 356 | "BusinessStatusText": "Erledigt", 357 | "BusinessStatusDate": "/Date(762998400000)/", 358 | "ResponsibleDepartment": 7, 359 | "ResponsibleDepartmentName": "Finanzdepartement", 360 | "ResponsibleDepartmentAbbreviation": "EFD", 361 | "IsLeadingDepartment": true, 362 | "Tags": null, 363 | "Category": null, 364 | "Modified": "/Date(1690530850383)/", 365 | "SubmissionDate": "/Date(762998400000)/", 366 | "SubmissionCouncil": 1, 367 | "SubmissionCouncilName": "Nationalrat", 368 | "SubmissionCouncilAbbreviation": "NR", 369 | "SubmissionSession": 4413, 370 | "SubmissionLegislativePeriod": 44, 371 | "FirstCouncil1": 1, 372 | "FirstCouncil1Name": "Nationalrat", 373 | "FirstCouncil1Abbreviation": "NR", 374 | "FirstCouncil2": null, 375 | "FirstCouncil2Name": null, 376 | "FirstCouncil2Abbreviation": null, 377 | "TagNames": null 378 | }, 379 | { 380 | "__metadata": { 381 | "id": "https://ws.parlament.ch/OData.svc/Business(ID=19943087,Language='DE')", 382 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943087,Language='DE')", 383 | "type": "itsystems.Pd.DataServices.DataModel.Business" 384 | }, 385 | "BusinessResponsibilities": { 386 | "__deferred": { 387 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943087,Language='DE')/BusinessResponsibilities" 388 | } 389 | }, 390 | "RelatedBusinesses": { 391 | "__deferred": { 392 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943087,Language='DE')/RelatedBusinesses" 393 | } 394 | }, 395 | "BusinessRoles": { 396 | "__deferred": { 397 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943087,Language='DE')/BusinessRoles" 398 | } 399 | }, 400 | "Publications": { 401 | "__deferred": { 402 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943087,Language='DE')/Publications" 403 | } 404 | }, 405 | "LegislativePeriods": { 406 | "__deferred": { 407 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943087,Language='DE')/LegislativePeriods" 408 | } 409 | }, 410 | "Sessions": { 411 | "__deferred": { 412 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943087,Language='DE')/Sessions" 413 | } 414 | }, 415 | "Preconsultations": { 416 | "__deferred": { 417 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943087,Language='DE')/Preconsultations" 418 | } 419 | }, 420 | "Bills": { 421 | "__deferred": { 422 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943087,Language='DE')/Bills" 423 | } 424 | }, 425 | "Councils": { 426 | "__deferred": { 427 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943087,Language='DE')/Councils" 428 | } 429 | }, 430 | "BusinessTypes": { 431 | "__deferred": { 432 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943087,Language='DE')/BusinessTypes" 433 | } 434 | }, 435 | "Votes": { 436 | "__deferred": { 437 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943087,Language='DE')/Votes" 438 | } 439 | }, 440 | "SubjectsBusiness": { 441 | "__deferred": { 442 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943087,Language='DE')/SubjectsBusiness" 443 | } 444 | }, 445 | "BusinessStates": { 446 | "__deferred": { 447 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943087,Language='DE')/BusinessStates" 448 | } 449 | }, 450 | "Council": { 451 | "__deferred": { 452 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943087,Language='DE')/Council" 453 | } 454 | }, 455 | "Transcripts": { 456 | "__deferred": { 457 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943087,Language='DE')/Transcripts" 458 | } 459 | }, 460 | "ID": 19943087, 461 | "Language": "DE", 462 | "BusinessShortNumber": "94.3087", 463 | "BusinessType": 5, 464 | "BusinessTypeName": "Motion", 465 | "BusinessTypeAbbreviation": "Mo.", 466 | "Title": "Ausführungsbestimmungen zu Art. 36sexies BV. Nationalstrassengesetzgebung", 467 | "Description": null, 468 | "InitialSituation": null, 469 | "Proceedings": null, 470 | "DraftText": null, 471 | "SubmittedText": "

Die ganzheitliche Verkehrspolitik des Bundesrates und des Parlamentes erfährt nach der Annahme der Volksinitiative \"zum Schutz des Alpengebietes vor dem Transitverkehr\" durch das Volk und die Stände zwangsläufig eine bedeutende Neuorientierung.

Aufgrund dieser offensichtlichen Sachverhalte laden wir den Bundesrat ein, unter Bezugnahme auf die schriftlich hinterlegten Eingaben von Ständerat Bloetzer sowie der Nationalräte Comby, Epiney und Schmidhalter, im Rahmen der Ausarbeitung der Ausführungsbestimmungen zu Artikel 36sexies der Bundesverfassung alle Vorkehrungen zu treffen, damit

- die Rhonetalstrasse zwischen Siders und Brig nicht als Transitstrasse klassiert wird und somit die Realisierung der dringend notwendigen Autobahn im Oberwallis ermöglicht wird.

In zweiter Priorität ersuchen wir den Bundesrat zu veranlassen,

- die heute in Kraft stehende Nationalstrassengesetzgebung dahingehend zu ändern, dass in Landesteilen und Regionen, die nicht über ein Nationalstrassennetz verfügen, die Finanzierungsmöglichkeiten für die Hauptstrassenachsen denjenigen der Nationalstrassen gleichgestellt werden. Dies im Sinne eines gerechten Ausgleichs, der es auch benachteiligten Regionen ermöglicht, die dringenden Verkehrsprobleme zu lösen.

", 472 | "ReasonText": "

Bereits im Vorfeld des Urnenganges zur Alpen-Initiative wurde von verschiedener Seite auf die Schwierigkeiten bei der Interpretation des Initiativtextes hingewiesen. Bundesrat und Parlament stehen nun vor der heiklen Aufgabe, zu definieren, welche Strassen im Alpengebiet im Sinne der Alpeninitiative als Transitachsen zu bezeichnen sind.

Zuhanden des Bundesrates, namentlich des zuständigen Eidgenössischen Verkehrs- und Energiedepartementes, möchten wir zum Ausdruck bringen, dass der Transitverkehr zwischen Siders und Brig äusserst bescheiden ist. Dieses Strassenteilstück dient in allererster Linie dem Regional- und Lokalverkehr. Sehr zuverlässige Verkehrszählungen belegen diese Tatsachen.

Nur aufgrund der hier aufgezeigten Entscheide bzw. Massnahmen können regionale Ungerechtigkeiten verhindert werden, die letztlich auch garantieren, dass in den Bergkantonen zeitgemässe Strassen überhaupt zu realisieren sind, die eine wirtschaftliche und touristische Weiterentwicklung ermöglichen.

", 473 | "DocumentationText": null, 474 | "MotionText": null, 475 | "FederalCouncilResponseText": "Der Bundesrat beantragt, Teil 1 als erledigt abzuschreiben und Teil 2 in ein Postulat umzuwandeln.", 476 | "FederalCouncilProposal": null, 477 | "FederalCouncilProposalText": "Der Bundesrat beantragt, Teil 1 als erledigt abzuschreiben und Teil 2 in ein Postulat umzuwandeln.", 478 | "FederalCouncilProposalDate": "/Date(783734400000)/", 479 | "SubmittedBy": "Hildbrand Franz-Joseph", 480 | "BusinessStatus": 229, 481 | "BusinessStatusText": "Erledigt", 482 | "BusinessStatusDate": "/Date(819504000000)/", 483 | "ResponsibleDepartment": 9, 484 | "ResponsibleDepartmentName": "Departement für Umwelt, Verkehr, Energie und Kommunikation", 485 | "ResponsibleDepartmentAbbreviation": "UVEK", 486 | "IsLeadingDepartment": true, 487 | "Tags": null, 488 | "Category": null, 489 | "Modified": "/Date(1690521283527)/", 490 | "SubmissionDate": "/Date(763084800000)/", 491 | "SubmissionCouncil": 1, 492 | "SubmissionCouncilName": "Nationalrat", 493 | "SubmissionCouncilAbbreviation": "NR", 494 | "SubmissionSession": 4413, 495 | "SubmissionLegislativePeriod": 44, 496 | "FirstCouncil1": 1, 497 | "FirstCouncil1Name": "Nationalrat", 498 | "FirstCouncil1Abbreviation": "NR", 499 | "FirstCouncil2": null, 500 | "FirstCouncil2Name": null, 501 | "FirstCouncil2Abbreviation": null, 502 | "TagNames": null 503 | }, 504 | { 505 | "__metadata": { 506 | "id": "https://ws.parlament.ch/OData.svc/Business(ID=19943088,Language='DE')", 507 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943088,Language='DE')", 508 | "type": "itsystems.Pd.DataServices.DataModel.Business" 509 | }, 510 | "BusinessResponsibilities": { 511 | "__deferred": { 512 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943088,Language='DE')/BusinessResponsibilities" 513 | } 514 | }, 515 | "RelatedBusinesses": { 516 | "__deferred": { 517 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943088,Language='DE')/RelatedBusinesses" 518 | } 519 | }, 520 | "BusinessRoles": { 521 | "__deferred": { 522 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943088,Language='DE')/BusinessRoles" 523 | } 524 | }, 525 | "Publications": { 526 | "__deferred": { 527 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943088,Language='DE')/Publications" 528 | } 529 | }, 530 | "LegislativePeriods": { 531 | "__deferred": { 532 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943088,Language='DE')/LegislativePeriods" 533 | } 534 | }, 535 | "Sessions": { 536 | "__deferred": { 537 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943088,Language='DE')/Sessions" 538 | } 539 | }, 540 | "Preconsultations": { 541 | "__deferred": { 542 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943088,Language='DE')/Preconsultations" 543 | } 544 | }, 545 | "Bills": { 546 | "__deferred": { 547 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943088,Language='DE')/Bills" 548 | } 549 | }, 550 | "Councils": { 551 | "__deferred": { 552 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943088,Language='DE')/Councils" 553 | } 554 | }, 555 | "BusinessTypes": { 556 | "__deferred": { 557 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943088,Language='DE')/BusinessTypes" 558 | } 559 | }, 560 | "Votes": { 561 | "__deferred": { 562 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943088,Language='DE')/Votes" 563 | } 564 | }, 565 | "SubjectsBusiness": { 566 | "__deferred": { 567 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943088,Language='DE')/SubjectsBusiness" 568 | } 569 | }, 570 | "BusinessStates": { 571 | "__deferred": { 572 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943088,Language='DE')/BusinessStates" 573 | } 574 | }, 575 | "Council": { 576 | "__deferred": { 577 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943088,Language='DE')/Council" 578 | } 579 | }, 580 | "Transcripts": { 581 | "__deferred": { 582 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943088,Language='DE')/Transcripts" 583 | } 584 | }, 585 | "ID": 19943088, 586 | "Language": "DE", 587 | "BusinessShortNumber": "94.3088", 588 | "BusinessType": 5, 589 | "BusinessTypeName": "Motion", 590 | "BusinessTypeAbbreviation": "Mo.", 591 | "Title": "Korrektur der aussenpolitischen Ausrichtung", 592 | "Description": null, 593 | "InitialSituation": null, 594 | "Proceedings": null, 595 | "DraftText": null, 596 | "SubmittedText": "

Der Bundesrat wird beauftragt, seine aussenpolitische Strategie im Interesse unseres Landes vermehrt auf die weltweite Zusammenarbeit auszurichten und diese innenpolitisch abzustimmen.

In den Beziehungen mit der EU und den europäischen Staaten ist eine umfassende Kooperation auf der Basis von Solidarität und Gegenseitigkeit anzustreben. Dies bedeutet insbesondere:

- die Fortsetzung der Zusammenarbeit mit der EU ohne das strategische Ziel eines Beitritts;

- die Intensivierung der bilateralen Verhandlungen;

- die Offenhaltung des aussenpolitischen Handlungsspielraumes für die Zukunft, insbesondere auch gegenüber der EU;

- das Festhalten an der dauernden, bewaffneten Neutralität als aussenpolitischem Mittel zur Wahrung der Unabhängigkeit und Sicherheit unseres Landes.

", 597 | "ReasonText": null, 598 | "DocumentationText": null, 599 | "MotionText": null, 600 | "FederalCouncilResponseText": "

In seinem Bericht vom 29. November 1993 über die Aussenpolitik der Schweiz in den neunziger Jahren teilt der Bundesrat die Ansichten der Urheber der Motion hinsichtlich der Zielsetzung einer weltweiten, auf Solidarität und Gegenseitigkeit basierenden Zusammenarbeit.

Was die weltweite Zusammenarbeit angeht, so misst der Bundesrat dieser wie die Fraktion der Schweizerischen Volkspartei grosses Gewicht bei. Er unterscheidet indes zwischen dem europäischen und dem globalen Umfeld und verweist darauf, dass die geographische Lage eines jeden Landes bei der Verwirklichung von dessen aussenpolitischen Zielen einen bedeutenden Faktor darstellt.

Der Bundesrat ist ebenfalls der Ansicht, es bedürfe einer Harmonie zwischen Aussen- und Innenpolitik. In seinem Bericht widmet er diesem Aspekt ein Kapitel und unterstreicht dabei die Wichtigkeit, die er der besseren Information der Bevölkerung und der Verstärkung des Dialoges mit dem Parlament und den Kantonen beimisst.

Was die Beziehungen zwischen der Schweiz und der Europäischen Union angeht, so ist der Bundesrat um ein auf Solidarität und Gegenseitigkeit gestütztes Vorgehen bemüht. Er geht, wie die Motionäre, von der Notwendigkeit aus, einerseits die Zusammenarbeit mit der EU fortzusetzen und die bilateralen Verhandlungen zu intensivieren, andererseits aber den aussenpolitischen Handlungsspielraum zu bewahren sowie die dauernde und bewaffnete Neutralität beizubehalten.

Die Motionäre werden festgestellt haben, dass der Bundesrat seit Januar 1993 alles unternommen hat, um den bilateralen sektoriellen Verhandlungsprozess in Gang zu bringen. Dem Erfolg dieser Verhandlungen gilt sein ganzer Einsatz.

Der Bundesrat hält am EU-Beitritt als dem strategischen Ziel der Integrationspolitik fest. Die Gründe für diese Zielsetzung sind im Bericht über die Aussenpolitik der Schweiz in den neunziger Jahren enthalten, der im Parlament ausführlich diskutiert wurde.

Der Bundesrat beantragt, die Motion in ein Postulat umzuwandeln.", 601 | "FederalCouncilProposal": 2, 602 | "FederalCouncilProposalText": "Der Bundesrat beantragt, die Motion in ein Postulat umzuwandeln.", 603 | "FederalCouncilProposalDate": "/Date(790387200000)/", 604 | "SubmittedBy": "Fraktion der Schweizerischen Volkspartei", 605 | "BusinessStatus": 209, 606 | "BusinessStatusText": "Überwiesen an den Bundesrat", 607 | "BusinessStatusDate": "/Date(827280000000)/", 608 | "ResponsibleDepartment": 3, 609 | "ResponsibleDepartmentName": "Departement für auswärtige Angelegenheiten", 610 | "ResponsibleDepartmentAbbreviation": "EDA", 611 | "IsLeadingDepartment": true, 612 | "Tags": null, 613 | "Category": null, 614 | "Modified": "/Date(1690539249113)/", 615 | "SubmissionDate": "/Date(763171200000)/", 616 | "SubmissionCouncil": 1, 617 | "SubmissionCouncilName": "Nationalrat", 618 | "SubmissionCouncilAbbreviation": "NR", 619 | "SubmissionSession": 4413, 620 | "SubmissionLegislativePeriod": 44, 621 | "FirstCouncil1": 1, 622 | "FirstCouncil1Name": "Nationalrat", 623 | "FirstCouncil1Abbreviation": "NR", 624 | "FirstCouncil2": null, 625 | "FirstCouncil2Name": null, 626 | "FirstCouncil2Abbreviation": null, 627 | "TagNames": null 628 | }, 629 | { 630 | "__metadata": { 631 | "id": "https://ws.parlament.ch/OData.svc/Business(ID=19943089,Language='DE')", 632 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943089,Language='DE')", 633 | "type": "itsystems.Pd.DataServices.DataModel.Business" 634 | }, 635 | "BusinessResponsibilities": { 636 | "__deferred": { 637 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943089,Language='DE')/BusinessResponsibilities" 638 | } 639 | }, 640 | "RelatedBusinesses": { 641 | "__deferred": { 642 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943089,Language='DE')/RelatedBusinesses" 643 | } 644 | }, 645 | "BusinessRoles": { 646 | "__deferred": { 647 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943089,Language='DE')/BusinessRoles" 648 | } 649 | }, 650 | "Publications": { 651 | "__deferred": { 652 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943089,Language='DE')/Publications" 653 | } 654 | }, 655 | "LegislativePeriods": { 656 | "__deferred": { 657 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943089,Language='DE')/LegislativePeriods" 658 | } 659 | }, 660 | "Sessions": { 661 | "__deferred": { 662 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943089,Language='DE')/Sessions" 663 | } 664 | }, 665 | "Preconsultations": { 666 | "__deferred": { 667 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943089,Language='DE')/Preconsultations" 668 | } 669 | }, 670 | "Bills": { 671 | "__deferred": { 672 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943089,Language='DE')/Bills" 673 | } 674 | }, 675 | "Councils": { 676 | "__deferred": { 677 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943089,Language='DE')/Councils" 678 | } 679 | }, 680 | "BusinessTypes": { 681 | "__deferred": { 682 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943089,Language='DE')/BusinessTypes" 683 | } 684 | }, 685 | "Votes": { 686 | "__deferred": { 687 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943089,Language='DE')/Votes" 688 | } 689 | }, 690 | "SubjectsBusiness": { 691 | "__deferred": { 692 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943089,Language='DE')/SubjectsBusiness" 693 | } 694 | }, 695 | "BusinessStates": { 696 | "__deferred": { 697 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943089,Language='DE')/BusinessStates" 698 | } 699 | }, 700 | "Council": { 701 | "__deferred": { 702 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943089,Language='DE')/Council" 703 | } 704 | }, 705 | "Transcripts": { 706 | "__deferred": { 707 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943089,Language='DE')/Transcripts" 708 | } 709 | }, 710 | "ID": 19943089, 711 | "Language": "DE", 712 | "BusinessShortNumber": "94.3089", 713 | "BusinessType": 5, 714 | "BusinessTypeName": "Motion", 715 | "BusinessTypeAbbreviation": "Mo.", 716 | "Title": "Kläranlagen. Befreiung von der Anschlusspflicht bei Wegfall der Bundessubventionen", 717 | "Description": null, 718 | "InitialSituation": null, 719 | "Proceedings": null, 720 | "DraftText": null, 721 | "SubmittedText": "

In den Bergkantonen wird jeder Einwohner mit brutto 105 Franken im Jahr durch die Abwasserreinigung belastet - im Mittelland sind es 64 Franken. Ende 1993 waren im Schweizer Berggebiet noch 311 Gemeinden keiner Kläranlage angeschlossen - insgesamt sind rund 200 000 Einwohner ohne Anschluss. Praktisch alle nicht an Kläranlagen angeschlossenen Bewohner leben in dünnbesiedelten Gebieten. Nach Wegfall der Bundessubventionen werden in diesen Regionen die Kosten je Einwohner für einen Anschluss überdurchschnittlich hoch ausfallen und stehen in einem Missverhältnis zum bescheidenen ökologischen Nutzen.

Der Bundesrat wird deshalb beauftragt, dem Parlament die gesetzlichen Massnahmen vorzuschlagen, um die Bewohner der nicht an eine Kläranlage angeschlossenen Gebiete von der Anschlusspflicht zu befreien. Die Befreiung von der Anschlusspflicht soll gleichzeitig mit dem Wegfall der Bundessubventionen in Kraft treten.

", 722 | "ReasonText": null, 723 | "DocumentationText": null, 724 | "MotionText": null, 725 | "FederalCouncilResponseText": "

Nach Artikel 10 Absatz 1 des Gewässerschutzgesetzes vom 24. Januar 1991 (GSchG) sorgen die Kantone für die Erstellung öffentlicher Kanalisationen und zentraler Anlagen zur Reinigung von verschmutztem Abwasser. Artikel 10 Absatz 2 GSchG relativiert diese generelle Regelung: Danach können die Kantone in abgelegenen oder in dünnbesiedelten Gebieten das verschmutzte Abwasser durch andere Systeme als durch zentrale Abwasserreinigungsanlagen behandeln lassen, wenn damit der Schutz der ober- und unterirdischen Gewässer gewährleistet ist. In Frage kommen dabei namentlich Einzel- oder Gruppenreinigungsanlagen wie Dreikammergruben, Bodenfiltrationen, Abwasserteiche und Ableitungen des Abwassers in Güllebehälter.

Das Anliegen der Motion, in abgelegenen, dünnbesiedelten, vorab ländlichen Gebieten auf eine generelle Anschlusspflicht an zentrale Abwasserreinigungsanlagen zu verzichten, wird damit von der bestehenden Gesetzgebung bereits erfüllt. Die Anwendung von Artikel 10 Absatz 2 GSchG liegt bei den Kantonen. An ihnen liegt es, bei der Anwendung dieser Bestimmung geeignete Lösungen zu finden. Die Formulierung \"in abgelegenen oder in dünnbesiedelten Gebieten\" belässt den Kantonen einen hinreichenden Beurteilungs- und Entscheidungsspielraum, um die örtlichen Gegebenheiten, wie die Grösse und die Struktur der Siedlung, den Zustand der Gewässer und die finanzielle Tragbarkeit einer dezentralen Lösung, zu berücksichtigen.

Der Bundesrat hat davon Kenntnis genommen, dass einige Kantone Artikel 10 Absatz 2 GSchG in der Vergangenheit sehr eng interpretiert haben. Da das Gewässerschutzgesetz den Kantonen aber grundsätzlich die Möglichkeit bietet, das Anliegen der Motion zu erfüllen, erachtet es der Bundesrat als unzweckmässig, das erst seit kurzer Zeit geltende Gesetz zu ändern und die Voraussetzungen für die Befreiung von der Anschlusspflicht an zentrale Abwasserreinigungsanlagen auf Gesetzesstufe neu und näher zu konkretisieren.

Nach der Motion soll die Befreiung von der Anschlusspflicht gleichzeitig mit dem Wegfall der Bundessubventionen in Kraft treten. Mit der schnellen Behandlung der Sparmassnahmen 1993 hat das Parlament den Willen zum Ausdruck gebracht, diese Massnahmen rasch in Kraft zu setzen. Der Bundesrat will mit der Inkraftsetzung der Sparmassnahmen aber nicht so lange zuwarten, bis eine allfällige Änderung des Gewässerschutzgesetzes abgeschlossen ist. Auch aus diesem Grund lehnt er eine Gesetzesänderung ab.

", 726 | "FederalCouncilProposal": null, 727 | "FederalCouncilProposalText": null, 728 | "FederalCouncilProposalDate": null, 729 | "SubmittedBy": "Schnider Theodor", 730 | "BusinessStatus": 229, 731 | "BusinessStatusText": "Erledigt", 732 | "BusinessStatusDate": "/Date(763171200000)/", 733 | "ResponsibleDepartment": 4, 734 | "ResponsibleDepartmentName": "Departement des Innern", 735 | "ResponsibleDepartmentAbbreviation": "EDI", 736 | "IsLeadingDepartment": true, 737 | "Tags": null, 738 | "Category": null, 739 | "Modified": "/Date(1690539266890)/", 740 | "SubmissionDate": "/Date(763171200000)/", 741 | "SubmissionCouncil": 1, 742 | "SubmissionCouncilName": "Nationalrat", 743 | "SubmissionCouncilAbbreviation": "NR", 744 | "SubmissionSession": 4413, 745 | "SubmissionLegislativePeriod": 44, 746 | "FirstCouncil1": 1, 747 | "FirstCouncil1Name": "Nationalrat", 748 | "FirstCouncil1Abbreviation": "NR", 749 | "FirstCouncil2": null, 750 | "FirstCouncil2Name": null, 751 | "FirstCouncil2Abbreviation": null, 752 | "TagNames": null 753 | }, 754 | { 755 | "__metadata": { 756 | "id": "https://ws.parlament.ch/OData.svc/Business(ID=19943090,Language='DE')", 757 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943090,Language='DE')", 758 | "type": "itsystems.Pd.DataServices.DataModel.Business" 759 | }, 760 | "BusinessResponsibilities": { 761 | "__deferred": { 762 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943090,Language='DE')/BusinessResponsibilities" 763 | } 764 | }, 765 | "RelatedBusinesses": { 766 | "__deferred": { 767 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943090,Language='DE')/RelatedBusinesses" 768 | } 769 | }, 770 | "BusinessRoles": { 771 | "__deferred": { 772 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943090,Language='DE')/BusinessRoles" 773 | } 774 | }, 775 | "Publications": { 776 | "__deferred": { 777 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943090,Language='DE')/Publications" 778 | } 779 | }, 780 | "LegislativePeriods": { 781 | "__deferred": { 782 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943090,Language='DE')/LegislativePeriods" 783 | } 784 | }, 785 | "Sessions": { 786 | "__deferred": { 787 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943090,Language='DE')/Sessions" 788 | } 789 | }, 790 | "Preconsultations": { 791 | "__deferred": { 792 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943090,Language='DE')/Preconsultations" 793 | } 794 | }, 795 | "Bills": { 796 | "__deferred": { 797 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943090,Language='DE')/Bills" 798 | } 799 | }, 800 | "Councils": { 801 | "__deferred": { 802 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943090,Language='DE')/Councils" 803 | } 804 | }, 805 | "BusinessTypes": { 806 | "__deferred": { 807 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943090,Language='DE')/BusinessTypes" 808 | } 809 | }, 810 | "Votes": { 811 | "__deferred": { 812 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943090,Language='DE')/Votes" 813 | } 814 | }, 815 | "SubjectsBusiness": { 816 | "__deferred": { 817 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943090,Language='DE')/SubjectsBusiness" 818 | } 819 | }, 820 | "BusinessStates": { 821 | "__deferred": { 822 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943090,Language='DE')/BusinessStates" 823 | } 824 | }, 825 | "Council": { 826 | "__deferred": { 827 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943090,Language='DE')/Council" 828 | } 829 | }, 830 | "Transcripts": { 831 | "__deferred": { 832 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943090,Language='DE')/Transcripts" 833 | } 834 | }, 835 | "ID": 19943090, 836 | "Language": "DE", 837 | "BusinessShortNumber": "94.3090", 838 | "BusinessType": 8, 839 | "BusinessTypeName": "Interpellation", 840 | "BusinessTypeAbbreviation": "Ip.", 841 | "Title": "Künstlich aufgeblähte Teuerung", 842 | "Description": null, 843 | "InitialSituation": null, 844 | "Proceedings": null, 845 | "DraftText": null, 846 | "SubmittedText": "

1. Will der Bundesrat es dulden, dass den Arbeitnehmern weiterhin eine künstliche Teuerung vorgerechnet wird, obwohl viele von ihnen überhaupt keinen Teuerungsausgleich erhalten haben?

2. Ist der Bundesrat nicht auch der Meinung, dass in der politisch brisanten Mietzinsfrage nur tatsächliche Preisveränderungen ausgewiesen werden sollten und dass jede auf fragwürdigen theoretischen Annahmen beruhende Aufblähung zu unterbleiben hat?

", 847 | "ReasonText": "

Gemäss Mitteilung des Bundesamtes für Statistik ist das Mietpreisniveau zwischen November 1993 und Februar 1994 praktisch stabil geblieben. Trotzdem erhöhte sich der Mietpreisindex infolge der Berechnungsweise um 0,9 Prozent.

Aufgrund des grossen Gewichtes der Wohnungsmiete im Warenkorb (etwa 25 Prozent) bedeutet dies, dass der Landesindex der Konsumentenpreise automatisch um rund 0,2 Prozentpunkte steigt, obwohl sich die Mietpreise nicht verändert haben, wie das Bundesamt für Statistik selber feststellt.

Das Bundesamt begründet dies damit, dass die altersbedingte Wertminderung des Wohnungsbestandes künstlich ausgeglichen werden müsse. Die Altersentwertung übersteige den Einfluss wertvermehrender baulicher Massnahmen.

Diese Behauptung widerspricht jeder Erfahrung. In der Schweiz kann in keiner Weise von der Verslummung des Wohnungsbestandes die Rede sein. Vielmehr befinden sich die Schweizer Mietliegenschaften aufgrund der gewaltigen Anstrengungen der vorwiegend privaten Eigentümer in bezug auf Renovationen und Modernisierungen in einem - im weltweiten Vergleich - exzellenten Zustand.

", 848 | "DocumentationText": null, 849 | "MotionText": null, 850 | "FederalCouncilResponseText": "

Die im Rahmen des Landesindexes der Konsumentenpreise ausgewiesene Teuerung wird nach international anerkannten Methoden sowie nach von der vormaligen Kommission für Konjunktur- und Sozialstatistik (Kokos) erarbeiteten und vom Bundesrat gutgeheissenen Grundsätzen berechnet.

Damit im Landesindex die reine Preisentwicklung gemessen werden kann, müssen die einbezogenen Waren und Dienstleistungen im Zeitablauf qualitativ vergleichbar sein, denn Qualitätsveränderungen sind \"versteckte\" Preisänderungen, die bei der Indexberechnung nicht ausser acht gelassen werden dürfen. Dieser Grundsatz der Indexberechnung gilt für alle im Landesindex einbezogenen Waren und Dienstleistungen.

Der als Teil des Landesindexes berechnete Mietpreisindex soll die Entwicklung des gesamtschweizerischen Mietpreisniveaus messen. Diese Entwicklung wird einerseits beeinflusst durch Mietzinsanpassungen bei den bestehenden Wohnungen, anderseits durch das kostenbedingt veränderte Niveau der Anfangsmieten von neuerstellten Wohnungen. Neben diesen beiden Einflussfaktoren ist auch allfälligen Qualitätsveränderungen Rechnung zu tragen.

Bei den meisten im Index-Warenkorb enthaltenen, gekauften Gütern handelt es sich um neuwertige und damit qualitativ vergleichbare Produkte. Die Qualität von (gemieteten) Wohnungen indessen ist einer ständigen Veränderung unterworfen. Einerseits nimmt sie in Folge fortschreitender Alterung ab, andererseits wird sie durch Renovationen, Um- und Neubauten verbessert.

Um den Einflüssen der sich verändernden Anfangsmieten von neuerstellten Wohnungen und der altersbedingten Wertverminderung Rechnung zu tragen, werden im Zeitablauf nicht die Mieten der einzelnen Wohnungen, sondern von Wohnungen gleicher Grösse und gleichen Alters verglichen. Einmal im Jahr, jeweils am Jahresanfang, werden die Wohnungen den Altersgruppen neu zugeteilt. Mit dieser Neuzuteilung werden die Einflüsse der im Zeitablauf sich verändernden Anfangsmieten und der im jeweils vergangenen Jahr aufgelaufenen Qualitätsverminderungen indexwirksam. Das hat dazu geführt, dass der Mietindex im Februar 1994 um 0,9 Prozent angestiegen ist, obschon die Situation bezüglich expliziten Mietzinsanpassungen praktisch stabil war. Aufgrund der Tatsache, dass sich die Anfangsmieten für neue Wohnungen wegen steigender Erstellungs- und Unterhaltskosten in den letzten Jahren stets erhöht haben (Anstieg des allgemeinen Mietpreisniveaus), wird dieser Effekt noch einige Zeit eine indexerhöhende Wirkung haben. In Perioden mit sinkenden Kosten und entsprechend tieferen Anfangsmieten wird sich eine indexsenkende Wirkung einstellen.

Wertvermehrende bauliche Massnahmen werden im Index ebenfalls berücksichtigt, indem die Mieten solcher Wohnungen mit Mieten von Wohnungen neuerer Baujahre verglichen werden, was in der Regel mit einem Indexrückgang verbunden ist.

Das Bundesamt für Statistik hat sich in diesem Zusammenhang nie dahin gehend geäussert, dass die Altersentwertung den \"Einfluss wertvermehrender baulicher Massnahmen\" übersteige, wie in der Begründung der Interpellation ausgeführt wird. Auch ist dem für die Berechnung angewandten methodischen Ansatz keine solche Annahme unterstellt, da Qualitätsveränderungen in beide Richtungen berücksichtigt werden.

In diesem Sinne lassen sich die beiden Fragen der Interpellation wie folgt beantworten:

1. Die Messung und die Bekanntgabe der Teuerung durch das Bundesamt für Statistik erfolgen nach den geltenden, vom Bundesrat gutgeheissenen Methoden und Grundsätzen. Sie sind unabhängig davon, ob die Arbeitnehmer einen Teuerungsausgleich erhalten haben oder nicht. Es soll nichts Künstliches vorgemacht, aber auch nichts Tatsächliches verschwiegen werden. Das Messinstrument \"Landesindex\" darf nicht aus politischen Motiven verändert oder gar manipuliert werden, weil damit der objektive Charakter verlorenginge. Aus diesem Grunde sind die Messung der Teuerung (Berechnung des Landesindexes) und die Anwendung des Indexes, welche im Verantwortungsbereich der jeweiligen Vertragspartner liegt, streng auseinanderzuhalten.

2. Die Berechnung des \"alten\" Mietpreisindexes (gültig bis Mai 1993) ist in der Vergangenheit wiederholt kritisiert worden. Es wurde unter anderem beanstandet, dass die angewandte Berechnungsmethode für den Einbezug neuerstellter Wohnungen sowie die methodische Behandlung von Qualitätsunterschieden bzw. Qualitätsveränderungen Mängel aufweisen und die tatsächlichen Verhältnisse nicht wirklichkeitsgetreu wiedergeben würden. Wegen der erheblichen politischen Bedeutung der Mietpreise und ihrer Entwicklung wurde deshalb der Verbesserung der Berechnungsmethode für den Mietpreisindex im Rahmen der kürzlich abgeschlossenen Indexrevision grosse Beachtung geschenkt. Der erarbeitete Lösungsvorschlag wurde von der Kokos gutgeheissen und dem Bundesrat zur Annahme empfohlen.

Es ist ein methodischer Ansatz gefunden worden, der gleichzeitig für den Einbezug neuerstellter Wohnungen wie für die Behandlung von Qualitätsveränderungen eine Lösung anbietet. Dabei ist unbestritten, dass es sich hier nicht um den einzig richtigen und idealen, sondern um einen bestmöglichen und praktikablen Ansatz handelt. Eine auch in der Erhebungspraxis anwendbare Methode zur wissenschaftlich exakten Quantifizierung von Qualitätsunterschieden bei Wohnungen steht leider zurzeit nicht zur Verfügung.

Dass nicht nur die bei bestehenden Wohnungen vorgenommenen Mietzinsanpassungen, sondern auch die sich verändernden Anfangsmieten und die Qualitätsveränderungen einen Einfluss auf den berechneten Mietpreisindex haben, entspricht der erklärten Zielsetzung, die Entwicklung des gesamtschweizerischen Mietpreisniveaus zu messen. Die verwendete Methode entspricht auch den allgemeinen Berechnungsgrundsätzen des Landesindexes.

", 851 | "FederalCouncilProposal": null, 852 | "FederalCouncilProposalText": null, 853 | "FederalCouncilProposalDate": null, 854 | "SubmittedBy": "Gysin Hans Rudolf", 855 | "BusinessStatus": 229, 856 | "BusinessStatusText": "Erledigt", 857 | "BusinessStatusDate": "/Date(763257600000)/", 858 | "ResponsibleDepartment": 4, 859 | "ResponsibleDepartmentName": "Departement des Innern", 860 | "ResponsibleDepartmentAbbreviation": "EDI", 861 | "IsLeadingDepartment": true, 862 | "Tags": null, 863 | "Category": null, 864 | "Modified": "/Date(1690489751197)/", 865 | "SubmissionDate": "/Date(763257600000)/", 866 | "SubmissionCouncil": 1, 867 | "SubmissionCouncilName": "Nationalrat", 868 | "SubmissionCouncilAbbreviation": "NR", 869 | "SubmissionSession": 4413, 870 | "SubmissionLegislativePeriod": 44, 871 | "FirstCouncil1": 1, 872 | "FirstCouncil1Name": "Nationalrat", 873 | "FirstCouncil1Abbreviation": "NR", 874 | "FirstCouncil2": null, 875 | "FirstCouncil2Name": null, 876 | "FirstCouncil2Abbreviation": null, 877 | "TagNames": null 878 | }, 879 | { 880 | "__metadata": { 881 | "id": "https://ws.parlament.ch/OData.svc/Business(ID=19943091,Language='DE')", 882 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943091,Language='DE')", 883 | "type": "itsystems.Pd.DataServices.DataModel.Business" 884 | }, 885 | "BusinessResponsibilities": { 886 | "__deferred": { 887 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943091,Language='DE')/BusinessResponsibilities" 888 | } 889 | }, 890 | "RelatedBusinesses": { 891 | "__deferred": { 892 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943091,Language='DE')/RelatedBusinesses" 893 | } 894 | }, 895 | "BusinessRoles": { 896 | "__deferred": { 897 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943091,Language='DE')/BusinessRoles" 898 | } 899 | }, 900 | "Publications": { 901 | "__deferred": { 902 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943091,Language='DE')/Publications" 903 | } 904 | }, 905 | "LegislativePeriods": { 906 | "__deferred": { 907 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943091,Language='DE')/LegislativePeriods" 908 | } 909 | }, 910 | "Sessions": { 911 | "__deferred": { 912 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943091,Language='DE')/Sessions" 913 | } 914 | }, 915 | "Preconsultations": { 916 | "__deferred": { 917 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943091,Language='DE')/Preconsultations" 918 | } 919 | }, 920 | "Bills": { 921 | "__deferred": { 922 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943091,Language='DE')/Bills" 923 | } 924 | }, 925 | "Councils": { 926 | "__deferred": { 927 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943091,Language='DE')/Councils" 928 | } 929 | }, 930 | "BusinessTypes": { 931 | "__deferred": { 932 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943091,Language='DE')/BusinessTypes" 933 | } 934 | }, 935 | "Votes": { 936 | "__deferred": { 937 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943091,Language='DE')/Votes" 938 | } 939 | }, 940 | "SubjectsBusiness": { 941 | "__deferred": { 942 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943091,Language='DE')/SubjectsBusiness" 943 | } 944 | }, 945 | "BusinessStates": { 946 | "__deferred": { 947 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943091,Language='DE')/BusinessStates" 948 | } 949 | }, 950 | "Council": { 951 | "__deferred": { 952 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943091,Language='DE')/Council" 953 | } 954 | }, 955 | "Transcripts": { 956 | "__deferred": { 957 | "uri": "https://ws.parlament.ch/OData.svc/Business(ID=19943091,Language='DE')/Transcripts" 958 | } 959 | }, 960 | "ID": 19943091, 961 | "Language": "DE", 962 | "BusinessShortNumber": "94.3091", 963 | "BusinessType": 5, 964 | "BusinessTypeName": "Motion", 965 | "BusinessTypeAbbreviation": "Mo.", 966 | "Title": "Ausdruck der Abstimmungsergebnisse", 967 | "Description": null, 968 | "InitialSituation": null, 969 | "Proceedings": null, 970 | "DraftText": null, 971 | "SubmittedText": "

Nachdem im Nationalrat die elektronische Abstimmung eingeführt worden ist, wird das Büro beauftragt, Artikel 81a des Ratsreglementes wie folgt zu ändern:

Grundsätzlich sind alle Abstimmungsergebnisse zu veröffentlichen.

", 972 | "ReasonText": "

Die Einführung der elektronischen Abstimmung erlaubt eine rasche Feststellung des Abstimmungsergebnisses. Zur Herstellung völliger Transparenz ist es richtig, wenn die Abstimmungslisten nicht nur selektiv aufgrund des Verlangens von 30 Ratsmitgliedern erstellt werden, sondern grundsätzlich das Ergebnis jeder Abstimmung ausgedruckt wird.

", 973 | "DocumentationText": null, 974 | "MotionText": null, 975 | "FederalCouncilResponseText": null, 976 | "FederalCouncilProposal": null, 977 | "FederalCouncilProposalText": null, 978 | "FederalCouncilProposalDate": null, 979 | "SubmittedBy": "Nabholz Lili", 980 | "BusinessStatus": 210, 981 | "BusinessStatusText": "Überwiesen an das Ratsbüro", 982 | "BusinessStatusDate": "/Date(763171200000)/", 983 | "ResponsibleDepartment": 1, 984 | "ResponsibleDepartmentName": "Parlament", 985 | "ResponsibleDepartmentAbbreviation": "Parl", 986 | "IsLeadingDepartment": true, 987 | "Tags": null, 988 | "Category": null, 989 | "Modified": "/Date(1688206412070)/", 990 | "SubmissionDate": "/Date(763171200000)/", 991 | "SubmissionCouncil": 1, 992 | "SubmissionCouncilName": "Nationalrat", 993 | "SubmissionCouncilAbbreviation": "NR", 994 | "SubmissionSession": 4413, 995 | "SubmissionLegislativePeriod": 44, 996 | "FirstCouncil1": 1, 997 | "FirstCouncil1Name": "Nationalrat", 998 | "FirstCouncil1Abbreviation": "NR", 999 | "FirstCouncil2": null, 1000 | "FirstCouncil2Name": null, 1001 | "FirstCouncil2Abbreviation": null, 1002 | "TagNames": null 1003 | } 1004 | ], 1005 | "__count": "52" 1006 | } 1007 | } 1008 | --------------------------------------------------------------------------------