{"id":16741372,"url":"https://github.com/metaodi/swissparlpy","last_synced_at":"2025-03-21T22:31:35.053Z","repository":{"id":42664418,"uuid":"410685015","full_name":"metaodi/swissparlpy","owner":"metaodi","description":"Wrapper for the Swiss Parliament API for Python","archived":false,"fork":false,"pushed_at":"2023-10-13T15:01:25.000Z","size":728,"stargazers_count":17,"open_issues_count":3,"forks_count":2,"subscribers_count":4,"default_branch":"develop","last_synced_at":"2025-03-18T05:34:57.169Z","etag":null,"topics":["api","api-wrapper","parliament","swiss","swissparl"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/metaodi.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-09-26T23:25:28.000Z","updated_at":"2024-07-03T16:19:04.000Z","dependencies_parsed_at":"2023-10-13T16:53:00.457Z","dependency_job_id":"a1de5299-cd05-4fe8-9e97-9f69385b21c1","html_url":"https://github.com/metaodi/swissparlpy","commit_stats":{"total_commits":72,"total_committers":3,"mean_commits":24.0,"dds":0.4722222222222222,"last_synced_commit":"7f9e34b5127e2fab591e1a4f4bc1f7db5cff096f"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metaodi%2Fswissparlpy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metaodi%2Fswissparlpy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metaodi%2Fswissparlpy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metaodi%2Fswissparlpy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/metaodi","download_url":"https://codeload.github.com/metaodi/swissparlpy/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244880231,"owners_count":20525505,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","api-wrapper","parliament","swiss","swissparl"],"created_at":"2024-10-13T01:01:26.080Z","updated_at":"2025-03-21T22:31:34.231Z","avatar_url":"https://github.com/metaodi.png","language":"Python","funding_links":[],"categories":["Politik \u0026 Demokratie"],"sub_categories":[],"readme":"[![PyPI Version][pypi-image]][pypi-url]\n[![Build Status][build-image]][build-url]\n[![Code style: black][black-image]][black-url]\n[![pre-commit][pre-commit-image]][pre-commit-url]\n\n\nswissparlpy\n===========\n\nThis 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).\n\n## Table of Contents\n\n* [Installation](#installation)\n* [Usage](#usage)\n    * [Get tables and their variables](#get-tables-and-their-variables)\n    * [Get data of a table](#get-data-of-a-table)\n    * [Use together with `pandas`](#use-together-with-pandas)\n    * [Substrings](#substrings)\n    * [Date ranges](#date-ranges)\n    * [Advanced filter](#advanced-filter)\n    * [Large queries](#large-queries)\n    * [API documentation](#documentation)\n    * [Similar libraries for other languages](#similar-libraries-for-other-languages)\n* [Credits](#credits)\n* [Development](#development)\n* [Release](#release)\n\n## Installation\n\n[swissparlpy is available on PyPI](https://pypi.org/project/swissparlpy/), so to install it simply use:\n\n```\n$ pip install swissparlpy\n```\n\n## Usage\n\nSee the [`examples` directory](/examples) for more scripts.\n\n### Get tables and their variables\n\n```python\n\u003e\u003e\u003e import swissparlpy as spp\n\u003e\u003e\u003e spp.get_tables()[:5] # get first 5 tables\n['MemberParty', 'Party', 'Person', 'PersonAddress', 'PersonCommunication']\n\u003e\u003e\u003e spp.get_variables('Party') # get variables of table `Party`\n['ID', 'Language', 'PartyNumber', 'PartyName', 'StartDate', 'EndDate', 'Modified', 'PartyAbbreviation']\n```\n\n### Get data of a table\n\n```python\n\u003e\u003e\u003e import swissparlpy as spp\n\u003e\u003e\u003e data = spp.get_data('Canton', Language='DE')\n\u003e\u003e\u003e data\n\u003cswissparlpy.client.SwissParlResponse object at 0x7f8e38baa610\u003e\n\u003e\u003e\u003e data.count\n26\n\u003e\u003e\u003e data[0]\n{'ID': 2, 'Language': 'DE', 'CantonNumber': 2, 'CantonName': 'Bern', 'CantonAbbreviation': 'BE'}\n\u003e\u003e\u003e [d['CantonName'] for d in data]\n['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']\n```\n\nThe 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.\n\nEven [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\n\n```python\nfor rec in data[:5]:\n   print(rec)\n```\n\n### Use together with `pandas`\n\nTo create a pandas DataFrame from `get_data` simply pass the return value to the constructor:\n\n```python\n\u003e\u003e\u003e import swissparlpy as spp\n\u003e\u003e\u003e import pandas as pd\n\u003e\u003e\u003e parties = spp.get_data('Party', Language='DE')\n\u003e\u003e\u003e parties_df = pd.DataFrame(parties)\n\u003e\u003e\u003e parties_df\n      ID Language  PartyNumber  ...                   EndDate                         Modified PartyAbbreviation\n0     12       DE           12  ... 2000-01-01 00:00:00+00:00 2010-12-26 13:05:26.430000+00:00                SP\n1     13       DE           13  ... 2000-01-01 00:00:00+00:00 2010-12-26 13:05:26.430000+00:00               SVP\n2     14       DE           14  ... 2000-01-01 00:00:00+00:00 2010-12-26 13:05:26.430000+00:00               CVP\n3     15       DE           15  ... 2000-01-01 00:00:00+00:00 2010-12-26 13:05:26.430000+00:00      FDP-Liberale\n4     16       DE           16  ... 2000-01-01 00:00:00+00:00 2010-12-26 13:05:26.430000+00:00               LDP\n..   ...      ...          ...  ...                       ...                              ...               ...\n78  1582       DE         1582  ... 2000-01-01 00:00:00+00:00 2015-12-03 08:48:38.250000+00:00             BastA\n79  1583       DE         1583  ... 2000-01-01 00:00:00+00:00 2019-03-07 17:24:15.013000+00:00              CVPO\n80  1584       DE         1584  ... 2000-01-01 00:00:00+00:00 2019-11-08 17:28:43.947000+00:00                Al\n81  1585       DE         1585  ... 2000-01-01 00:00:00+00:00 2019-11-08 17:41:39.513000+00:00               EàG\n82  1586       DE         1586  ... 2000-01-01 00:00:00+00:00 2021-08-12 07:59:22.627000+00:00               M-E\n\n[83 rows x 8 columns]\n```\n\n### Substrings\n\nIf you want to query for substrings there are two main operators to use:\n\n**`__startswith`**:\n\n```python\n\u003e\u003e\u003e import swissparlpy as spp\n\u003e\u003e\u003e persons = spp.get_data(\"Person\", Language=\"DE\", LastName__startswith='Bal')\n\u003e\u003e\u003e persons.count\n12\n```\n\n**`__contains`**\n```python\n\u003e\u003e\u003e import swissparlpy as spp\n\u003e\u003e\u003e co2_business = spp.get_data(\"Business\", Title__contains=\"CO2\", Language = \"DE\")\n\u003e\u003e\u003e co2_business.count\n265\n```\n\nYou can suffix any field with those operators to query the data.\n\n### Date ranges\n\nTo query for date ranges you can use the operators...\n\n* `__gt` (greater than)\n* `__gte` (greater than or equal)\n* `__lt` (less than)\n* `__lte` (less than or equal)\n\n...in combination with a `datetime` object.\n\n```python\n\u003e\u003e\u003e import swissparlpy as spp\n\u003e\u003e\u003e from datetime import datetime\n\u003e\u003e\u003e business = spp.get_data(\n...     \"Business\",\n...     Language=\"DE\",\n...     SubmissionDate__gt=datetime.fromisoformat('2019-09-30'),\n...     SubmissionDate__lte=datetime.fromisoformat('2019-10-31')\n... )\n\u003e\u003e\u003e business.count\n22\n```\n\n### Advanced filter\n\n**Text query**\n\nIt'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`:\n\n```python\nimport swissparlpy as spp\nimport pandas as pd\n   \npersons = spp.get_data(\n   \"Person\",\n   filter=\"(startswith(FirstName, 'Ste') or LastName eq 'Seiler') and Language eq 'DE'\"\n)\n\ndf = pd.DataFrame(persons)\nprint(df[['FirstName', 'LastName']])\n```\n\n**Callable Filter**\n\nYou can provide a callable as a filter which allows for more advanced filters.\n\n`swissparlpy.filter` provides `or_` and `and_`.\n\n```python\nimport swissparlpy as spp\nimport pandas as pd\n\n# filter by FirstName = 'Stefan' OR LastName == 'Seiler'\ndef filter_by_name(ent):\n   return spp.filter.or_(\n      ent.FirstName == 'Stefan',\n      ent.LastName == 'Seiler'\n   )\n   \npersons = spp.get_data(\"Person\", filter=filter_by_name, Language='DE')\n\ndf = pd.DataFrame(persons)\nprint(df[['FirstName', 'LastName']])\n```\n\n### Large queries\n\nLarge 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.\n\nThis 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`:\n\n```python\nimport swissparlpy as spp\nimport pandas as pd\nimport os\n\n__location__ = os.path.realpath(os.getcwd())\npath = os.path.join(__location__, \"voting50\")\n\n# download votes of one session and save as pickled DataFrame\ndef save_votes_of_session(id, path):\n    if not os.path.exists(path):\n        os.mkdir(path)\n    data = spp.get_data(\"Voting\", Language=\"DE\", IdSession=id)\n    print(f\"{data.count} rows loaded.\")\n    df = pd.DataFrame(data)\n    pickle_path = os.path.join(path, f'{id}.pks')\n    df.to_pickle(pickle_path)\n    print(f\"Saved pickle at {pickle_path}\")\n\n\n# get all session of the 50 legislative period\nsessions50 = spp.get_data(\"Session\", Language=\"DE\", LegislativePeriodNumber=50)\nsessions50.count\n\nfor session in sessions50:\n    print(f\"Loading session {session['ID']}\")\n    save_votes_of_session(session['ID'], path)\n\n# Combine to one dataframe\ndf_voting50 = pd.concat([pd.read_pickle(os.path.join(path, x)) for x in os.listdir(path)])\n```\n\n### Documentation\n\nThe 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.\nThe documentation can indeed be recreated using [dbdiagram.io](https://dbdiagram.io/home).\n\nBelow is a first look of what the dependencies are between the tables contained in the API:\n\n![db diagram of swiss parliament API](/docs/swissparAPY_diagram.png \"db diagram of swiss parliament API\")\n\n### Similar libraries for other languages\n\n* R: [zumbov2/swissparl](https://github.com/zumbov2/swissparl)\n* JavaScript: [michaelschoenbaechler/swissparl](https://github.com/michaelschoenbaechler/swissparl)\n\n## Credits\n\nThis library is inspired by the R package [swissparl](https://github.com/zumbov2/swissparl) of [David Zumbach](https://github.com/zumbov2).\n[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.\n\n## Development\n\nTo develop on this project, install `flit`:\n\n```\npip install flit\nflit install -s\n```\n\n## Release\n\nTo create a new release, follow these steps (please respect [Semantic Versioning](http://semver.org/)):\n\n1. Adapt the version number in `swissparlpy/__init__.py`\n1. Update the CHANGELOG with the version\n1. Create a [pull request to merge `develop` into `main`](https://github.com/metaodi/swissparlpy/compare/main...develop?expand=1) (make sure the tests pass!)\n1. Create a [new release/tag on GitHub](https://github.com/metaodi/swissparlpy/releases) (on the main branch)\n1. 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\n\n\n\u003c!-- Badges --\u003e\n[pypi-image]: https://img.shields.io/pypi/v/swissparlpy\n[pypi-url]: https://pypi.org/project/swissparlpy/\n[build-image]: https://github.com/metaodi/swissparlpy/actions/workflows/build.yml/badge.svg\n[build-url]: https://github.com/metaodi/swissparlpy/actions/workflows/build.yml\n[black-image]: https://img.shields.io/badge/code%20style-black-000000.svg\n[black-url]: https://github.com/psf/black\n[pre-commit-image]: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit\n[pre-commit-url]: https://github.com/pre-commit/pre-commit\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetaodi%2Fswissparlpy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmetaodi%2Fswissparlpy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetaodi%2Fswissparlpy/lists"}