Edycja konfiguracji JSON

Zadanie 14 z 15 · rozdział 20Trudność: 2 z 3filesjsondict

Treść zadania

Plik konfiguracyjny w formacie JSON zawiera obiekt (w Pythonie: słownik), w którym mogą być zagnieżdżone kolejne obiekty. Wczytaj ścieżkę pliku, klucz i nową wartość. Klucz jest zapisany w notacji kropkowej: baza.port oznacza klucz port wewnątrz obiektu zapisanego pod kluczem baza.

Klucz istnieje, jeśli każda jego część poza ostatnią prowadzi do obiektu, a ostatnia część jest kluczem w tym obiekcie. Jeśli klucz istnieje:

  1. wypisz jego dotychczasową wartość,
  2. ustaw nową wartość — jako liczbę całkowitą, jeśli wczytany napis składa się z samych cyfr, ewentualnie poprzedzonych znakiem - (np. 8080, -5); w przeciwnym razie jako napis (np. 3.5, true, localhost),
  3. zapisz cały plik od nowa poleceniem json.dump(dane, plik, indent=2, ensure_ascii=False).

Dzięki takiemu zapisowi plik ma wcięcia po 2 spacje, klucze zostają w dotychczasowej kolejności, a polskie litery nie są zamieniane na kody \u…. Sprawdzarka porównuje plik po zmianie dokładnie z tym formatem (ignoruje tylko końcowe spacje i puste wiersze).

Dane wejściowe

  • 1. linia: ścieżka pliku
  • 2. linia: klucz w notacji kropkowej
  • 3. linia: nowa wartość

Dane wyjściowe

  • Dotychczasowa wartość klucza: napis bez cudzysłowów, liczba jako liczba.
  • Brak klucza: K — gdzie K to wczytany klucz — jeśli klucz nie istnieje. Plik pozostaje wtedy bez zmian.
  • Plik nie istnieje. — jeśli podana ścieżka nie wskazuje istniejącego pliku.

Ograniczenia

  • Plik zawiera poprawny JSON, którego główną wartością jest obiekt.
  • Wartość pod istniejącym kluczem jest napisem albo liczbą całkowitą. Pozostałe wartości w pliku mogą być dowolne (listy, true, null …).
  • Części klucza nie zawierają kropek.

Uwagi

  • Moduł json zamienia tekst JSON na słowniki, listy, napisy i liczby Pythona i z powrotem:
import json

with open("config.json", encoding="utf-8") as plik:
    dane = json.load(plik)          # np. {"baza": {"port": 5432}}

dane["baza"]["port"] = 6543

with open("config.json", "w", encoding="utf-8") as plik:
    json.dump(dane, plik, indent=2, ensure_ascii=False)
  • Do zagnieżdżonego obiektu dojdziesz pętlą po klucz.split("."): w każdym kroku sprawdź, czy bieżąca wartość jest słownikiem (isinstance(obiekt, dict)) i czy zawiera kolejną część klucza.

Przykłady

Pliki przed uruchomieniem
  • config.json
    {
      "nazwa": "Sklep",
      "baza": {
        "host": "localhost",
        "port": 5432
      },
      "wersja": "1.0"
    }
Wejście
config.json
baza.port
6543
Wyjście
5432
Pliki po uruchomieniu
  • config.json
    {
      "nazwa": "Sklep",
      "baza": {
        "host": "localhost",
        "port": 6543
      },
      "wersja": "1.0"
    }
Pliki przed uruchomieniem
  • config.json
    {"nazwa": "Sklep", "baza": {"host": "localhost"}}
Wejście
config.json
baza.port
6543
Wyjście
Brak klucza: baza.port
Pliki po uruchomieniu
  • config.json
    {"nazwa": "Sklep", "baza": {"host": "localhost"}}

W obiekcie baza nie ma klucza port, więc plik się nie zmienia.

Zasady obowiązujące w rozdziale 20

Poniższe zadania polegają na wczytywaniu danych ze standardowego wejścia (stdin), wykonywaniu operacji na plikach i folderach oraz wypisywaniu wyniku na standardowe wyjście (stdout).
Każde zadanie jest osobnym, niezależnym programem.

Konwencje wspólne:

  • Program działa na plikach w katalogu roboczym, czyli w folderze, w którym jest uruchamiany. Wszystkie ścieżki na wejściu są względne wobec katalogu roboczego i używają / jako separatora, np. dane/raport.txt. Ścieżki wczytuj jako całe linie — mogą zawierać spacje.
  • Sprawdzarka przed każdym testem tworzy nowy katalog roboczy z plikami opisanymi w teście, uruchamia program, a potem sprawdza zarówno wypisany tekst, jak i zawartość plików.
  • W przykładach Pliki przed: pokazuje zawartość katalogu roboczego przed uruchomieniem programu, a Pliki po: — stan wybranych plików po jego zakończeniu. Każda linia to ścieżka pliku, a linie zaczynające się od | to kolejne wiersze jego treści. Ścieżka zakończona / to pusty folder, (rozmiar: N B) oznacza plik o rozmiarze N bajtów, a (usunięty) — plik, którego po zakończeniu programu ma już nie być.
  • Pliki tekstowe są zapisane w kodowaniu UTF-8 — otwieraj je przez open(sciezka, encoding="utf-8").
  • Rozszerzenie to końcówka nazwy pliku od ostatniej kropki (razem z nią), np. archiwum.tar.gz ma rozszerzenie .gz. Rozszerzenia porównuj bez względu na wielkość liter (.TXT to też .txt).
  • Listy plików wypisuj po jednym w linii, jako ścieżki względem podanego folderu z separatorem / (np. 2024/raport.txt), posortowane rosnąco tak, jak sortuje napisy funkcja sorted(). Na Windowsie ścieżki mają separator \ — zamień go na / (np. metodą Path.as_posix()).
  • Komunikaty dla przypadków brzegowych wypisuj dokładnie w podanej postaci, np. Folder nie istnieje., Plik nie istnieje., Brak plików.
  • Program nie wypisuje komunikatów typu „Podaj ścieżkę:”. Tekst podany w input("…") jest ignorowany przez sprawdzarkę.

Zadanie pochodzi z otwartego zbioru Nauka-Programowania (z rozwiązaniami wzorcowymi). Zgłoś błąd w treści lub testach.

Python uruchomi się w przeglądarce przy pierwszym teście.

Kod zapisuje się automatycznie w tej przeglądarce. Tab wstawia wcięcie; aby opuścić edytor klawiaturą, naciśnij Esc, a potem Tab.

Testy

Program dostaje „Wejście” przez input() i musi wypisać „Oczekiwane wyjście”. Liczby porównywane są z tolerancją 0,01, a tekst podany w input("…") nie jest sprawdzany.

Test 1

Nie uruchomiono
Wejście
serwer.json
serwer.port
8080
Oczekiwane wyjście
80
Pliki przed uruchomieniem
  • serwer.json
    {"serwer": {"adres": "0.0.0.0", "port": 80}, "debug": true}
Pliki po uruchomieniu
  • serwer.json
    {
      "serwer": {
        "adres": "0.0.0.0",
        "port": 8080
      },
      "debug": true
    }

Test 2

Nie uruchomiono
Wejście
ustawienia.json
motyw
jasny
Oczekiwane wyjście
ciemny
Pliki przed uruchomieniem
  • ustawienia.json
    {
      "jezyk": "pl",
      "motyw": "ciemny"
    }
Pliki po uruchomieniu
  • ustawienia.json
    {
      "jezyk": "pl",
      "motyw": "jasny"
    }

Test 3

Nie uruchomiono
Wejście
czujnik.json
temperatura.min
-5
Oczekiwane wyjście
0
Pliki przed uruchomieniem
  • czujnik.json
    {"nazwa": "termometr", "temperatura": {"min": 0, "max": 30}}
Pliki po uruchomieniu
  • czujnik.json
    {
      "nazwa": "termometr",
      "temperatura": {
        "min": -5,
        "max": 30
      }
    }

Test 4

Nie uruchomiono
Wejście
app.json
wersja
3.5
Oczekiwane wyjście
3.4
Pliki przed uruchomieniem
  • app.json
    {"wersja": "3.4", "autor": "Ola"}
Pliki po uruchomieniu
  • app.json
    {
      "wersja": "3.5",
      "autor": "Ola"
    }

Test 5

Nie uruchomiono
Wejście
profil.json
autor.imię
Żaneta
Oczekiwane wyjście
Łukasz
Pliki przed uruchomieniem
  • profil.json
    {"powitanie": "Cześć", "autor": {"imię": "Łukasz", "tagi": ["a", "b"]}}
Pliki po uruchomieniu
  • profil.json
    {
      "powitanie": "Cześć",
      "autor": {
        "imię": "Żaneta",
        "tagi": [
          "a",
          "b"
        ]
      }
    }

Test 6

Nie uruchomiono
Wejście
gra.json
poziomy.latwy.czas
brak
Oczekiwane wyjście
120
Pliki przed uruchomieniem
  • gra.json
    {"poziomy": {"latwy": {"wrogowie": 3, "czas": 120}}, "dzwiek": null}
Pliki po uruchomieniu
  • gra.json
    {
      "poziomy": {
        "latwy": {
          "wrogowie": 3,
          "czas": "brak"
        }
      },
      "dzwiek": null
    }

Test 7

Nie uruchomiono
Wejście
config.json
baza.uzytkownik
admin
Oczekiwane wyjście
Brak klucza: baza.uzytkownik
Pliki przed uruchomieniem
  • config.json
    {"baza": {"host": "localhost"}}
Pliki po uruchomieniu
  • config.json
    {"baza": {"host": "localhost"}}

Test 8

Nie uruchomiono
Wejście
config.json
baza.port.numer
1
Oczekiwane wyjście
Brak klucza: baza.port.numer
Pliki przed uruchomieniem
  • config.json
    {"baza": {"port": 5432}}
Pliki po uruchomieniu
  • config.json
    {"baza": {"port": 5432}}

Test 9

Nie uruchomiono
Wejście
config.json
baza
1
Oczekiwane wyjście
Plik nie istnieje.
Pliki przed uruchomieniem
  • inne.json
    {}
Pliki po uruchomieniu
  • config.json(usunięty)
Uruchom z własnymi danymi