Skip to main content

KDM (K-water Data Model) SDK for water resource data access

Project description

KDM SDK

Python 3.10+ License: MIT Tests Beta

๐Ÿš€ ๋ฒ ํƒ€ ์˜คํ”ˆ - K-water Data Model (KDM) ๋ฐ์ดํ„ฐ๋ฅผ ์‰ฝ๊ฒŒ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋Š” Python SDK์ž…๋‹ˆ๋‹ค.

K-water Data Model (KDM)์€ water.or.kr/kdm ๊ธฐ๋ฐ˜์˜ ์ˆ˜์ž์› ๋ฐ์ดํ„ฐ ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค. ์ด SDK๋ฅผ ํ†ตํ•ด ๋Œ ์ˆ˜๋ฌธ ๋ฐ์ดํ„ฐ, ํ•˜์ฒœ ์ˆ˜์œ„, ๊ฐ•์šฐ๋Ÿ‰ ๋“ฑ์˜ ์ˆ˜์ž์› ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ„ํŽธํ•˜๊ฒŒ ์กฐํšŒํ•˜๊ณ  ๋ถ„์„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

English Documentation

์ฃผ์š” ๊ธฐ๋Šฅ

  • ์ง๊ด€์ ์ธ Query API - ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹์œผ๋กœ ๊ฐ„๋‹จํ•œ ์ฟผ๋ฆฌ ์ž‘์„ฑ
  • ๋ฐฐ์น˜ ์ฟผ๋ฆฌ - ์—ฌ๋Ÿฌ ์‹œ์„ค์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ‘๋ ฌ๋กœ ์กฐํšŒํ•˜์—ฌ ์„ฑ๋Šฅ ํ–ฅ์ƒ
  • ์ƒํ•˜๋ฅ˜ ์—ฐ๊ด€ ๋ถ„์„ - ๋Œ ๋ฐฉ๋ฅ˜๋Ÿ‰๊ณผ ํ•˜๋ฅ˜ ์ˆ˜์œ„์˜ ์ƒ๊ด€๊ด€๊ณ„ ๋ถ„์„
  • ๐Ÿ†• ๊ด€์ธก์†Œ ์ž๋™ ํƒ์ƒ‰ - ๋Œ์˜ ์ƒํ•˜๋ฅ˜ ๊ด€์ธก์†Œ ์ž๋™ ๊ฒ€์ƒ‰ (Basin ๋งค์นญ + ์ง€๋ฆฌ ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰)
  • ๐Ÿ†• ์›๋ณธ ์‹œ์„ค์ฝ”๋“œ ์ œ๊ณต - K-water, ํ™˜๊ฒฝ๋ถ€ ๋“ฑ ์›์ฒœ ๊ธฐ๊ด€์˜ ์‹œ์„ค์ฝ”๋“œ๋กœ ์™ธ๋ถ€ ์‹œ์Šคํ…œ ์—ฐ๋™
  • ํ…œํ”Œ๋ฆฟ ์‹œ์Šคํ…œ - YAML ๋˜๋Š” Python์œผ๋กœ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฟผ๋ฆฌ ํ…œํ”Œ๋ฆฟ ์ž‘์„ฑ
  • pandas ํ†ตํ•ฉ - ์กฐํšŒ ๊ฒฐ๊ณผ๋ฅผ DataFrame์œผ๋กœ ์ฆ‰์‹œ ๋ณ€ํ™˜
  • ๊ฐ„ํŽธํ•œ ๋‚ด๋ณด๋‚ด๊ธฐ - Excel, CSV, Parquet, JSON์œผ๋กœ ํ•œ ์ค„์— ์ €์žฅ
  • ์ž๋™ ํด๋ฐฑ - ์‹œ๊ฐ„ ๋‹จ์œ„ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์œผ๋ฉด ์ž๋™์œผ๋กœ ์ผ/์›” ๋‹จ์œ„ ์กฐํšŒ
  • ๋น„๋™๊ธฐ ์ง€์› - async/await ํŒจํ„ด์œผ๋กœ ํšจ์œจ์ ์ธ ๋ฐ์ดํ„ฐ ์กฐํšŒ
  • ํƒ€์ž… ํžŒํŠธ - ์ „์ฒด ์ฝ”๋“œ์— ํƒ€์ž… ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ IDE ์ง€์› ๊ฐ•ํ™”

SDK์˜ ์—ญํ• 

โœ… SDK๊ฐ€ ํ•˜๋Š” ์ผ

  • ๋ฐ์ดํ„ฐ ์กฐํšŒ: KDM ์ˆ˜์ž์› ๋ฐ์ดํ„ฐ๋ฅผ ์‰ฝ๊ฒŒ ์กฐํšŒ
  • ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜: pandas DataFrame์œผ๋กœ ์ž๋™ ๋ณ€ํ™˜
  • ๋ฐ์ดํ„ฐ ์ €์žฅ: Excel, CSV, Parquet, JSON์œผ๋กœ ํ•œ๊ธ€ ์ธ์ฝ”๋”ฉ ์ง€์›ํ•˜์—ฌ ์ €์žฅ

โŒ SDK๊ฐ€ ํ•˜์ง€ ์•Š๋Š” ์ผ

  • ์‹œ๊ฐํ™”: matplotlib, seaborn, plotly ๋“ฑ ์‚ฌ์šฉ
  • ํ†ต๊ณ„ ๋ถ„์„: pandas, scipy, numpy ๋“ฑ ์‚ฌ์šฉ
  • ๋ฐ์ดํ„ฐ ์ •์ œ: pandas ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ

์ฒ ํ•™: ์ด SDK๋Š” KDM ๋ฐ์ดํ„ฐ๋ฅผ pandas๋กœ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ๊นŒ์ง€๋งŒ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ์ดํ›„๋Š” ์—ฌ๋Ÿฌ๋ถ„์˜ ๋ฐ์ดํ„ฐ ๋ถ„์„ ๋Šฅ๋ ฅ์„ ํ™œ์šฉํ•˜์„ธ์š”!

examples/analyst_reference.py์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ ํ›„ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ถ„์„ ์˜ˆ์ œ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

์„ค์น˜

# PyPI์—์„œ ์„ค์น˜ (๊ถŒ์žฅ) โญ
pip install kdm-sdk

# ๋ฐ์ดํ„ฐ ๋ถ„์„๊ฐ€์šฉ (๋ถ„์„ ๋„๊ตฌ ํฌํ•จ)
pip install kdm-sdk[analyst]

# ๊ฐœ๋ฐœ์ž์šฉ (๊ฐœ๋ฐœ ๋„๊ตฌ ํฌํ•จ)
pip install kdm-sdk[dev]

# ๋˜๋Š” GitHub์—์„œ ์ตœ์‹  ๋ฒ„์ „ ์„ค์น˜
pip install git+https://github.com/kwatermywater/kdm-sdk.git

[analyst] ์˜ต์…˜์—๋Š” ๋‹ค์Œ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค: pandas, jupyter, matplotlib, seaborn, plotly, openpyxl, pyarrow, scipy, statsmodels

์š”๊ตฌ์‚ฌํ•ญ

  • Python 3.10 ์ด์ƒ
  • KDM MCP Server (์šด์˜ ์„œ๋ฒ„: http://203.237.1.4:8080)
  • pandas 2.0+

์ฒ˜์Œ ์‚ฌ์šฉํ•˜์‹œ๋‚˜์š”?

๐Ÿ“š ๋ฐ์ดํ„ฐ ๊ฐ€์ด๋“œ ๋ฐ”๋กœ๊ฐ€๊ธฐ - ์ˆ˜์ž์› ๋ฐ์ดํ„ฐ๊ฐ€ ์ฒ˜์Œ์ด์‹  ๋ถ„๋“ค์„ ์œ„ํ•œ ์นœ์ ˆํ•œ ์„ค๋ช…์„œ

๊ฐ€์ด๋“œ ๋‚ด์šฉ:

  • ์‹œ์„ค ์œ ํ˜• (๋Œ, ์ˆ˜์œ„๊ด€์ธก์†Œ, ์šฐ๋Ÿ‰๊ด€์ธก์†Œ ๋“ฑ)
  • ์‹œ๊ฐ„ ๋‹จ์œ„ (์‹œ๊ฐ„๋ณ„, ์ผ๋ณ„, ์›”๋ณ„) ๋ฐ ์กฐํšŒ ๊ธฐ๊ฐ„ ๐Ÿ“…
  • ์ธก์ • ํ•ญ๋ชฉ (์ €์ˆ˜์œจ, ์œ ์ž…๋Ÿ‰, ๋ฐฉ๋ฅ˜๋Ÿ‰ ๋“ฑ) ๐Ÿ“Š
  • ์‹œ์„ค ๊ฒ€์ƒ‰ ๋ฐฉ๋ฒ•
  • ์šฉ์–ด ์„ค๋ช… (์ €์ˆ˜์œ„, CMS, TOC ๋“ฑ)
  • ์ดˆ๋ณด์ž์šฉ ์˜ˆ์ œ

๋น ๋ฅธ ํŒ:

# ๐Ÿ’ก ์–ด๋–ค ๋Œ์ด ์žˆ๋Š”์ง€ ๋ชจ๋ฅผ ๋•Œ
results = await client.search_facilities(query="๋Œ", limit=10)

# ๐Ÿ’ก ์ธก์ • ํ•ญ๋ชฉ์ด ๋ญ๊ฐ€ ์žˆ๋Š”์ง€ ๋ชจ๋ฅผ ๋•Œ
items = await client.list_measurements(site_name="์†Œ์–‘๊ฐ•๋Œ")

# ๐Ÿ’ก ์‹œ๊ฐ„ ๋‹จ์œ„๋ฅผ ๋ชจ๋ฅผ ๋•Œ (์ž๋™ ์„ ํƒ)
result = await KDMQuery().site("์†Œ์–‘๊ฐ•๋Œ").measurements(["์ €์ˆ˜์œจ"]) \
    .days(7).time_key("auto").execute()

๋น ๋ฅธ ์‹œ์ž‘

๊ธฐ๋ณธ ์ฟผ๋ฆฌ (Fluent API)

import asyncio
from kdm_sdk import KDMQuery

async def main():
    # ๋Œ ์ €์ˆ˜์œจ ๋ฐ์ดํ„ฐ ์กฐํšŒ
    result = await KDMQuery() \
        .site("์†Œ์–‘๊ฐ•๋Œ", facility_type="dam") \
        .measurements(["์ €์ˆ˜์œจ", "์œ ์ž…๋Ÿ‰"]) \
        .days(7) \
        .execute()

    # pandas DataFrame์œผ๋กœ ๋ณ€ํ™˜
    df = result.to_dataframe()
    print(df.head())

asyncio.run(main())

๋ฐฐ์น˜ ์ฟผ๋ฆฌ (์—ฌ๋Ÿฌ ์‹œ์„ค ๋™์‹œ ์กฐํšŒ)

from kdm_sdk import KDMQuery

async def batch_query():
    query = KDMQuery()

    # ์—ฌ๋Ÿฌ ๋Œ ์ถ”๊ฐ€
    for dam in ["์†Œ์–‘๊ฐ•๋Œ", "์ถฉ์ฃผ๋Œ", "ํŒ”๋‹น๋Œ"]:
        query.site(dam, facility_type="dam") \
             .measurements(["์ €์ˆ˜์œจ"]) \
             .days(7) \
             .add()

    # ๋ณ‘๋ ฌ ์‹คํ–‰
    results = await query.execute_batch(parallel=True)

    # ๋‹จ์ผ DataFrame์œผ๋กœ ํ†ตํ•ฉ
    combined_df = results.aggregate()
    print(combined_df.groupby("site_name")["์ €์ˆ˜์œจ"].mean())

asyncio.run(batch_query())

์ƒํ•˜๋ฅ˜ ์ƒ๊ด€๊ด€๊ณ„ ๋ถ„์„

from kdm_sdk import FacilityPair

async def correlation_analysis():
    # ๋Œ ๋ฐฉ๋ฅ˜๊ฐ€ ํ•˜๋ฅ˜ ์ˆ˜์œ„์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ ๋ถ„์„
    from kdm_sdk import KDMClient
    import pandas as pd

    async with KDMClient() as client:
        # ์ƒ๋ฅ˜ ๋ฐ์ดํ„ฐ ์กฐํšŒ (๋Œ)
        upstream_result = await client.get_water_data(
            site_name="์†Œ์–‘๊ฐ•๋Œ",
            facility_type="dam",
            measurement_items=["๋ฐฉ๋ฅ˜๋Ÿ‰"],
            days=30,
            time_key="h_1"
        )

        # ํ•˜๋ฅ˜ ๋ฐ์ดํ„ฐ ์กฐํšŒ (์ˆ˜์œ„๊ด€์ธก์†Œ)
        downstream_result = await client.get_water_data(
            site_name="์ถ˜์ฒœ์‹œ(์ถ˜์ฒœ๋Œํ•˜๋ฅ˜)",
            facility_type="water_level",
            measurement_items=["์ˆ˜์œ„"],
            days=30,
            time_key="h_1"
        )

        # DataFrame ๋ณ€ํ™˜
        def to_df(data):
            records = []
            for item in data:
                record = {"datetime": item.get("datetime")}
                if "values" in item:
                    for key, val in item["values"].items():
                        record[key] = val.get("value")
                records.append(record)
            df = pd.DataFrame(records)
            if "datetime" in df.columns:
                df["datetime"] = pd.to_datetime(df["datetime"])
                df.set_index("datetime", inplace=True)
            return df

        upstream_df = to_df(upstream_result.get("data", []))
        downstream_df = to_df(downstream_result.get("data", []))

        # FacilityPair ์ƒ์„ฑ
        pair = FacilityPair(
            upstream_name="์†Œ์–‘๊ฐ•๋Œ",
            downstream_name="์ถ˜์ฒœ์‹œ(์ถ˜์ฒœ๋Œํ•˜๋ฅ˜)",
            upstream_type="dam",
            downstream_type="water_level",
            upstream_data=upstream_df,
            downstream_data=downstream_df
        )

        # ์ตœ์  ์‹œ๊ฐ„์ฐจ ์ฐพ๊ธฐ
        correlation = pair.find_optimal_lag(max_lag_hours=12)
        print(f"์ตœ์  ์‹œ๊ฐ„์ฐจ: {correlation.lag_hours:.1f}์‹œ๊ฐ„")
        print(f"์ƒ๊ด€๊ณ„์ˆ˜: {correlation.correlation:.3f}")

asyncio.run(correlation_analysis())

ํ…œํ”Œ๋ฆฟ ๊ธฐ๋ฐ˜ ์ฟผ๋ฆฌ

from kdm_sdk.templates import TemplateBuilder

async def template_query():
    # ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํ…œํ”Œ๋ฆฟ ์ƒ์„ฑ
    template = TemplateBuilder("์ฃผ๊ฐ„ ๋Œ ๋ชจ๋‹ˆํ„ฐ๋ง") \
        .site("์†Œ์–‘๊ฐ•๋Œ", facility_type="dam") \
        .measurements(["์ €์ˆ˜์œจ", "์œ ์ž…๋Ÿ‰", "๋ฐฉ๋ฅ˜๋Ÿ‰"]) \
        .days(7) \
        .time_key("h_1") \
        .build()

    # ํ…œํ”Œ๋ฆฟ ์‹คํ–‰
    result = await template.execute()
    df = result.to_dataframe()

    # ํ…œํ”Œ๋ฆฟ ์ €์žฅํ•˜์—ฌ ์žฌ์‚ฌ์šฉ
    template.save_yaml("templates/weekly_monitoring.yaml")

asyncio.run(template_query())

๊ด€์ธก์†Œ ์ž๋™ ํƒ์ƒ‰ (์‹ ๊ทœ ๊ธฐ๋Šฅ)

from kdm_sdk import KDMClient

async def find_stations():
    async with KDMClient() as client:
        # ๋Œ์˜ ํ•˜๋ฅ˜ ์ˆ˜์œ„๊ด€์ธก์†Œ ์ž๋™ ๊ฒ€์ƒ‰
        result = await client.find_related_stations(
            dam_name="์†Œ์–‘๊ฐ•๋Œ",
            direction="downstream",
            station_type="water_level"
        )

        # ๋Œ ์ •๋ณด (์›๋ณธ ์‹œ์„ค์ฝ”๋“œ ํฌํ•จ)
        dam = result['dam']
        print(f"๋Œ: {dam['site_name']}")
        print(f"์›๋ณธ์ฝ”๋“œ: {dam['original_facility_code']}")  # K-water ์ฝ”๋“œ

        # ๊ด€๋ จ ๊ด€์ธก์†Œ ๋ชฉ๋ก
        for station in result['stations']:
            print(f"- {station['site_name']}: {station['original_facility_code']}")
            print(f"  ๋งค์นญ๋ฐฉ์‹: {station['match_type']}")  # basin or geographic
            print(f"  ๊ฑฐ๋ฆฌ: {station['distance_km']:.1f} km")

asyncio.run(find_stations())

๋ฌธ์„œ

ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

kdm-sdk/
โ”œโ”€โ”€ src/
โ”‚   โ””โ”€โ”€ kdm_sdk/
โ”‚       โ”œโ”€โ”€ __init__.py           # ํŒจํ‚ค์ง€ exports
โ”‚       โ”œโ”€โ”€ client.py             # MCP ํด๋ผ์ด์–ธํŠธ
โ”‚       โ”œโ”€โ”€ query.py              # Fluent query API
โ”‚       โ”œโ”€โ”€ results.py            # ๊ฒฐ๊ณผ ๋ž˜ํผ
โ”‚       โ”œโ”€โ”€ facilities.py         # FacilityPair
โ”‚       โ””โ”€โ”€ templates/            # ํ…œํ”Œ๋ฆฟ ์‹œ์Šคํ…œ
โ”‚           โ”œโ”€โ”€ builder.py        # TemplateBuilder
โ”‚           โ”œโ”€โ”€ base.py           # Template ๊ธฐ๋ณธ ํด๋ž˜์Šค
โ”‚           โ””โ”€โ”€ loaders.py        # YAML/Python ๋กœ๋”
โ”œโ”€โ”€ tests/                        # ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ
โ”œโ”€โ”€ examples/                     # ์‚ฌ์šฉ ์˜ˆ์ œ
โ”‚   โ”œโ”€โ”€ basic_usage.py           # KDMClient ์˜ˆ์ œ
โ”‚   โ”œโ”€โ”€ query_usage.py           # Query API ์˜ˆ์ œ
โ”‚   โ”œโ”€โ”€ facility_pair_usage.py   # FacilityPair ์˜ˆ์ œ
โ”‚   โ””โ”€โ”€ templates/               # ํ…œํ”Œ๋ฆฟ ์˜ˆ์ œ
โ”œโ”€โ”€ docs/                         # ๋ฌธ์„œ
โ””โ”€โ”€ README.md                     # ์ด ํŒŒ์ผ

์˜ˆ์ œ

examples/ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ์ „์ฒด ์˜ˆ์ œ๋ฅผ ํ™•์ธํ•˜์„ธ์š”:

ํ…Œ์ŠคํŠธ

# ์ „์ฒด ํ…Œ์ŠคํŠธ ์‹คํ–‰
pytest

# ํŠน์ • ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ ์‹คํ–‰
pytest tests/test_query.py -v

# ์ปค๋ฒ„๋ฆฌ์ง€ ์ธก์ •
pytest --cov=kdm_sdk --cov-report=html

# ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋งŒ ์‹คํ–‰
pytest -m unit

# ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ์‹คํ–‰ (MCP ์„œ๋ฒ„ ํ•„์š”)
pytest -m integration

์ฃผ์š” ์‚ฌ์šฉ ์‚ฌ๋ก€

1. ์—ฌ๋Ÿฌ ๋Œ ๋ชจ๋‹ˆํ„ฐ๋ง

query = KDMQuery()
for dam in ["์†Œ์–‘๊ฐ•๋Œ", "์ถฉ์ฃผ๋Œ", "ํŒ”๋‹น๋Œ", "๋Œ€์ฒญ๋Œ"]:
    query.site(dam).measurements(["์ €์ˆ˜์œจ"]).days(30).add()

results = await query.execute_batch(parallel=True)
df = results.aggregate()

2. ์ „๋…„ ๋Œ€๋น„ ๋น„๊ต

result = await KDMQuery() \
    .site("์žฅํฅ๋Œ") \
    .measurements(["์ €์ˆ˜์œจ"]) \
    .date_range("2024-06-01", "2024-06-30") \
    .compare_with_previous_year() \
    .execute()

3. ํ•˜๋ฅ˜ ์ˆ˜์œ„ ์˜ˆ์ธก

from kdm_sdk import KDMClient, FacilityPair
import pandas as pd

async with KDMClient() as client:
    # ์ƒ๋ฅ˜ ๋ฐ์ดํ„ฐ (๋Œ)
    upstream_result = await client.get_water_data(
        site_name="์†Œ์–‘๊ฐ•๋Œ",
        facility_type="dam",
        measurement_items=["๋ฐฉ๋ฅ˜๋Ÿ‰"],
        days=365,
        time_key="h_1"
    )

    # ํ•˜๋ฅ˜ ๋ฐ์ดํ„ฐ (๋Œ)
    downstream_result = await client.get_water_data(
        site_name="์˜์•”๋Œ",
        facility_type="dam",
        measurement_items=["์ˆ˜์œ„"],
        days=365,
        time_key="h_1"
    )

    # DataFrame ๋ณ€ํ™˜
    def to_df(data):
        records = []
        for item in data:
            record = {"datetime": item.get("datetime")}
            if "values" in item:
                for key, val in item["values"].items():
                    record[key] = val.get("value")
            records.append(record)
        df = pd.DataFrame(records)
        if "datetime" in df.columns:
            df["datetime"] = pd.to_datetime(df["datetime"])
            df.set_index("datetime", inplace=True)
        return df

    upstream_df = to_df(upstream_result.get("data", []))
    downstream_df = to_df(downstream_result.get("data", []))

    # FacilityPair ์ƒ์„ฑ
    pair = FacilityPair(
        upstream_name="์†Œ์–‘๊ฐ•๋Œ",
        downstream_name="์˜์•”๋Œ",
        upstream_data=upstream_df,
        downstream_data=downstream_df
    )

    # ์‹œ๊ฐ„์ฐจ๋ฅผ ๊ณ ๋ คํ•˜์—ฌ DataFrame ์ƒ์„ฑ (๋ฌผ์ด ์ด๋™ํ•˜๋Š”๋ฐ 5.5์‹œ๊ฐ„ ์†Œ์š”)
    df = pair.to_dataframe(lag_hours=5.5)

    # ๋จธ์‹ ๋Ÿฌ๋‹ ๋ชจ๋ธ ํ•™์Šต์— ์‚ฌ์šฉ
    X = df[["์†Œ์–‘๊ฐ•๋Œ_๋ฐฉ๋ฅ˜๋Ÿ‰"]]
    y = df["์˜์•”๋Œ_์ˆ˜์œ„"]

๊ฐœ๋ฐœ

ํ…Œ์ŠคํŠธ ์ฃผ๋„ ๊ฐœ๋ฐœ (TDD)

์ด ํ”„๋กœ์ ํŠธ๋Š” TDD ๋ฐฉ๋ฒ•๋ก ์œผ๋กœ ๊ฐœ๋ฐœ๋˜์—ˆ์Šต๋‹ˆ๋‹ค:

  1. Red - ์‹คํŒจํ•˜๋Š” ํ…Œ์ŠคํŠธ ๋จผ์ € ์ž‘์„ฑ
  2. Green - ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ•˜๋Š” ์ตœ์†Œํ•œ์˜ ์ฝ”๋“œ ๊ตฌํ˜„
  3. Refactor - ์ฝ”๋“œ ํ’ˆ์งˆ ๊ฐœ์„ 

ํ…Œ์ŠคํŠธ ์‹คํ–‰

# ๊ฐœ๋ฐœ ์˜์กด์„ฑ ์„ค์น˜
pip install -r requirements-dev.txt

# ํ…Œ์ŠคํŠธ ์‹คํ–‰
pytest -v

# ์ฝ”๋“œ ํฌ๋งทํŒ…
black src tests

# ํƒ€์ž… ์ฒดํฌ
mypy src

๊ธฐ์—ฌํ•˜๊ธฐ

๊ธฐ์—ฌ๋ฅผ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค! PR ์ œ์ถœ ์ „ ๋ชจ๋“  ํ…Œ์ŠคํŠธ๊ฐ€ ํ†ต๊ณผํ•˜๋Š”์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”.

  1. ์ €์žฅ์†Œ ํฌํฌ
  2. ๊ธฐ๋Šฅ ๋ธŒ๋žœ์น˜ ์ƒ์„ฑ
  3. ์ƒˆ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€
  4. ๋ชจ๋“  ํ…Œ์ŠคํŠธ ํ†ต๊ณผ ํ™•์ธ: pytest
  5. ์ฝ”๋“œ ํฌ๋งทํŒ…: black src tests
  6. Pull Request ์ œ์ถœ

๋ผ์ด์„ ์Šค

MIT License - ์ž์„ธํ•œ ๋‚ด์šฉ์€ LICENSE ํŒŒ์ผ์„ ์ฐธ์กฐํ•˜์„ธ์š”.

์ง€์›

๋ฌธ์˜์‚ฌํ•ญ ๋ฐ ์ด์Šˆ:

  • ์ €์žฅ์†Œ์— ์ด์Šˆ ์ƒ์„ฑ
  • ๋ฐ์ดํ„ฐ ๊ฐ€์ด๋“œ๋Š” DATA_GUIDE.md ์ฐธ์กฐ
  • ์‚ฌ์šฉ ํŒจํ„ด์€ ์˜ˆ์ œ ํ™•์ธ

๋ณ€๊ฒฝ ์ด๋ ฅ

๋ฒ„์ „ ํžˆ์Šคํ† ๋ฆฌ๋Š” CHANGELOG.md๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

๊ฐ์‚ฌ์˜ ๊ธ€

  • K-water์˜ ํ•œ๊ตญ ๋Œ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์„ ์œ„ํ•ด ๊ฐœ๋ฐœ๋˜์—ˆ์Šต๋‹ˆ๋‹ค
  • ๋ฐ์ดํ„ฐ ์ ‘๊ทผ์„ ์œ„ํ•ด MCP (Model Context Protocol) ์‚ฌ์šฉ
  • ํ…Œ์ŠคํŠธ ์ฃผ๋„ ๊ฐœ๋ฐœ(TDD) ๋ฐฉ๋ฒ•๋ก ์œผ๋กœ ๊ฐœ๋ฐœ๋˜์—ˆ์Šต๋‹ˆ๋‹ค

๋ฒ ํƒ€ ์˜คํ”ˆ ์•ˆ๋‚ด

โš ๏ธ ํ˜„์žฌ ๋ฒ ํƒ€ ๋ฒ„์ „์ž…๋‹ˆ๋‹ค.

์ด SDK๋Š” ๋ฒ ํƒ€ ํ…Œ์ŠคํŠธ ๋‹จ๊ณ„์— ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์— ์ถฉ๋ถ„ํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ด์ฃผ์„ธ์š”.

์•Œ๋ ค์ง„ ์ œํ•œ์‚ฌํ•ญ:

  • ์ผ๋ถ€ ์ธก์ • ํ•ญ๋ชฉ์€ ๋ฐ์ดํ„ฐ ๊ฐ€์šฉ์„ฑ์— ๋”ฐ๋ผ ์กฐํšŒ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
  • MCP ์„œ๋ฒ„ ์‘๋‹ต ์‹œ๊ฐ„์€ ๋„คํŠธ์›Œํฌ ์ƒํƒœ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

ํ”ผ๋“œ๋ฐฑ:

  • GitHub Issues๋ฅผ ํ†ตํ•ด ๋ฒ„๊ทธ ๋ฆฌํฌํŠธ ๋ฐ ๊ธฐ๋Šฅ ์ œ์•ˆ์„ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค
  • ๋ฒ ํƒ€ ํ…Œ์Šคํ„ฐ๋ถ„๋“ค์˜ ํ”ผ๋“œ๋ฐฑ์ด SDK ๊ฐœ์„ ์— ํฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค

๋ฌธ์˜: GitHub Issues ๋˜๋Š” K-water ๋‹ด๋‹น์ž์—๊ฒŒ ์—ฐ๋ฝํ•ด์ฃผ์„ธ์š”.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kdm_sdk-0.2.1b0.tar.gz (88.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

kdm_sdk-0.2.1b0-py3-none-any.whl (32.5 kB view details)

Uploaded Python 3

File details

Details for the file kdm_sdk-0.2.1b0.tar.gz.

File metadata

  • Download URL: kdm_sdk-0.2.1b0.tar.gz
  • Upload date:
  • Size: 88.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.7

File hashes

Hashes for kdm_sdk-0.2.1b0.tar.gz
Algorithm Hash digest
SHA256 0ddeddabde4f82248406c8fd19df45783ca706d5afc6a436209bee7e16d8c87b
MD5 e91caecc178e9eb42c2e66cd1a1aac54
BLAKE2b-256 582247e41fa36fd8a75818c41f75115257d511f802357723ff76301b6aada430

See more details on using hashes here.

File details

Details for the file kdm_sdk-0.2.1b0-py3-none-any.whl.

File metadata

  • Download URL: kdm_sdk-0.2.1b0-py3-none-any.whl
  • Upload date:
  • Size: 32.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.7

File hashes

Hashes for kdm_sdk-0.2.1b0-py3-none-any.whl
Algorithm Hash digest
SHA256 c806f4ea069a900924eb0493ba9b4dbe3b338d4464ab17a0f54fc3d9ec6cd661
MD5 85882c61c73012fbe18164d8a682a6a6
BLAKE2b-256 7eb333b24e2239565a5688b4c7d6a6ea159a512e607c5beb8ec399f1afd1fbf8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page