infosoud 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- infosoud-0.1.0/LICENSE +21 -0
- infosoud-0.1.0/PKG-INFO +148 -0
- infosoud-0.1.0/README.md +127 -0
- infosoud-0.1.0/infosoud/__init__.py +3 -0
- infosoud-0.1.0/infosoud/__main__.py +165 -0
- infosoud-0.1.0/infosoud/client.py +329 -0
- infosoud-0.1.0/infosoud.egg-info/PKG-INFO +148 -0
- infosoud-0.1.0/infosoud.egg-info/SOURCES.txt +12 -0
- infosoud-0.1.0/infosoud.egg-info/dependency_links.txt +1 -0
- infosoud-0.1.0/infosoud.egg-info/entry_points.txt +2 -0
- infosoud-0.1.0/infosoud.egg-info/requires.txt +4 -0
- infosoud-0.1.0/infosoud.egg-info/top_level.txt +1 -0
- infosoud-0.1.0/pyproject.toml +30 -0
- infosoud-0.1.0/setup.cfg +4 -0
infosoud-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 pravnikovo.info
|
|
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 all
|
|
13
|
+
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 THE
|
|
21
|
+
SOFTWARE.
|
infosoud-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: infosoud
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Czech court case lookup tool (infosoud.gov.cz)
|
|
5
|
+
Author: pravnikovo.info
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://infosoud.pravnikovo.info
|
|
8
|
+
Project-URL: Repository, https://github.com/pravnikovo/infosoud
|
|
9
|
+
Keywords: czech,court,justice,infosoud,právní,soud
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Topic :: Office/Business
|
|
13
|
+
Classifier: Natural Language :: Czech
|
|
14
|
+
Requires-Python: >=3.8
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: requests>=2.20
|
|
18
|
+
Provides-Extra: web
|
|
19
|
+
Requires-Dist: flask>=2.0; extra == "web"
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# InfoSoud
|
|
23
|
+
|
|
24
|
+
Neoficiální klient pro [InfoSoud](https://infosoud.gov.cz) — vyhledávání v soudních řízeních České republiky.
|
|
25
|
+
|
|
26
|
+
Umožňuje vyhledat průběh soudního řízení, nařízená jednání a události podle spisové značky. Data pocházejí z veřejného API Ministerstva spravedlnosti ČR.
|
|
27
|
+
|
|
28
|
+
**[infosoud.pravnikovo.info](https://infosoud.pravnikovo.info)** — webové rozhraní
|
|
29
|
+
|
|
30
|
+
## Instalace
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install infosoud
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Použití
|
|
37
|
+
|
|
38
|
+
### Příkazový řádek
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Vyhledat řízení
|
|
42
|
+
infosoud "1 T 64/2024" OSSCEDC
|
|
43
|
+
infosoud "1T64_2024 OSSCEDC" # kompaktní formát
|
|
44
|
+
infosoud "4 T 21/2025 melnik" # název soudu místo kódu
|
|
45
|
+
|
|
46
|
+
# Zobrazit jednání
|
|
47
|
+
infosoud --hearings "1 T 64/2024" OSSCEDC
|
|
48
|
+
|
|
49
|
+
# JSON výstup
|
|
50
|
+
infosoud --json "1 T 64/2024" OSSCEDC
|
|
51
|
+
|
|
52
|
+
# CSV výstup (události)
|
|
53
|
+
infosoud --csv "1 T 64/2024" OSSCEDC
|
|
54
|
+
|
|
55
|
+
# Vypsat soudy
|
|
56
|
+
infosoud --courts
|
|
57
|
+
infosoud --courts --csv
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Python
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from infosoud import InfoSoudClient, parse_spis_zn
|
|
64
|
+
|
|
65
|
+
client = InfoSoudClient()
|
|
66
|
+
|
|
67
|
+
# Vyhledat řízení
|
|
68
|
+
case = client.search_case("1 T 64/2024", "OSSCEDC")
|
|
69
|
+
print(case["stav"]) # "nevyřízená věc"
|
|
70
|
+
print(case["organizace"]) # "Okresní soud Děčín"
|
|
71
|
+
|
|
72
|
+
for event in case["udalosti"]:
|
|
73
|
+
print(f"{event['datum']} {event['udalost']}")
|
|
74
|
+
|
|
75
|
+
# Vyhledat jednání
|
|
76
|
+
hearings = client.search_hearings("1 T 64/2024", "OSSCEDC")
|
|
77
|
+
for h in hearings["udalosti"]:
|
|
78
|
+
print(f"{h['datum']} {h['cas']} {h['druhJednani']} {h['resitel']}")
|
|
79
|
+
|
|
80
|
+
# Detail události (čas, jednací síň)
|
|
81
|
+
detail = client.get_event_detail("1 T 64/2024", "OSSCEDC", "NAR_JED", 48)
|
|
82
|
+
for attr in detail["atributy"]:
|
|
83
|
+
print(f"{attr['typ']}: {attr['hodnota']}")
|
|
84
|
+
|
|
85
|
+
# Spisová značka — tolerantní parser
|
|
86
|
+
spis = parse_spis_zn("1T64_2024")
|
|
87
|
+
print(spis.canonical()) # "1 T 64/2024"
|
|
88
|
+
print(spis.compact()) # "1T64_2024"
|
|
89
|
+
|
|
90
|
+
# Fuzzy vyhledání soudu
|
|
91
|
+
code = client.resolve_court_name("melnik") # → "OSSTCME"
|
|
92
|
+
code = client.resolve_court_name("praha 9") # → "OSPHA09"
|
|
93
|
+
|
|
94
|
+
# Seznam soudů
|
|
95
|
+
courts = client.build_court_map() # {kód: název} pro všech 104 soudů
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Formáty spisové značky
|
|
99
|
+
|
|
100
|
+
Parser je maximálně tolerantní — všechny tyto formáty jsou ekvivalentní:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
1 T 64/2024 1T64/2024 1T 64/2024
|
|
104
|
+
1 T64/2024 1T64_2024 1 T 64 / 2024
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Kód soudu lze přidat za sp. zn.: `1T64_2024 OSSCEDC`
|
|
108
|
+
|
|
109
|
+
Místo kódu soudu lze zadat název: `4 T 21/2025 melnik` (bez diakritiky)
|
|
110
|
+
|
|
111
|
+
## API endpointy
|
|
112
|
+
|
|
113
|
+
| Endpoint | Metoda | Popis |
|
|
114
|
+
|----------|--------|-------|
|
|
115
|
+
| `/api/v1/rizeni/vyhledej` | POST | Vyhledání řízení |
|
|
116
|
+
| `/api/v1/jednani/vyhledej` | POST | Vyhledání jednání |
|
|
117
|
+
| `/api/v1/udalost/vyhledej` | POST | Detail události |
|
|
118
|
+
| `/api/v1/organizace/lov` | GET | Seznam krajských/vrchních soudů |
|
|
119
|
+
| `/api/v1/organizace/podrizene/lov` | GET | Seznam okresních soudů |
|
|
120
|
+
|
|
121
|
+
Base URL: `https://infosoud.gov.cz/api/v1`
|
|
122
|
+
|
|
123
|
+
## Kódy soudů
|
|
124
|
+
|
|
125
|
+
Kompletní seznam 104 soudů (96 z API + 8 poboček):
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
infosoud --courts
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Příklady: `OSSCEDC` (OS Děčín), `OSPHA09` (OS Praha 9), `KSJIMBM` (KS Brno), `MSPHAAB` (MS Praha)
|
|
132
|
+
|
|
133
|
+
## Webové rozhraní
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
pip install infosoud[web]
|
|
137
|
+
python -m infosoud.web
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Otevře webserver na `http://localhost:8060` s vyhledávacím formulářem, timeline událostí, ICS exportem jednání a CSV exportem.
|
|
141
|
+
|
|
142
|
+
## Licence
|
|
143
|
+
|
|
144
|
+
MIT — viz [LICENSE](LICENSE)
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
*Neoficiální nástroj. Data pocházejí z [infosoud.gov.cz](https://infosoud.gov.cz). Projekt [pravnikovo.info](https://pravnikovo.info) — open source nástroje pro právníky.*
|
infosoud-0.1.0/README.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# InfoSoud
|
|
2
|
+
|
|
3
|
+
Neoficiální klient pro [InfoSoud](https://infosoud.gov.cz) — vyhledávání v soudních řízeních České republiky.
|
|
4
|
+
|
|
5
|
+
Umožňuje vyhledat průběh soudního řízení, nařízená jednání a události podle spisové značky. Data pocházejí z veřejného API Ministerstva spravedlnosti ČR.
|
|
6
|
+
|
|
7
|
+
**[infosoud.pravnikovo.info](https://infosoud.pravnikovo.info)** — webové rozhraní
|
|
8
|
+
|
|
9
|
+
## Instalace
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install infosoud
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Použití
|
|
16
|
+
|
|
17
|
+
### Příkazový řádek
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Vyhledat řízení
|
|
21
|
+
infosoud "1 T 64/2024" OSSCEDC
|
|
22
|
+
infosoud "1T64_2024 OSSCEDC" # kompaktní formát
|
|
23
|
+
infosoud "4 T 21/2025 melnik" # název soudu místo kódu
|
|
24
|
+
|
|
25
|
+
# Zobrazit jednání
|
|
26
|
+
infosoud --hearings "1 T 64/2024" OSSCEDC
|
|
27
|
+
|
|
28
|
+
# JSON výstup
|
|
29
|
+
infosoud --json "1 T 64/2024" OSSCEDC
|
|
30
|
+
|
|
31
|
+
# CSV výstup (události)
|
|
32
|
+
infosoud --csv "1 T 64/2024" OSSCEDC
|
|
33
|
+
|
|
34
|
+
# Vypsat soudy
|
|
35
|
+
infosoud --courts
|
|
36
|
+
infosoud --courts --csv
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Python
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from infosoud import InfoSoudClient, parse_spis_zn
|
|
43
|
+
|
|
44
|
+
client = InfoSoudClient()
|
|
45
|
+
|
|
46
|
+
# Vyhledat řízení
|
|
47
|
+
case = client.search_case("1 T 64/2024", "OSSCEDC")
|
|
48
|
+
print(case["stav"]) # "nevyřízená věc"
|
|
49
|
+
print(case["organizace"]) # "Okresní soud Děčín"
|
|
50
|
+
|
|
51
|
+
for event in case["udalosti"]:
|
|
52
|
+
print(f"{event['datum']} {event['udalost']}")
|
|
53
|
+
|
|
54
|
+
# Vyhledat jednání
|
|
55
|
+
hearings = client.search_hearings("1 T 64/2024", "OSSCEDC")
|
|
56
|
+
for h in hearings["udalosti"]:
|
|
57
|
+
print(f"{h['datum']} {h['cas']} {h['druhJednani']} {h['resitel']}")
|
|
58
|
+
|
|
59
|
+
# Detail události (čas, jednací síň)
|
|
60
|
+
detail = client.get_event_detail("1 T 64/2024", "OSSCEDC", "NAR_JED", 48)
|
|
61
|
+
for attr in detail["atributy"]:
|
|
62
|
+
print(f"{attr['typ']}: {attr['hodnota']}")
|
|
63
|
+
|
|
64
|
+
# Spisová značka — tolerantní parser
|
|
65
|
+
spis = parse_spis_zn("1T64_2024")
|
|
66
|
+
print(spis.canonical()) # "1 T 64/2024"
|
|
67
|
+
print(spis.compact()) # "1T64_2024"
|
|
68
|
+
|
|
69
|
+
# Fuzzy vyhledání soudu
|
|
70
|
+
code = client.resolve_court_name("melnik") # → "OSSTCME"
|
|
71
|
+
code = client.resolve_court_name("praha 9") # → "OSPHA09"
|
|
72
|
+
|
|
73
|
+
# Seznam soudů
|
|
74
|
+
courts = client.build_court_map() # {kód: název} pro všech 104 soudů
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Formáty spisové značky
|
|
78
|
+
|
|
79
|
+
Parser je maximálně tolerantní — všechny tyto formáty jsou ekvivalentní:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
1 T 64/2024 1T64/2024 1T 64/2024
|
|
83
|
+
1 T64/2024 1T64_2024 1 T 64 / 2024
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Kód soudu lze přidat za sp. zn.: `1T64_2024 OSSCEDC`
|
|
87
|
+
|
|
88
|
+
Místo kódu soudu lze zadat název: `4 T 21/2025 melnik` (bez diakritiky)
|
|
89
|
+
|
|
90
|
+
## API endpointy
|
|
91
|
+
|
|
92
|
+
| Endpoint | Metoda | Popis |
|
|
93
|
+
|----------|--------|-------|
|
|
94
|
+
| `/api/v1/rizeni/vyhledej` | POST | Vyhledání řízení |
|
|
95
|
+
| `/api/v1/jednani/vyhledej` | POST | Vyhledání jednání |
|
|
96
|
+
| `/api/v1/udalost/vyhledej` | POST | Detail události |
|
|
97
|
+
| `/api/v1/organizace/lov` | GET | Seznam krajských/vrchních soudů |
|
|
98
|
+
| `/api/v1/organizace/podrizene/lov` | GET | Seznam okresních soudů |
|
|
99
|
+
|
|
100
|
+
Base URL: `https://infosoud.gov.cz/api/v1`
|
|
101
|
+
|
|
102
|
+
## Kódy soudů
|
|
103
|
+
|
|
104
|
+
Kompletní seznam 104 soudů (96 z API + 8 poboček):
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
infosoud --courts
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Příklady: `OSSCEDC` (OS Děčín), `OSPHA09` (OS Praha 9), `KSJIMBM` (KS Brno), `MSPHAAB` (MS Praha)
|
|
111
|
+
|
|
112
|
+
## Webové rozhraní
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
pip install infosoud[web]
|
|
116
|
+
python -m infosoud.web
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Otevře webserver na `http://localhost:8060` s vyhledávacím formulářem, timeline událostí, ICS exportem jednání a CSV exportem.
|
|
120
|
+
|
|
121
|
+
## Licence
|
|
122
|
+
|
|
123
|
+
MIT — viz [LICENSE](LICENSE)
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
*Neoficiální nástroj. Data pocházejí z [infosoud.gov.cz](https://infosoud.gov.cz). Projekt [pravnikovo.info](https://pravnikovo.info) — open source nástroje pro právníky.*
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""CLI for InfoSoud — Czech court case lookup.
|
|
2
|
+
|
|
3
|
+
Usage:
|
|
4
|
+
python -m infosoud "1 T 64/2024" OSSCEDC
|
|
5
|
+
python -m infosoud "1T64_2024 OSSCEDC"
|
|
6
|
+
python -m infosoud "4 T 21/2025 melnik"
|
|
7
|
+
python -m infosoud --hearings "1 T 64/2024" OSSCEDC
|
|
8
|
+
python -m infosoud --courts
|
|
9
|
+
python -m infosoud --json "1 T 64/2024" OSSCEDC
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
import json
|
|
16
|
+
import sys
|
|
17
|
+
|
|
18
|
+
from .client import InfoSoudClient, parse_spis_zn, EVENT_LABELS
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def format_case_summary(data: dict) -> str:
|
|
22
|
+
"""Format case data into human-readable summary."""
|
|
23
|
+
lines = []
|
|
24
|
+
org = data.get("organizace", "?")
|
|
25
|
+
nadr = data.get("nadrizenaOrganizace", "")
|
|
26
|
+
stav = data.get("stav") or "?"
|
|
27
|
+
stav_datum = data.get("stavDatum", "")
|
|
28
|
+
|
|
29
|
+
spzn = (f"{data.get('cislo', '') or ''} {data.get('druh', '') or ''} "
|
|
30
|
+
f"{data.get('bcVec', '') or ''}/{data.get('rocnik', '') or ''}")
|
|
31
|
+
lines.append(f"Sp. zn.: {spzn}")
|
|
32
|
+
lines.append(f"Soud: {org}" + (f" ({nadr})" if nadr else ""))
|
|
33
|
+
lines.append(f"Stav: {stav}" + (f" (od {stav_datum})" if stav_datum else ""))
|
|
34
|
+
|
|
35
|
+
events = data.get("udalosti") or []
|
|
36
|
+
if events:
|
|
37
|
+
lines.append(f"\nUdálosti ({len(events)}):")
|
|
38
|
+
for ev in events:
|
|
39
|
+
code = ev.get("udalost", "?")
|
|
40
|
+
label = EVENT_LABELS.get(code, code)
|
|
41
|
+
datum = ev.get("datum", "?")
|
|
42
|
+
zruseno = " [ZRUŠENO]" if ev.get("zruseno") else ""
|
|
43
|
+
lines.append(f" {datum} {label}{zruseno}")
|
|
44
|
+
|
|
45
|
+
return "\n".join(lines)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def format_hearings_summary(data: dict) -> str:
|
|
49
|
+
"""Format hearings data into human-readable summary."""
|
|
50
|
+
lines = [f"Jednání — {data.get('organizace', '?')}"]
|
|
51
|
+
events = data.get("udalosti") or []
|
|
52
|
+
if not events:
|
|
53
|
+
lines.append(" Žádná jednání nařízena.")
|
|
54
|
+
return "\n".join(lines)
|
|
55
|
+
for ev in events:
|
|
56
|
+
zruseno = " [ZRUŠENO]" if ev.get("jednaniZruseno") else ""
|
|
57
|
+
lines.append(f" {ev.get('datum', '?')} {ev.get('cas', '?')} "
|
|
58
|
+
f"{ev.get('druhJednani', '?')}{zruseno}")
|
|
59
|
+
lines.append(f" Soudce: {ev.get('resitel', '?')}")
|
|
60
|
+
lines.append(f" Síň: {ev.get('jednaciSin', '?')}")
|
|
61
|
+
return "\n".join(lines)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def main():
|
|
65
|
+
parser = argparse.ArgumentParser(
|
|
66
|
+
prog="infosoud",
|
|
67
|
+
description="InfoSoud — vyhledávání v soudních řízeních (infosoud.gov.cz)",
|
|
68
|
+
)
|
|
69
|
+
parser.add_argument("spis_zn", nargs="?",
|
|
70
|
+
help="Spisová značka (např. '1 T 64/2024', '1T64_2024 OSSCEDC', '4 T 21/2025 melnik')")
|
|
71
|
+
parser.add_argument("court_code", nargs="?",
|
|
72
|
+
help="Kód soudu (nepovinné pokud je v sp. zn.)")
|
|
73
|
+
parser.add_argument("--hearings", action="store_true",
|
|
74
|
+
help="Zobrazit nařízená jednání")
|
|
75
|
+
parser.add_argument("--courts", action="store_true",
|
|
76
|
+
help="Vypsat seznam soudů")
|
|
77
|
+
parser.add_argument("--json", dest="json_out", action="store_true",
|
|
78
|
+
help="Výstup v JSON")
|
|
79
|
+
parser.add_argument("--csv", dest="csv_out", action="store_true",
|
|
80
|
+
help="Výstup v CSV")
|
|
81
|
+
|
|
82
|
+
args = parser.parse_args()
|
|
83
|
+
client = InfoSoudClient()
|
|
84
|
+
|
|
85
|
+
if args.courts:
|
|
86
|
+
courts = client.build_court_map()
|
|
87
|
+
if args.json_out:
|
|
88
|
+
print(json.dumps(courts, ensure_ascii=False, indent=2))
|
|
89
|
+
elif args.csv_out:
|
|
90
|
+
print("kod,nazev")
|
|
91
|
+
for code, name in sorted(courts.items(), key=lambda x: x[1]):
|
|
92
|
+
print(f"{code},{name}")
|
|
93
|
+
else:
|
|
94
|
+
for code, name in sorted(courts.items(), key=lambda x: x[1]):
|
|
95
|
+
print(f" {code} {name}")
|
|
96
|
+
print(f"\nCelkem: {len(courts)} soudů")
|
|
97
|
+
return
|
|
98
|
+
|
|
99
|
+
if not args.spis_zn:
|
|
100
|
+
parser.print_help()
|
|
101
|
+
sys.exit(1)
|
|
102
|
+
|
|
103
|
+
# Try to resolve court name from input
|
|
104
|
+
spis_zn_raw = args.spis_zn
|
|
105
|
+
court_code = args.court_code or ""
|
|
106
|
+
|
|
107
|
+
if not court_code:
|
|
108
|
+
# Check if trailing text in spis_zn is a court name
|
|
109
|
+
import re
|
|
110
|
+
m = re.match(
|
|
111
|
+
r"((?:\d+\s*[A-Za-z]+\s*\d+\s*[/_]\s*\d{4}))\s+(.+)$",
|
|
112
|
+
spis_zn_raw.strip(),
|
|
113
|
+
)
|
|
114
|
+
if m:
|
|
115
|
+
spzn_part = m.group(1).strip()
|
|
116
|
+
tail = m.group(2).strip()
|
|
117
|
+
if re.match(r"^[A-Z][A-Z0-9]{4,9}$", tail):
|
|
118
|
+
spis_zn_raw, court_code = spzn_part, tail
|
|
119
|
+
else:
|
|
120
|
+
resolved = client.resolve_court_name(tail)
|
|
121
|
+
if resolved:
|
|
122
|
+
spis_zn_raw, court_code = spzn_part, resolved
|
|
123
|
+
|
|
124
|
+
spis_zn = parse_spis_zn(spis_zn_raw)
|
|
125
|
+
code = court_code or spis_zn.court_code
|
|
126
|
+
|
|
127
|
+
if not code:
|
|
128
|
+
print("Chybí kód soudu. Zadejte jako druhý argument nebo součást sp. zn.",
|
|
129
|
+
file=sys.stderr)
|
|
130
|
+
print("Příklad: python -m infosoud '1 T 64/2024' OSSCEDC", file=sys.stderr)
|
|
131
|
+
print(" python -m infosoud '4 T 21/2025 melnik'", file=sys.stderr)
|
|
132
|
+
sys.exit(1)
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
if args.hearings:
|
|
136
|
+
data = client.search_hearings(spis_zn, code)
|
|
137
|
+
if args.json_out:
|
|
138
|
+
print(json.dumps(data, ensure_ascii=False, indent=2))
|
|
139
|
+
else:
|
|
140
|
+
print(format_hearings_summary(data))
|
|
141
|
+
else:
|
|
142
|
+
data = client.search_case(spis_zn, code)
|
|
143
|
+
if args.json_out:
|
|
144
|
+
print(json.dumps(data, ensure_ascii=False, indent=2))
|
|
145
|
+
elif args.csv_out:
|
|
146
|
+
events = data.get("udalosti") or []
|
|
147
|
+
print("datum;udalost;zruseno;souvisejici_spzn;soud")
|
|
148
|
+
for ev in events:
|
|
149
|
+
code_ev = ev.get("udalost", "")
|
|
150
|
+
label = EVENT_LABELS.get(code_ev, code_ev)
|
|
151
|
+
zr = "Ano" if ev.get("zruseno") else ""
|
|
152
|
+
zid = ev.get("znackaId", {})
|
|
153
|
+
rel = (f"{zid.get('cisloSenatu', '')} {zid.get('druhVeci', '')} "
|
|
154
|
+
f"{zid.get('bcVec', '')}/{zid.get('rocnik', '')} "
|
|
155
|
+
f"{zid.get('organizace', '')}").strip()
|
|
156
|
+
print(f"{ev.get('datum', '')};{label};{zr};{rel};{data.get('organizace', '')}")
|
|
157
|
+
else:
|
|
158
|
+
print(format_case_summary(data))
|
|
159
|
+
except Exception as e:
|
|
160
|
+
print(f"Chyba: {e}", file=sys.stderr)
|
|
161
|
+
sys.exit(1)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
if __name__ == "__main__":
|
|
165
|
+
main()
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
"""InfoSoud API client — Czech court case tracking (infosoud.gov.cz).
|
|
2
|
+
|
|
3
|
+
Public REST API of the Czech Ministry of Justice for looking up
|
|
4
|
+
court case status, events timeline, and scheduled hearings.
|
|
5
|
+
|
|
6
|
+
No authentication required. Be polite — use reasonable delays between requests.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
import logging
|
|
13
|
+
import re
|
|
14
|
+
import time
|
|
15
|
+
import unicodedata
|
|
16
|
+
from dataclasses import dataclass
|
|
17
|
+
|
|
18
|
+
import requests
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
BASE_URL = "https://infosoud.gov.cz/api/v1"
|
|
23
|
+
|
|
24
|
+
# Universal regex — tolerant to any whitespace/separator combo
|
|
25
|
+
_SPZN_UNIVERSAL = re.compile(
|
|
26
|
+
r"(\d+)\s*([A-Za-z]+)\s*(\d+)\s*[/_]\s*(\d{4})"
|
|
27
|
+
r"(?:\s+([A-Z][A-Z0-9]{4,9}))?$"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass(frozen=True)
|
|
32
|
+
class SpisZn:
|
|
33
|
+
"""Parsed spisová značka (Czech court case file number)."""
|
|
34
|
+
cislo_senatu: int
|
|
35
|
+
druh_veci: str
|
|
36
|
+
bc_vec: int
|
|
37
|
+
rocnik: int
|
|
38
|
+
court_code: str | None = None
|
|
39
|
+
|
|
40
|
+
def to_api_params(self, court_code: str | None = None) -> dict:
|
|
41
|
+
"""Convert to InfoSoud API request body."""
|
|
42
|
+
code = court_code or self.court_code
|
|
43
|
+
params = {
|
|
44
|
+
"cisloSenatu": str(self.cislo_senatu),
|
|
45
|
+
"druhVeci": self.druh_veci,
|
|
46
|
+
"bcVec": str(self.bc_vec),
|
|
47
|
+
"rocnik": str(self.rocnik),
|
|
48
|
+
}
|
|
49
|
+
if code:
|
|
50
|
+
code = resolve_court_code(code)
|
|
51
|
+
ct = classify_court_code(code)
|
|
52
|
+
if ct == "NS":
|
|
53
|
+
params["typOrganizace"] = "NEJVYSSI"
|
|
54
|
+
elif ct in ("KS", "VS", "MS"):
|
|
55
|
+
params["druhOrganizace"] = code
|
|
56
|
+
else:
|
|
57
|
+
params["okresniSoud"] = code
|
|
58
|
+
return params
|
|
59
|
+
|
|
60
|
+
def canonical(self) -> str:
|
|
61
|
+
"""Canonical form: '1 T 64/2024'."""
|
|
62
|
+
return f"{self.cislo_senatu} {self.druh_veci} {self.bc_vec}/{self.rocnik}"
|
|
63
|
+
|
|
64
|
+
def compact(self) -> str:
|
|
65
|
+
"""Compact form: '1T64_2024'."""
|
|
66
|
+
return f"{self.cislo_senatu}{self.druh_veci}{self.bc_vec}_{self.rocnik}"
|
|
67
|
+
|
|
68
|
+
def __str__(self) -> str:
|
|
69
|
+
s = self.canonical()
|
|
70
|
+
if self.court_code:
|
|
71
|
+
s += f" {self.court_code}"
|
|
72
|
+
return s
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def parse_spis_zn(text: str) -> SpisZn:
|
|
76
|
+
"""Parse spisová značka in any common format.
|
|
77
|
+
|
|
78
|
+
Extremely tolerant — whitespace and separators are ignored.
|
|
79
|
+
All of these parse identically:
|
|
80
|
+
"1 T 64/2024" "1T64/2024" "1T 64/2024"
|
|
81
|
+
"1 T64/2024" "1T64_2024" "1 T 64 / 2024"
|
|
82
|
+
"43T191_2024" "43 T 191/2024 OSPHA09"
|
|
83
|
+
"11 C 233/2022" "2 To 29/2023" "6To436/2025"
|
|
84
|
+
"""
|
|
85
|
+
text = text.strip()
|
|
86
|
+
m = _SPZN_UNIVERSAL.match(text)
|
|
87
|
+
if m:
|
|
88
|
+
return SpisZn(
|
|
89
|
+
cislo_senatu=int(m.group(1)),
|
|
90
|
+
druh_veci=m.group(2),
|
|
91
|
+
bc_vec=int(m.group(3)),
|
|
92
|
+
rocnik=int(m.group(4)),
|
|
93
|
+
court_code=m.group(5) if m.group(5) else None,
|
|
94
|
+
)
|
|
95
|
+
raise ValueError(f"Cannot parse spisová značka: {text!r}")
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
# --- Court codes ---
|
|
99
|
+
|
|
100
|
+
KS_CODES = {
|
|
101
|
+
"KSJIMBM": "Krajský soud Brno",
|
|
102
|
+
"KSJICCB": "Krajský soud České Budějovice",
|
|
103
|
+
"KSVYCHK": "Krajský soud Hradec Králové",
|
|
104
|
+
"KSSEMOS": "Krajský soud Ostrava",
|
|
105
|
+
"KSZPCPM": "Krajský soud Plzeň",
|
|
106
|
+
"KSSTCAB": "Krajský soud Praha",
|
|
107
|
+
"KSSCEUL": "Krajský soud Ústí nad Labem",
|
|
108
|
+
"MSPHAAB": "Městský soud Praha",
|
|
109
|
+
"VSSEMOL": "Vrchní soud Olomouc",
|
|
110
|
+
"VSPHAAB": "Vrchní soud Praha",
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
EXTRA_COURTS = {
|
|
114
|
+
"KSVYCPA": "Krajský soud Hradec Králové — pobočka Pardubice",
|
|
115
|
+
"KSSEMOC": "Krajský soud Ostrava — pobočka Olomouc",
|
|
116
|
+
"KSSCELB": "Krajský soud Ústí nad Labem — pobočka Liberec",
|
|
117
|
+
"VSSTCAB": "Vrchní soud Praha",
|
|
118
|
+
"VSSEMOC": "Vrchní soud Olomouc",
|
|
119
|
+
"OSSEMHA": "Okresní soud Karviná — pobočka Havířov",
|
|
120
|
+
"OSSEMKR": "Okresní soud Bruntál — pobočka Krnov",
|
|
121
|
+
"OSSEMVM": "Okresní soud Vsetín — pobočka Valašské Meziříčí",
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
COURT_CODE_ALIASES = {
|
|
125
|
+
"KSSEMOC": "KSSEMOS",
|
|
126
|
+
"VSSTCAB": "VSPHAAB",
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
PRAGUE_DISTRICTS = [f"OSPHA{i:02d}" for i in range(1, 11)]
|
|
130
|
+
|
|
131
|
+
EVENT_LABELS = {
|
|
132
|
+
"ZAHAJ_RIZ": "Zahájení řízení",
|
|
133
|
+
"NAR_JED": "Nařízení jednání",
|
|
134
|
+
"ZRUS_JED": "Zrušení jednání",
|
|
135
|
+
"VYD_ROZH": "Vydání rozhodnutí",
|
|
136
|
+
"ODES_SPIS": "Odeslání spisu",
|
|
137
|
+
"VRAC_SPIS": "Vrácení spisu",
|
|
138
|
+
"POD_OP_PR": "Podání opravného prostředku",
|
|
139
|
+
"VYR_OP_PR": "Vyřízení opravného prostředku",
|
|
140
|
+
"ODVOLANI": "Řízení o odvolání",
|
|
141
|
+
"DOVOL_RIZ": "Řízení o dovolání",
|
|
142
|
+
"NAD_RIZENI": "Řízení u nadřízeného soudu",
|
|
143
|
+
"ST_VEC_ODS": "Skončení věci",
|
|
144
|
+
"ST_VEC_OBZ": "Obživnutí věci",
|
|
145
|
+
"ST_VEC_PRE": "Přerušení řízení",
|
|
146
|
+
"ST_VEC_UPR": "Ukončení přerušení",
|
|
147
|
+
"ST_VEC_VYR": "Vyřízení věci",
|
|
148
|
+
"ST_VEC_PUK": "Pravomocné ukončení",
|
|
149
|
+
"SPIS_K_SC": "Spis odeslán soudci",
|
|
150
|
+
"SPIS_K_SO": "Spis odeslán soudnímu komisaři",
|
|
151
|
+
"SPIS_OD_SC": "Soudce předal spis",
|
|
152
|
+
"SPIS_OD_SO": "Soudní komisař předal spis",
|
|
153
|
+
"PREVD_SPIS": "Převedeno pod jinou sp. zn.",
|
|
154
|
+
"PR_VEC_NS": "Přerušení věci",
|
|
155
|
+
"VR_SP_NS": "Vrácení spisu odvolacímu soudu",
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def classify_court_code(code: str) -> str:
|
|
160
|
+
"""Classify court code: NS, KS, VS, MS, or OS."""
|
|
161
|
+
if not code:
|
|
162
|
+
return "OS"
|
|
163
|
+
upper = code.upper()
|
|
164
|
+
for prefix in ("NS", "VS", "MS", "KS"):
|
|
165
|
+
if upper.startswith(prefix):
|
|
166
|
+
return prefix
|
|
167
|
+
return "OS"
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def resolve_court_code(code: str) -> str:
|
|
171
|
+
"""Resolve alternative court codes to InfoSoud codes."""
|
|
172
|
+
return COURT_CODE_ALIASES.get(code.upper(), code)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def strip_diacritics(text: str) -> str:
|
|
176
|
+
"""Remove Czech diacritics for fuzzy matching."""
|
|
177
|
+
return "".join(
|
|
178
|
+
c for c in unicodedata.normalize("NFD", text)
|
|
179
|
+
if unicodedata.category(c) != "Mn"
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
class InfoSoudClient:
|
|
184
|
+
"""Client for the InfoSoud REST API.
|
|
185
|
+
|
|
186
|
+
Usage::
|
|
187
|
+
|
|
188
|
+
client = InfoSoudClient()
|
|
189
|
+
case = client.search_case("1 T 64/2024", "OSSCEDC")
|
|
190
|
+
hearings = client.search_hearings("1 T 64/2024", "OSSCEDC")
|
|
191
|
+
courts = client.build_court_map()
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
def __init__(self, delay: float = 0.5, timeout: int = 15,
|
|
195
|
+
base_url: str = BASE_URL):
|
|
196
|
+
self.base_url = base_url
|
|
197
|
+
self.delay = delay
|
|
198
|
+
self.timeout = timeout
|
|
199
|
+
self.session = requests.Session()
|
|
200
|
+
self.session.headers.update({
|
|
201
|
+
"User-Agent": "infosoud-oss/0.1 (https://github.com/pravnikovo/infosoud)",
|
|
202
|
+
"Accept": "application/json",
|
|
203
|
+
"Content-Type": "application/json",
|
|
204
|
+
})
|
|
205
|
+
self._last_request = 0.0
|
|
206
|
+
|
|
207
|
+
def _throttle(self) -> None:
|
|
208
|
+
elapsed = time.monotonic() - self._last_request
|
|
209
|
+
if elapsed < self.delay:
|
|
210
|
+
time.sleep(self.delay - elapsed)
|
|
211
|
+
|
|
212
|
+
def _get(self, path: str, params: dict | None = None) -> dict | list:
|
|
213
|
+
self._throttle()
|
|
214
|
+
url = f"{self.base_url}{path}"
|
|
215
|
+
t0 = time.monotonic()
|
|
216
|
+
resp = self.session.get(url, params=params, timeout=self.timeout)
|
|
217
|
+
self._last_request = time.monotonic()
|
|
218
|
+
elapsed_ms = int((self._last_request - t0) * 1000)
|
|
219
|
+
logger.debug("GET %s → %d (%dms)", path, resp.status_code, elapsed_ms)
|
|
220
|
+
resp.raise_for_status()
|
|
221
|
+
return resp.json()
|
|
222
|
+
|
|
223
|
+
def _post(self, path: str, body: dict) -> dict:
|
|
224
|
+
self._throttle()
|
|
225
|
+
url = f"{self.base_url}{path}"
|
|
226
|
+
t0 = time.monotonic()
|
|
227
|
+
resp = self.session.post(url, json=body, timeout=self.timeout)
|
|
228
|
+
self._last_request = time.monotonic()
|
|
229
|
+
elapsed_ms = int((self._last_request - t0) * 1000)
|
|
230
|
+
logger.debug("POST %s → %d (%dms)", path, resp.status_code, elapsed_ms)
|
|
231
|
+
resp.raise_for_status()
|
|
232
|
+
return resp.json()
|
|
233
|
+
|
|
234
|
+
def search_case(self, spis_zn: str | SpisZn,
|
|
235
|
+
court_code: str | None = None) -> dict:
|
|
236
|
+
"""Search case by spisová značka. Returns events timeline."""
|
|
237
|
+
if isinstance(spis_zn, str):
|
|
238
|
+
spis_zn = parse_spis_zn(spis_zn)
|
|
239
|
+
code = court_code or spis_zn.court_code
|
|
240
|
+
|
|
241
|
+
if code and code.upper() in ("OSPHA", "OSPHA0"):
|
|
242
|
+
return self._search_prague(spis_zn, "/rizeni/vyhledej")
|
|
243
|
+
|
|
244
|
+
return self._post("/rizeni/vyhledej", spis_zn.to_api_params(court_code))
|
|
245
|
+
|
|
246
|
+
def search_hearings(self, spis_zn: str | SpisZn,
|
|
247
|
+
court_code: str | None = None) -> dict:
|
|
248
|
+
"""Search hearings for a case."""
|
|
249
|
+
if isinstance(spis_zn, str):
|
|
250
|
+
spis_zn = parse_spis_zn(spis_zn)
|
|
251
|
+
code = court_code or spis_zn.court_code
|
|
252
|
+
|
|
253
|
+
if code and code.upper() in ("OSPHA", "OSPHA0"):
|
|
254
|
+
return self._search_prague(spis_zn, "/jednani/vyhledej",
|
|
255
|
+
extra={"typHledani": "SPZN"})
|
|
256
|
+
|
|
257
|
+
params = spis_zn.to_api_params(court_code)
|
|
258
|
+
params["typHledani"] = "SPZN"
|
|
259
|
+
return self._post("/jednani/vyhledej", params)
|
|
260
|
+
|
|
261
|
+
def get_event_detail(self, spis_zn: str | SpisZn,
|
|
262
|
+
court_code: str | None,
|
|
263
|
+
event_type: str, event_order: int) -> dict:
|
|
264
|
+
"""Fetch detail for a single event (room, time, result)."""
|
|
265
|
+
if isinstance(spis_zn, str):
|
|
266
|
+
spis_zn = parse_spis_zn(spis_zn)
|
|
267
|
+
params = spis_zn.to_api_params(court_code)
|
|
268
|
+
params["druhUdalosti"] = event_type
|
|
269
|
+
params["poradiUdalosti"] = str(event_order)
|
|
270
|
+
return self._post("/udalost/vyhledej", params)
|
|
271
|
+
|
|
272
|
+
def get_courts(self) -> list[dict]:
|
|
273
|
+
"""Get list of krajské/vrchní soudy."""
|
|
274
|
+
return self._get("/organizace/lov")
|
|
275
|
+
|
|
276
|
+
def get_district_courts(self, ks_code: str | None = None) -> list[dict]:
|
|
277
|
+
"""Get list of okresní soudy, optionally filtered by KS."""
|
|
278
|
+
params = {"kod": ks_code} if ks_code else None
|
|
279
|
+
return self._get("/organizace/podrizene/lov", params=params)
|
|
280
|
+
|
|
281
|
+
def build_court_map(self) -> dict[str, str]:
|
|
282
|
+
"""Fetch and build complete court code → name mapping."""
|
|
283
|
+
result = dict(EXTRA_COURTS)
|
|
284
|
+
for court in self.get_courts():
|
|
285
|
+
result[court["kod"]] = court["nazev"]
|
|
286
|
+
for court in self.get_district_courts():
|
|
287
|
+
result[court["kod"]] = court["nazev"]
|
|
288
|
+
return result
|
|
289
|
+
|
|
290
|
+
def resolve_court_name(self, name: str,
|
|
291
|
+
court_map: dict | None = None) -> str | None:
|
|
292
|
+
"""Fuzzy-match a court name (diacritics-insensitive) to a court code."""
|
|
293
|
+
if court_map is None:
|
|
294
|
+
court_map = self.build_court_map()
|
|
295
|
+
name_lower = strip_diacritics(name.lower())
|
|
296
|
+
for prefix in ("os ", "okresni soud ", "krajsky soud ", "ks ", "ms "):
|
|
297
|
+
if name_lower.startswith(prefix):
|
|
298
|
+
name_lower = name_lower[len(prefix):]
|
|
299
|
+
break
|
|
300
|
+
best_code, best_score = None, 0
|
|
301
|
+
for code, full_name in court_map.items():
|
|
302
|
+
full_lower = strip_diacritics(full_name.lower())
|
|
303
|
+
if name_lower in full_lower:
|
|
304
|
+
score = len(name_lower) / len(full_lower)
|
|
305
|
+
if score > best_score:
|
|
306
|
+
best_score = score
|
|
307
|
+
best_code = code
|
|
308
|
+
return best_code
|
|
309
|
+
|
|
310
|
+
def _search_prague(self, spis_zn: SpisZn, path: str,
|
|
311
|
+
extra: dict | None = None) -> dict:
|
|
312
|
+
"""Try all Prague districts for an ambiguous OSPHA code."""
|
|
313
|
+
for district in PRAGUE_DISTRICTS:
|
|
314
|
+
params = spis_zn.to_api_params(district)
|
|
315
|
+
if extra:
|
|
316
|
+
params.update(extra)
|
|
317
|
+
try:
|
|
318
|
+
result = self._post(path, params)
|
|
319
|
+
if result.get("udalosti") or result.get("stav"):
|
|
320
|
+
logger.info("Resolved OSPHA → %s for %s",
|
|
321
|
+
district, spis_zn.canonical())
|
|
322
|
+
return result
|
|
323
|
+
except requests.HTTPError as e:
|
|
324
|
+
if e.response is not None and e.response.status_code == 400:
|
|
325
|
+
continue
|
|
326
|
+
raise
|
|
327
|
+
raise ValueError(
|
|
328
|
+
f"Cannot find {spis_zn.canonical()} in any Prague district court"
|
|
329
|
+
)
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: infosoud
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Czech court case lookup tool (infosoud.gov.cz)
|
|
5
|
+
Author: pravnikovo.info
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://infosoud.pravnikovo.info
|
|
8
|
+
Project-URL: Repository, https://github.com/pravnikovo/infosoud
|
|
9
|
+
Keywords: czech,court,justice,infosoud,právní,soud
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Topic :: Office/Business
|
|
13
|
+
Classifier: Natural Language :: Czech
|
|
14
|
+
Requires-Python: >=3.8
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: requests>=2.20
|
|
18
|
+
Provides-Extra: web
|
|
19
|
+
Requires-Dist: flask>=2.0; extra == "web"
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# InfoSoud
|
|
23
|
+
|
|
24
|
+
Neoficiální klient pro [InfoSoud](https://infosoud.gov.cz) — vyhledávání v soudních řízeních České republiky.
|
|
25
|
+
|
|
26
|
+
Umožňuje vyhledat průběh soudního řízení, nařízená jednání a události podle spisové značky. Data pocházejí z veřejného API Ministerstva spravedlnosti ČR.
|
|
27
|
+
|
|
28
|
+
**[infosoud.pravnikovo.info](https://infosoud.pravnikovo.info)** — webové rozhraní
|
|
29
|
+
|
|
30
|
+
## Instalace
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install infosoud
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Použití
|
|
37
|
+
|
|
38
|
+
### Příkazový řádek
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Vyhledat řízení
|
|
42
|
+
infosoud "1 T 64/2024" OSSCEDC
|
|
43
|
+
infosoud "1T64_2024 OSSCEDC" # kompaktní formát
|
|
44
|
+
infosoud "4 T 21/2025 melnik" # název soudu místo kódu
|
|
45
|
+
|
|
46
|
+
# Zobrazit jednání
|
|
47
|
+
infosoud --hearings "1 T 64/2024" OSSCEDC
|
|
48
|
+
|
|
49
|
+
# JSON výstup
|
|
50
|
+
infosoud --json "1 T 64/2024" OSSCEDC
|
|
51
|
+
|
|
52
|
+
# CSV výstup (události)
|
|
53
|
+
infosoud --csv "1 T 64/2024" OSSCEDC
|
|
54
|
+
|
|
55
|
+
# Vypsat soudy
|
|
56
|
+
infosoud --courts
|
|
57
|
+
infosoud --courts --csv
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Python
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from infosoud import InfoSoudClient, parse_spis_zn
|
|
64
|
+
|
|
65
|
+
client = InfoSoudClient()
|
|
66
|
+
|
|
67
|
+
# Vyhledat řízení
|
|
68
|
+
case = client.search_case("1 T 64/2024", "OSSCEDC")
|
|
69
|
+
print(case["stav"]) # "nevyřízená věc"
|
|
70
|
+
print(case["organizace"]) # "Okresní soud Děčín"
|
|
71
|
+
|
|
72
|
+
for event in case["udalosti"]:
|
|
73
|
+
print(f"{event['datum']} {event['udalost']}")
|
|
74
|
+
|
|
75
|
+
# Vyhledat jednání
|
|
76
|
+
hearings = client.search_hearings("1 T 64/2024", "OSSCEDC")
|
|
77
|
+
for h in hearings["udalosti"]:
|
|
78
|
+
print(f"{h['datum']} {h['cas']} {h['druhJednani']} {h['resitel']}")
|
|
79
|
+
|
|
80
|
+
# Detail události (čas, jednací síň)
|
|
81
|
+
detail = client.get_event_detail("1 T 64/2024", "OSSCEDC", "NAR_JED", 48)
|
|
82
|
+
for attr in detail["atributy"]:
|
|
83
|
+
print(f"{attr['typ']}: {attr['hodnota']}")
|
|
84
|
+
|
|
85
|
+
# Spisová značka — tolerantní parser
|
|
86
|
+
spis = parse_spis_zn("1T64_2024")
|
|
87
|
+
print(spis.canonical()) # "1 T 64/2024"
|
|
88
|
+
print(spis.compact()) # "1T64_2024"
|
|
89
|
+
|
|
90
|
+
# Fuzzy vyhledání soudu
|
|
91
|
+
code = client.resolve_court_name("melnik") # → "OSSTCME"
|
|
92
|
+
code = client.resolve_court_name("praha 9") # → "OSPHA09"
|
|
93
|
+
|
|
94
|
+
# Seznam soudů
|
|
95
|
+
courts = client.build_court_map() # {kód: název} pro všech 104 soudů
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Formáty spisové značky
|
|
99
|
+
|
|
100
|
+
Parser je maximálně tolerantní — všechny tyto formáty jsou ekvivalentní:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
1 T 64/2024 1T64/2024 1T 64/2024
|
|
104
|
+
1 T64/2024 1T64_2024 1 T 64 / 2024
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Kód soudu lze přidat za sp. zn.: `1T64_2024 OSSCEDC`
|
|
108
|
+
|
|
109
|
+
Místo kódu soudu lze zadat název: `4 T 21/2025 melnik` (bez diakritiky)
|
|
110
|
+
|
|
111
|
+
## API endpointy
|
|
112
|
+
|
|
113
|
+
| Endpoint | Metoda | Popis |
|
|
114
|
+
|----------|--------|-------|
|
|
115
|
+
| `/api/v1/rizeni/vyhledej` | POST | Vyhledání řízení |
|
|
116
|
+
| `/api/v1/jednani/vyhledej` | POST | Vyhledání jednání |
|
|
117
|
+
| `/api/v1/udalost/vyhledej` | POST | Detail události |
|
|
118
|
+
| `/api/v1/organizace/lov` | GET | Seznam krajských/vrchních soudů |
|
|
119
|
+
| `/api/v1/organizace/podrizene/lov` | GET | Seznam okresních soudů |
|
|
120
|
+
|
|
121
|
+
Base URL: `https://infosoud.gov.cz/api/v1`
|
|
122
|
+
|
|
123
|
+
## Kódy soudů
|
|
124
|
+
|
|
125
|
+
Kompletní seznam 104 soudů (96 z API + 8 poboček):
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
infosoud --courts
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Příklady: `OSSCEDC` (OS Děčín), `OSPHA09` (OS Praha 9), `KSJIMBM` (KS Brno), `MSPHAAB` (MS Praha)
|
|
132
|
+
|
|
133
|
+
## Webové rozhraní
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
pip install infosoud[web]
|
|
137
|
+
python -m infosoud.web
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Otevře webserver na `http://localhost:8060` s vyhledávacím formulářem, timeline událostí, ICS exportem jednání a CSV exportem.
|
|
141
|
+
|
|
142
|
+
## Licence
|
|
143
|
+
|
|
144
|
+
MIT — viz [LICENSE](LICENSE)
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
*Neoficiální nástroj. Data pocházejí z [infosoud.gov.cz](https://infosoud.gov.cz). Projekt [pravnikovo.info](https://pravnikovo.info) — open source nástroje pro právníky.*
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
infosoud/__init__.py
|
|
5
|
+
infosoud/__main__.py
|
|
6
|
+
infosoud/client.py
|
|
7
|
+
infosoud.egg-info/PKG-INFO
|
|
8
|
+
infosoud.egg-info/SOURCES.txt
|
|
9
|
+
infosoud.egg-info/dependency_links.txt
|
|
10
|
+
infosoud.egg-info/entry_points.txt
|
|
11
|
+
infosoud.egg-info/requires.txt
|
|
12
|
+
infosoud.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
infosoud
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "infosoud"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Czech court case lookup tool (infosoud.gov.cz)"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.8"
|
|
12
|
+
authors = [{name = "pravnikovo.info"}]
|
|
13
|
+
keywords = ["czech", "court", "justice", "infosoud", "právní", "soud"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Topic :: Office/Business",
|
|
18
|
+
"Natural Language :: Czech",
|
|
19
|
+
]
|
|
20
|
+
dependencies = ["requests>=2.20"]
|
|
21
|
+
|
|
22
|
+
[project.optional-dependencies]
|
|
23
|
+
web = ["flask>=2.0"]
|
|
24
|
+
|
|
25
|
+
[project.scripts]
|
|
26
|
+
infosoud = "infosoud.__main__:main"
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://infosoud.pravnikovo.info"
|
|
30
|
+
Repository = "https://github.com/pravnikovo/infosoud"
|
infosoud-0.1.0/setup.cfg
ADDED