diff --git a/docs/conf.py b/docs/conf.py index 4942648..b07de50 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,6 +26,7 @@ 'sphinx_copybutton', 'autodoc2', 'sphinx_inline_tabs', + 'sphinx_tippy', ] templates_path = ['_templates'] @@ -61,6 +62,10 @@ autodoc2_module_all_regexes = [ # r'tdk\..*', ] +autodoc2_hidden_objects = {"inherited", "undoc"} +autodoc2_replace_annotations = [ + ("tdk.etc.tools.T", "T"), +] # -- Options for intersphinx # https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html#configuration diff --git a/poetry.lock b/poetry.lock index cbc5db3..0fb43e8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1644,6 +1644,27 @@ sphinx = ">=3" doc = ["furo", "myst-parser"] test = ["pytest", "pytest-cov", "pytest-xdist"] +[[package]] +name = "sphinx-tippy" +version = "0.4.3" +description = "Get rich tool tips in your sphinx documentation!" +optional = false +python-versions = ">=3.8" +files = [ + {file = "sphinx_tippy-0.4.3-py3-none-any.whl", hash = "sha256:572b0e001baec9b03e2b19ec4e9760ca1a853f4c3226b5cea251f477b2c2b096"}, + {file = "sphinx_tippy-0.4.3.tar.gz", hash = "sha256:255abee0aed8085fdb9ab0cc595cd7a45748ae7f4662156e500a17a3f73ad63d"}, +] + +[package.dependencies] +beautifulsoup4 = "*" +jinja2 = "*" +requests = "*" +sphinx = ">4" + +[package.extras] +docs = ["furo", "myst-parser"] +testing = ["pytest", "pytest-regressions", "sphinx-pytest"] + [[package]] name = "sphinxcontrib-applehelp" version = "2.0.0" @@ -2085,4 +2106,4 @@ propcache = ">=0.2.0" [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "a588d62f8dc6d1145d787c93717ed87b0be822e3bdb617289c5ac63d5bde72f1" +content-hash = "2ef8fa44818e5fad2e43c908abd5f9f0b973fc7f2ed899b719cb4911ca8ffeca" diff --git a/pyproject.toml b/pyproject.toml index dc6d6c4..31928b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,6 +60,7 @@ sphinx-autobuild = "^2024.10.3" sphinx-autodoc2 = "^0.5.0" sphinx-copybutton = "^0.5.2" sphinx-inline-tabs = "^2023.4.21" +sphinx-tippy = "^0.4.3" [tool.poetry-dynamic-versioning] enable = true diff --git a/src/tdk/__init__.py b/src/tdk/__init__.py index 27e4421..12178d8 100644 --- a/src/tdk/__init__.py +++ b/src/tdk/__init__.py @@ -1,4 +1,26 @@ +""" +`tdk` is the top-level package that forms the collection of modules that provide +access to various dictionaries from the Turkish Language Association (TDK) +and tools about the Turkish language. + +Each submodule provides access to a different dictionary from the +Turkish Language Association (TDK). + +If you do not care about niche dictionaries, you probably want the +{py:mod}`tdk.gts` module, which provides access to the +Güncel Türkçe Sözlük[^gts]. + +[^gts]: Updated Turkish Dictionary + +Each function comes with a synchronous and an asynchronous version. +An async function `foo` has a synchronous counterpart `foo_sync`. +Each function can optionally take an `http_session` parameter to use +an existing []() for the HTTP requests. +If not provided, a new session is created and managed by the function using +[](<#session_maker>). +""" + __version__ = "0.0.0" +"""At runtime, holds the human-readable version of the installed version.""" __version_tuple__ = (0, 0, 0) - -from tdk import dictionaries, etc +"""At runtime, holds the version of the installed package as a tuple of ints.""" diff --git a/src/tdk/etc/__init__.py b/src/tdk/etc/__init__.py index 64e8a44..2546917 100644 --- a/src/tdk/etc/__init__.py +++ b/src/tdk/etc/__init__.py @@ -1 +1,8 @@ +""" +This subpackage contains additional tools and data to be used with the library. + +The submodules within this package are available as aliases in this subpackage, +so you can import them directly from the `tdk.etc` package. +""" + from tdk.etc import alphabet, enums, tools diff --git a/src/tdk/etc/alphabet.py b/src/tdk/etc/alphabet.py index 56cf59a..b3b6de7 100644 --- a/src/tdk/etc/alphabet.py +++ b/src/tdk/etc/alphabet.py @@ -1,4 +1,12 @@ +""" +This module containts constants about the Turkish alphabet. +""" + VOWELS = "aeıioöuü" +"""Vowels of the Turkish alphabet in lowercase.""" LONG_VOWELS = "âîû" +"""Vowels of the Turkish alphabet with circumflexes in lowercase.""" CONSONANTS = "bcçdfgğhjklmnprsştvyz" +"""Consonants of the Turkish alphabet in lowercase.""" ALPHABET = "abcçdefgğhıijklmnoöprsştuüvyz" +"""The Turkish alphabet in lowercase.""" diff --git a/src/tdk/etc/enums.py b/src/tdk/etc/enums.py index b1222d8..b3b70b5 100644 --- a/src/tdk/etc/enums.py +++ b/src/tdk/etc/enums.py @@ -1,24 +1,44 @@ +""" +This module containts enums and data classes used in the TDK package. +""" + +from __future__ import annotations + from enum import Enum, IntEnum -from typing import Annotated -from pydantic import BaseModel, Field, AliasChoices, WrapValidator +from pydantic import BaseModel, Field, AliasChoices class LetterType(Enum): + """Letter types for Turkish alphabet.""" SHORT_VOWEL = 0 + """The letter is contained in .""" LONG_VOWEL = 1 + """The letter is contained in .""" CONSONANT = 2 + """The letter is contained in .""" class SyllableType(Enum): + """Syllable types according to aruz prosody rules.""" OPEN = 0 + """The syllable ends with a vowel.""" CLOSED = 1 + """The syllable ends with a consonant.""" MEDLI = 2 + """The syllable has a long vowel or has two consecutive consonants.""" class OriginLanguage(IntEnum): + """Languages that the words from {py:mod}`tdk.gts` can be from. + + Numbers are the IDs of the languages as seen in the TDK database. + """ + ORIGINAL = 0 + """The word is originally Turkish.""" COMPOUND = 19 + """The word is a compound word with parts from more than one language.""" ARABIC = 11 PERSIAN = 12 @@ -40,7 +60,12 @@ class OriginLanguage(IntEnum): ALBANIAN = 348 MONGOLIAN = 354 + """Mongolian language.""" MONGOLIAN_2 = 153 + """Also Mongolian language. + + There are two IDs for the same language in the TDK database. + """ FINNISH = 392 ROMAIC = 393 @@ -50,24 +75,48 @@ class OriginLanguage(IntEnum): class PropertyKind(IntEnum): + """Kinds of properties that can be assigned to a word meaning.""" FIELD = 1 + """The property is a field of study.""" PART_OF_SPEECH = 3 + """The property is a part of speech.""" TONE = 4 + """The property is a tone or style of speech.""" class PropertyData(BaseModel): + """Data class for properties of word meanings.""" id: int = Field(validation_alias=AliasChoices("id", "ozellik_id")) + """The ID of the property in the TDK database.""" kind: PropertyKind = Field(validation_alias=AliasChoices("kind", "tur")) + """The kind of the property.""" full_name: str = Field( validation_alias=AliasChoices("full_name", "tam_adi") ) + """The full name of the property.""" short_name: str = Field( validation_alias=AliasChoices("short_name", "kisa_adi") ) + """The short name of the property.""" number: int = Field(validation_alias=AliasChoices("number", "ekno")) + """The additional number of the property in the TDK database (`ekno`).""" class MeaningProperty(Enum): + """List of properties seen in the TDK database.""" + + @staticmethod + def get(arg: int | str) -> MeaningProperty: + """Get a from its ID, full or short name. + + :param arg: The ID, full or short name of the property. + :returns: The property, as a enum member. + """ + if isinstance(arg, dict): + return _property_table[int(arg["ozellik_id"])] + return _property_table[arg] + + # region Members EXCLAMATION = PropertyData( id=18, kind=PropertyKind.PART_OF_SPEECH, @@ -75,6 +124,13 @@ class MeaningProperty(Enum): short_name="ünl.", number=29, ) + """ + :param id: `18` + :param kind: [`PART_OF_SPEECH`]() + :param full_name: `"ünlem"` + :param short_name: `"ünl."` + :param number: `29` + """ NOUN = PropertyData( id=19, kind=PropertyKind.PART_OF_SPEECH, @@ -82,6 +138,13 @@ class MeaningProperty(Enum): short_name="a.", number=30, ) + """ + :param id: `19` + :param kind: [`PART_OF_SPEECH`]() + :param full_name: `"isim"` + :param short_name: `"a."` + :param number: `30` + """ ADJECTIVE = PropertyData( id=20, kind=PropertyKind.PART_OF_SPEECH, @@ -89,6 +152,13 @@ class MeaningProperty(Enum): short_name="sf.", number=31, ) + """ + :param id: `20` + :param kind: [`PART_OF_SPEECH`]() + :param full_name: `"sıfat"` + :param short_name: `"sf."` + :param number: `31` + """ DATIVE = PropertyData( id=21, kind=PropertyKind.PART_OF_SPEECH, @@ -96,6 +166,13 @@ class MeaningProperty(Enum): short_name="-e", number=32, ) + """ + :param id: `21` + :param kind: [`PART_OF_SPEECH`]() + :param full_name: `"-e"` + :param short_name: `"-e"` + :param number: `32` + """ ACCUSATIVE = PropertyData( id=22, kind=PropertyKind.PART_OF_SPEECH, @@ -103,6 +180,13 @@ class MeaningProperty(Enum): short_name="-i", number=33, ) + """ + :param id: `22` + :param kind: [`PART_OF_SPEECH`]() + :param full_name: `"-i"` + :param short_name: `"-i"` + :param number: `33` + """ INTRANSITIVE = PropertyData( id=23, kind=PropertyKind.PART_OF_SPEECH, @@ -110,6 +194,13 @@ class MeaningProperty(Enum): short_name="nsz.", number=34, ) + """ + :param id: `23` + :param kind: [`PART_OF_SPEECH`]() + :param full_name: `"nesnesiz"` + :param short_name: `"nsz."` + :param number: `34` + """ ADVERB = PropertyData( id=24, kind=PropertyKind.PART_OF_SPEECH, @@ -117,6 +208,13 @@ class MeaningProperty(Enum): short_name="zf.", number=35, ) + """ + :param id: `24` + :param kind: [`PART_OF_SPEECH`]() + :param full_name: `"zarf"` + :param short_name: `"zf."` + :param number: `35` + """ BY = PropertyData( id=25, kind=PropertyKind.PART_OF_SPEECH, @@ -124,6 +222,13 @@ class MeaningProperty(Enum): short_name="-le", number=36, ) + """ + :param id: `25` + :param kind: [`PART_OF_SPEECH`]() + :param full_name: `"-le"` + :param short_name: `"-le"` + :param number: `36` + """ ABLATIVE = PropertyData( id=26, kind=PropertyKind.PART_OF_SPEECH, @@ -131,6 +236,13 @@ class MeaningProperty(Enum): short_name="-den", number=37, ) + """ + :param id: `26` + :param kind: [`PART_OF_SPEECH`]() + :param full_name: `"-den"` + :param short_name: `"-den"` + :param number: `37` + """ PARTICLE = PropertyData( id=27, kind=PropertyKind.PART_OF_SPEECH, @@ -138,6 +250,13 @@ class MeaningProperty(Enum): short_name="e.", number=38, ) + """ + :param id: `27` + :param kind: [`PART_OF_SPEECH`]() + :param full_name: `"edat"` + :param short_name: `"e."` + :param number: `38` + """ CONJUNCTION = PropertyData( id=28, kind=PropertyKind.PART_OF_SPEECH, @@ -145,6 +264,13 @@ class MeaningProperty(Enum): short_name="bağ.", number=39, ) + """ + :param id: `28` + :param kind: [`PART_OF_SPEECH`]() + :param full_name: `"bağlaç"` + :param short_name: `"bağ."` + :param number: `39` + """ PRONOUN = PropertyData( id=29, kind=PropertyKind.PART_OF_SPEECH, @@ -152,6 +278,13 @@ class MeaningProperty(Enum): short_name="zm.", number=40, ) + """ + :param id: `29` + :param kind: [`PART_OF_SPEECH`]() + :param full_name: `"zamir"` + :param short_name: `"zm."` + :param number: `40` + """ SLANG = PropertyData( id=30, kind=PropertyKind.TONE, @@ -159,6 +292,13 @@ class MeaningProperty(Enum): short_name="argo", number=41, ) + """ + :param id: `30` + :param kind: [`TONE`]() + :param full_name: `"argo"` + :param short_name: `"argo"` + :param number: `41` + """ OBSOLETE = PropertyData( id=31, kind=PropertyKind.TONE, @@ -166,6 +306,13 @@ class MeaningProperty(Enum): short_name="esk.", number=42, ) + """ + :param id: `31` + :param kind: [`TONE`]() + :param full_name: `"eskimiş"` + :param short_name: `"esk."` + :param number: `42` + """ METAPHOR = PropertyData( id=32, kind=PropertyKind.TONE, @@ -173,6 +320,13 @@ class MeaningProperty(Enum): short_name="mec.", number=43, ) + """ + :param id: `32` + :param kind: [`TONE`]() + :param full_name: `"mecaz"` + :param short_name: `"mec."` + :param number: `43` + """ LAY = PropertyData( id=33, kind=PropertyKind.TONE, @@ -180,6 +334,13 @@ class MeaningProperty(Enum): short_name="hlk.", number=44, ) + """ + :param id: `33` + :param kind: [`TONE`]() + :param full_name: `"halk ağzında"` + :param short_name: `"hlk."` + :param number: `44` + """ COLLOQUIAL = PropertyData( id=34, kind=PropertyKind.TONE, @@ -187,6 +348,13 @@ class MeaningProperty(Enum): short_name="tkz.", number=45, ) + """ + :param id: `34` + :param kind: [`TONE`]() + :param full_name: `"teklifsiz konuşmada"` + :param short_name: `"tkz."` + :param number: `45` + """ SATIRIC = PropertyData( id=35, kind=PropertyKind.TONE, @@ -194,6 +362,13 @@ class MeaningProperty(Enum): short_name="alay", number=46, ) + """ + :param id: `35` + :param kind: [`TONE`]() + :param full_name: `"alay yollu"` + :param short_name: `"alay"` + :param number: `46` + """ VULGAR = PropertyData( id=36, kind=PropertyKind.TONE, @@ -201,6 +376,13 @@ class MeaningProperty(Enum): short_name="kaba", number=47, ) + """ + :param id: `36` + :param kind: [`TONE`]() + :param full_name: `"kaba konuşmada"` + :param short_name: `"kaba"` + :param number: `47` + """ JOCULAR = PropertyData( id=37, kind=PropertyKind.TONE, @@ -208,6 +390,13 @@ class MeaningProperty(Enum): short_name="şaka", number=48, ) + """ + :param id: `37` + :param kind: [`TONE`]() + :param full_name: `"şaka yollu"` + :param short_name: `"şaka"` + :param number: `48` + """ INVECTIVE = PropertyData( id=38, kind=PropertyKind.TONE, @@ -215,6 +404,13 @@ class MeaningProperty(Enum): short_name="hkr.", number=49, ) + """ + :param id: `38` + :param kind: [`TONE`]() + :param full_name: `"hakaret yollu"` + :param short_name: `"hkr."` + :param number: `49` + """ MUSIC = PropertyData( id=39, kind=PropertyKind.FIELD, @@ -222,6 +418,13 @@ class MeaningProperty(Enum): short_name="müz.", number=88, ) + """ + :param id: `39` + :param kind: [`FIELD`]() + :param full_name: `"müzik"` + :param short_name: `"müz."` + :param number: `88` + """ SPORTS = PropertyData( id=40, kind=PropertyKind.FIELD, @@ -229,6 +432,13 @@ class MeaningProperty(Enum): short_name="sp.", number=89, ) + """ + :param id: `40` + :param kind: [`FIELD`]() + :param full_name: `"spor"` + :param short_name: `"sp."` + :param number: `89` + """ BOTANY = PropertyData( id=41, kind=PropertyKind.FIELD, @@ -236,6 +446,13 @@ class MeaningProperty(Enum): short_name="bit. b.", number=90, ) + """ + :param id: `41` + :param kind: [`FIELD`]() + :param full_name: `"bitki bilimi"` + :param short_name: `"bit. b."` + :param number: `90` + """ NAVAL = PropertyData( id=42, kind=PropertyKind.FIELD, @@ -243,6 +460,13 @@ class MeaningProperty(Enum): short_name="den.", number=91, ) + """ + :param id: `42` + :param kind: [`FIELD`]() + :param full_name: `"denizcilik"` + :param short_name: `"den."` + :param number: `91` + """ HISTORY = PropertyData( id=43, kind=PropertyKind.FIELD, @@ -250,6 +474,13 @@ class MeaningProperty(Enum): short_name="tar.", number=92, ) + """ + :param id: `43` + :param kind: [`FIELD`]() + :param full_name: `"tarih"` + :param short_name: `"tar."` + :param number: `92` + """ ASTRONOMY = PropertyData( id=44, kind=PropertyKind.FIELD, @@ -257,6 +488,13 @@ class MeaningProperty(Enum): short_name="gök b.", number=93, ) + """ + :param id: `44` + :param kind: [`FIELD`]() + :param full_name: `"gök bilimi"` + :param short_name: `"gök b."` + :param number: `93` + """ GEOGRAPHY = PropertyData( id=45, kind=PropertyKind.FIELD, @@ -264,6 +502,13 @@ class MeaningProperty(Enum): short_name="coğ.", number=94, ) + """ + :param id: `45` + :param kind: [`FIELD`]() + :param full_name: `"coğrafya"` + :param short_name: `"coğ."` + :param number: `94` + """ GRAMMAR = PropertyData( id=46, kind=PropertyKind.FIELD, @@ -271,6 +516,13 @@ class MeaningProperty(Enum): short_name="db.", number=95, ) + """ + :param id: `46` + :param kind: [`FIELD`]() + :param full_name: `"dil bilgisi"` + :param short_name: `"db."` + :param number: `95` + """ PSYCHOLOGY = PropertyData( id=47, kind=PropertyKind.FIELD, @@ -278,6 +530,13 @@ class MeaningProperty(Enum): short_name="ruh b.", number=96, ) + """ + :param id: `47` + :param kind: [`FIELD`]() + :param full_name: `"ruh bilimi"` + :param short_name: `"ruh b."` + :param number: `96` + """ CHEMISTRY = PropertyData( id=48, kind=PropertyKind.FIELD, @@ -285,6 +544,13 @@ class MeaningProperty(Enum): short_name="kim.", number=97, ) + """ + :param id: `48` + :param kind: [`FIELD`]() + :param full_name: `"kimya"` + :param short_name: `"kim."` + :param number: `97` + """ ANATOMY = PropertyData( id=49, kind=PropertyKind.FIELD, @@ -292,6 +558,13 @@ class MeaningProperty(Enum): short_name="anat.", number=98, ) + """ + :param id: `49` + :param kind: [`FIELD`]() + :param full_name: `"anatomi"` + :param short_name: `"anat."` + :param number: `98` + """ COMMERCE = PropertyData( id=50, kind=PropertyKind.FIELD, @@ -299,6 +572,13 @@ class MeaningProperty(Enum): short_name="tic.", number=99, ) + """ + :param id: `50` + :param kind: [`FIELD`]() + :param full_name: `"ticaret"` + :param short_name: `"tic."` + :param number: `99` + """ LAW = PropertyData( id=51, kind=PropertyKind.FIELD, @@ -306,6 +586,13 @@ class MeaningProperty(Enum): short_name="huk.", number=100, ) + """ + :param id: `51` + :param kind: [`FIELD`]() + :param full_name: `"hukuk"` + :param short_name: `"huk."` + :param number: `100` + """ MATHEMATICS = PropertyData( id=52, kind=PropertyKind.FIELD, @@ -313,6 +600,13 @@ class MeaningProperty(Enum): short_name="mat.", number=101, ) + """ + :param id: `52` + :param kind: [`FIELD`]() + :param full_name: `"matematik"` + :param short_name: `"mat."` + :param number: `101` + """ ZOOLOGY = PropertyData( id=53, kind=PropertyKind.FIELD, @@ -320,6 +614,13 @@ class MeaningProperty(Enum): short_name="hay. b.", number=102, ) + """ + :param id: `53` + :param kind: [`FIELD`]() + :param full_name: `"hayvan bilimi"` + :param short_name: `"hay. b."` + :param number: `102` + """ LITERATURE = PropertyData( id=54, kind=PropertyKind.FIELD, @@ -327,6 +628,13 @@ class MeaningProperty(Enum): short_name="ed.", number=103, ) + """ + :param id: `54` + :param kind: [`FIELD`]() + :param full_name: `"edebiyat"` + :param short_name: `"ed."` + :param number: `103` + """ CINEMA = PropertyData( id=55, kind=PropertyKind.FIELD, @@ -334,6 +642,13 @@ class MeaningProperty(Enum): short_name="sin.", number=104, ) + """ + :param id: `55` + :param kind: [`FIELD`]() + :param full_name: `"sinema"` + :param short_name: `"sin."` + :param number: `104` + """ BIOLOGY = PropertyData( id=56, kind=PropertyKind.FIELD, @@ -341,6 +656,13 @@ class MeaningProperty(Enum): short_name="biy.", number=105, ) + """ + :param id: `56` + :param kind: [`FIELD`]() + :param full_name: `"biyoloji"` + :param short_name: `"biy."` + :param number: `105` + """ PHILOSOPHY = PropertyData( id=57, kind=PropertyKind.FIELD, @@ -348,6 +670,13 @@ class MeaningProperty(Enum): short_name="fel.", number=106, ) + """ + :param id: `57` + :param kind: [`FIELD`]() + :param full_name: `"felsefe"` + :param short_name: `"fel."` + :param number: `106` + """ PHYSICS = PropertyData( id=58, kind=PropertyKind.FIELD, @@ -355,6 +684,13 @@ class MeaningProperty(Enum): short_name="fiz.", number=108, ) + """ + :param id: `58` + :param kind: [`FIELD`]() + :param full_name: `"fizik"` + :param short_name: `"fiz."` + :param number: `108` + """ THEATRICAL = PropertyData( id=59, kind=PropertyKind.FIELD, @@ -362,6 +698,13 @@ class MeaningProperty(Enum): short_name="tiy.", number=109, ) + """ + :param id: `59` + :param kind: [`FIELD`]() + :param full_name: `"tiyatro"` + :param short_name: `"tiy."` + :param number: `109` + """ GEOLOGY = PropertyData( id=60, kind=PropertyKind.FIELD, @@ -369,6 +712,13 @@ class MeaningProperty(Enum): short_name="jeol.", number=110, ) + """ + :param id: `60` + :param kind: [`FIELD`]() + :param full_name: `"jeoloji"` + :param short_name: `"jeol."` + :param number: `110` + """ TECHNICAL = PropertyData( id=61, kind=PropertyKind.FIELD, @@ -376,6 +726,13 @@ class MeaningProperty(Enum): short_name="tek.", number=112, ) + """ + :param id: `61` + :param kind: [`FIELD`]() + :param full_name: `"teknik"` + :param short_name: `"tek."` + :param number: `112` + """ SOCIOLOGY = PropertyData( id=62, kind=PropertyKind.FIELD, @@ -383,6 +740,13 @@ class MeaningProperty(Enum): short_name="top. b.", number=113, ) + """ + :param id: `62` + :param kind: [`FIELD`]() + :param full_name: `"toplum bilimi"` + :param short_name: `"top. b."` + :param number: `113` + """ PHYSIOLOGY = PropertyData( id=63, kind=PropertyKind.FIELD, @@ -390,6 +754,13 @@ class MeaningProperty(Enum): short_name="fizy.", number=114, ) + """ + :param id: `63` + :param kind: [`FIELD`]() + :param full_name: `"fizyoloji"` + :param short_name: `"fizy."` + :param number: `114` + """ METEOROLOGY = PropertyData( id=64, kind=PropertyKind.FIELD, @@ -397,6 +768,13 @@ class MeaningProperty(Enum): short_name="meteor.", number=115, ) + """ + :param id: `64` + :param kind: [`FIELD`]() + :param full_name: `"meteoroloji"` + :param short_name: `"meteor."` + :param number: `115` + """ LOGIC = PropertyData( id=65, kind=PropertyKind.FIELD, @@ -404,6 +782,13 @@ class MeaningProperty(Enum): short_name="man.", number=116, ) + """ + :param id: `65` + :param kind: [`FIELD`]() + :param full_name: `"mantık"` + :param short_name: `"man."` + :param number: `116` + """ ECONOMY = PropertyData( id=66, kind=PropertyKind.FIELD, @@ -411,6 +796,13 @@ class MeaningProperty(Enum): short_name="ekon.", number=117, ) + """ + :param id: `66` + :param kind: [`FIELD`]() + :param full_name: `"ekonomi"` + :param short_name: `"ekon."` + :param number: `117` + """ ARCHITECTURE = PropertyData( id=67, kind=PropertyKind.FIELD, @@ -418,6 +810,13 @@ class MeaningProperty(Enum): short_name="mim.", number=118, ) + """ + :param id: `67` + :param kind: [`FIELD`]() + :param full_name: `"mimarlık"` + :param short_name: `"mim."` + :param number: `118` + """ MINERALOGY = PropertyData( id=68, kind=PropertyKind.FIELD, @@ -425,6 +824,13 @@ class MeaningProperty(Enum): short_name="min.", number=119, ) + """ + :param id: `68` + :param kind: [`FIELD`]() + :param full_name: `"mineraloji"` + :param short_name: `"min."` + :param number: `119` + """ PEDAGOGY = PropertyData( id=69, kind=PropertyKind.FIELD, @@ -432,6 +838,13 @@ class MeaningProperty(Enum): short_name="eğt.", number=120, ) + """ + :param id: `69` + :param kind: [`FIELD`]() + :param full_name: `"eğitim bilimi"` + :param short_name: `"eğt."` + :param number: `120` + """ MILITARY = PropertyData( id=73, kind=PropertyKind.FIELD, @@ -439,6 +852,13 @@ class MeaningProperty(Enum): short_name="ask.", number=124, ) + """ + :param id: `73` + :param kind: [`FIELD`]() + :param full_name: `"askerlik"` + :param short_name: `"ask."` + :param number: `124` + """ GEOMETRY = PropertyData( id=80, kind=PropertyKind.FIELD, @@ -446,6 +866,13 @@ class MeaningProperty(Enum): short_name="geom.", number=253, ) + """ + :param id: `80` + :param kind: [`FIELD`]() + :param full_name: `"geometri"` + :param short_name: `"geom."` + :param number: `253` + """ TECHNOLOGY = PropertyData( id=81, kind=PropertyKind.FIELD, @@ -453,6 +880,13 @@ class MeaningProperty(Enum): short_name="tekno.", number=264, ) + """ + :param id: `81` + :param kind: [`FIELD`]() + :param full_name: `"teknoloji"` + :param short_name: `"tekno."` + :param number: `264` + """ AUXILIARY_VERB = PropertyData( id=82, kind=PropertyKind.PART_OF_SPEECH, @@ -460,6 +894,13 @@ class MeaningProperty(Enum): short_name="yar.", number=271, ) + """ + :param id: `82` + :param kind: [`PART_OF_SPEECH`]() + :param full_name: `"yardımcı fiil"` + :param short_name: `"yar."` + :param number: `271` + """ LOCATIVE = PropertyData( id=83, kind=PropertyKind.PART_OF_SPEECH, @@ -467,6 +908,13 @@ class MeaningProperty(Enum): short_name="-de", number=274, ) + """ + :param id: `83` + :param kind: [`PART_OF_SPEECH`]() + :param full_name: `"-de"` + :param short_name: `"-de"` + :param number: `274` + """ LINGUISTICS = PropertyData( id=84, kind=PropertyKind.FIELD, @@ -474,6 +922,13 @@ class MeaningProperty(Enum): short_name="dil b.", number=289, ) + """ + :param id: `84` + :param kind: [`FIELD`]() + :param full_name: `"dil bilimi"` + :param short_name: `"dil b."` + :param number: `289` + """ MEDICINE = PropertyData( id=85, kind=PropertyKind.FIELD, @@ -481,6 +936,13 @@ class MeaningProperty(Enum): short_name="tıp", number=307, ) + """ + :param id: `85` + :param kind: [`FIELD`]() + :param full_name: `"tıp"` + :param short_name: `"tıp"` + :param number: `307` + """ TELEVISION = PropertyData( id=87, kind=PropertyKind.FIELD, @@ -488,6 +950,13 @@ class MeaningProperty(Enum): short_name="TV", number=325, ) + """ + :param id: `87` + :param kind: [`FIELD`]() + :param full_name: `"televizyon"` + :param short_name: `"TV"` + :param number: `325` + """ RELIGION = PropertyData( id=88, kind=PropertyKind.FIELD, @@ -495,6 +964,13 @@ class MeaningProperty(Enum): short_name="din b.", number=326, ) + """ + :param id: `88` + :param kind: [`FIELD`]() + :param full_name: `"din bilgisi"` + :param short_name: `"din b."` + :param number: `326` + """ MINING = PropertyData( id=96, kind=PropertyKind.FIELD, @@ -502,6 +978,13 @@ class MeaningProperty(Enum): short_name="mdn.", number=364, ) + """ + :param id: `96` + :param kind: [`FIELD`]() + :param full_name: `"madencilik"` + :param short_name: `"mdn."` + :param number: `364` + """ I_T = PropertyData( id=98, kind=PropertyKind.FIELD, @@ -509,6 +992,13 @@ class MeaningProperty(Enum): short_name="bl.", number=368, ) + """ + :param id: `98` + :param kind: [`FIELD`]() + :param full_name: `"bilişim"` + :param short_name: `"bl."` + :param number: `368` + """ MYTHOLOGY = PropertyData( id=99, kind=PropertyKind.FIELD, @@ -516,6 +1006,13 @@ class MeaningProperty(Enum): short_name="mit.", number=376, ) + """ + :param id: `99` + :param kind: [`FIELD`]() + :param full_name: `"mit."` + :param short_name: `"mit."` + :param number: `376` + """ ANTHROPOLOGY = PropertyData( id=105, kind=PropertyKind.FIELD, @@ -523,23 +1020,16 @@ class MeaningProperty(Enum): short_name="ant.", number=404, ) - - @staticmethod - def get(arg): - if isinstance(arg, dict): - return _property_table[int(arg["ozellik_id"])] - return _property_table[arg] - - -def _validate_property(v, handler): - if isinstance(v, MeaningProperty): - return v - return handler(MeaningProperty.get(v)) + """ + :param id: `105` + :param kind: [`FIELD`]() + :param full_name: `"antropoloji"` + :param short_name: `"ant."` + :param number: `404` + """ + # endregion -ValidatedProperty = Annotated[ - MeaningProperty, WrapValidator(_validate_property) -] _property_table: dict[int | str, MeaningProperty] = {} for enum_value in MeaningProperty: diff --git a/src/tdk/etc/tools.py b/src/tdk/etc/tools.py index 10c345e..6a33c58 100644 --- a/src/tdk/etc/tools.py +++ b/src/tdk/etc/tools.py @@ -1,3 +1,7 @@ +""" +This module contains various tools for working with strings. +""" + from collections.abc import Sequence from io import StringIO, SEEK_SET from typing import TypeVar @@ -8,6 +12,7 @@ def _next_vowel_index(text: str, cur: int) -> int: + """Find the next vowel index in the text.""" index = cur while True: if index + 1 >= len(text): @@ -20,13 +25,16 @@ def _next_vowel_index(text: str, cur: int) -> int: def _are_there_letters_between( text: str, start: int, end: int, alphabet=ALPHABET ) -> bool: + """Check if there are any letters between the start and end indices.""" return any(character in alphabet for character in text[start + 1 : end]) ALPHABET_PUNCTUATION = f"{ALPHABET}{punctuation}" +"""The Turkish alphabet and common punctuation marks.""" def _previous_letter(text, end, stop_characters=ALPHABET_PUNCTUATION): + """Find the previous letter index in the text.""" index = end - 1 while True: if text[index] in stop_characters: @@ -40,10 +48,12 @@ def _previous_letter(text, end, stop_characters=ALPHABET_PUNCTUATION): def hecele(text: str, /) -> list[str]: """Split the text into syllables. + ```pycon >>> hecele("merhaba") ["mer", "ha", ba"] >>> hecele("ortaokul") ["or", "ta", "o", "kul"] + ``` """ current_vowel_index = _next_vowel_index(text, -1) @@ -75,20 +85,23 @@ def hecele(text: str, /) -> list[str]: (_Ltr.SHORT_VOWEL, _Ltr.CONSONANT, _Ltr.CONSONANT), (_Ltr.CONSONANT, _Ltr.SHORT_VOWEL, _Ltr.CONSONANT, _Ltr.CONSONANT), ) +"""Look-up table for medli syllable patterns. + +Used by when determining if the syllable is medli. +""" def get_syllable_type(syllable: str, /) -> SyllableType: - """Determine the type of the syllable. + """Determine the type of the syllable according to aruz prosody rules. The type of the syllable is defined as follows, - where C is a consonant, V is a short vowel, and L is a long vowel: - - * If the syllable is of the form LC, CLC, VCC, CVCC, it is MEDLI. - * If the syllable ends with a short vowel, it is OPEN. - * Otherwise, it is CLOSED. + where `C` is a consonant, `V` is a short vowel, and `L` is a long vowel: - :param syllable: - :return: + * If the syllable is of the form `LC`, `CLC`, `VCC`, or `CVCC`; it is + . + * If the syllable ends with a short vowel, it is + . + * Otherwise, it is . """ letters = lowercase(syllable, remove_circumflexes=False) cv_map = tuple(get_letter_type(letter) for letter in letters) @@ -102,9 +115,23 @@ def get_syllable_type(syllable: str, /) -> SyllableType: def get_letter_type(letter: str, /) -> _Ltr: + """Determine the type of the letter. + + * If the letter is a vowel without a circumflex, it is a + . + * If the letter is a vowel with a circumflex, it is a + . + * If the letter is a consonant, it is a . + + :raises ValueError: If the letter is not a valid letter in + , , + or . + """ ch = lowercase(letter, remove_circumflexes=False) if not ch: raise ValueError(f"Empty string is not a valid letter.") + if len(ch) != 1: + raise ValueError(f"Expected a single character, got {len(ch)}.") if ch in VOWELS: return _Ltr.SHORT_VOWEL elif ch in LONG_VOWELS: @@ -119,15 +146,17 @@ def lowercase( /, *, alphabet: str = ALPHABET, - keep_unknown_characters=False, - remove_circumflexes=True, + keep_unknown_characters: bool = False, + remove_circumflexes: bool = True, ) -> str: """Removes all whitespace and punctuation from word and lowercase it. + ```pycon >>> lowercase("geçti Bor'un pazarı (sür eşeğini Niğde'ye)") "geçtiborunpazarısüreşeğininiğdeye" + ``` - :return: A lowercase string without any whitespace or punctuation. + :returns: A lowercase string without any whitespace or punctuation. """ a_circumflex_replacement = "a" if remove_circumflexes else "â" @@ -154,30 +183,40 @@ def lowercase( def dictionary_order(word: str, /, *, alphabet=ALPHABET) -> tuple[int]: - """ - >>> dictionary_order("algarina") < dictionary_order("zamansızlık") - True - >>> dictionary_order("yumuşaklık") < dictionary_order("beşik") - False + """Returns a tuple of indices that can be used as orthographic order. + + ```python + assert dictionary_order("algarina") < dictionary_order("zamansızlık") + assert dictionary_order("yumuşaklık") > dictionary_order("beşik") + ``` + + :::{admonition} Invariant + :class: tip + + If `B` comes after `A` in the dictionary, + `dictionary_order(B) > dictionary_order(A)`. + ::: """ return tuple(alphabet.index(letter) for letter in lowercase(word)) def counter(word: str, *, targets=VOWELS) -> int: - """ + """Find total number of occurrences of each element in targets. + ```pycon >>> counter(word="aaaaaBBBc", targets="c") 1 >>> counter(word="aaaaaBBBc", targets="b") 3 >>> counter(word="aaaaaBBBc", targets="cb") 4 + ``` - The word is sanitized using `lowercase()`. + `word` is sanitized using `lowercase()`. + ```pycon >>> counter(word="aaaaaBBBc", targets="B") 0 - - :return: The total number of occurrences of each element in targets. + ``` """ word = lowercase(word) return sum(word.count(x) for x in targets) @@ -186,9 +225,11 @@ def counter(word: str, *, targets=VOWELS) -> int: def streaks(word: str, *, targets=CONSONANTS) -> list[int]: """ Accumulate the number of characters in word which are also in targets. - When a character in word isn't in targets, break the streak and append it to the return list. - (Even if the current streak is 0.) + When a character in word isn't in targets, + break the streak and append it to the return list, + even if the current streak is 0. + ```pycon >>> streaks("anapara") [0, 1, 1, 1, 0] # /a N /a P /a R /a / >>> streaks("zorlanmak") @@ -197,6 +238,7 @@ def streaks(word: str, *, targets=CONSONANTS) -> list[int]: [1, 1, 2, 1, 1] # Ç /ö Z /ü ML /e M /e K / >>> streaks("tasdikletmek") [1, 2, 2, 2, 1] # T /a SD /i KL /e TM /e K / + ``` """ streaks_found = [] accumulator = 0 @@ -214,7 +256,7 @@ def streaks(word: str, *, targets=CONSONANTS) -> list[int]: def max_streak(word: str, *, targets=CONSONANTS) -> int: - """The maximum consecutive targets in word.""" + """Find the maximum consecutive targets in word.""" return max(streaks(word=word, targets=targets)) @@ -222,7 +264,7 @@ def max_streak(word: str, *, targets=CONSONANTS) -> int: def distinct(seq: Sequence[T]) -> list[T]: - """Returns the sequence with each element appearing once with order.""" + """Returns the sequence with each element appearing once with FIFO order.""" seen: set[T] = set() seen_add = seen.add return [x for x in seq if not (x in seen or seen_add(x))] diff --git a/src/tdk/internal/__init__.py b/src/tdk/internal/__init__.py index e69de29..06f26fb 100644 --- a/src/tdk/internal/__init__.py +++ b/src/tdk/internal/__init__.py @@ -0,0 +1,5 @@ +""" +This subpackage contains additional tools and data to be used by the library. + +Not designed to be used directly by end users. +""" diff --git a/src/tdk/internal/http.py b/src/tdk/internal/http.py index b9a9ab3..a0f4940 100644 --- a/src/tdk/internal/http.py +++ b/src/tdk/internal/http.py @@ -1,3 +1,7 @@ +""" +This module provides helper functions for making HTTP requests. +""" + from functools import wraps from typing import Optional @@ -14,11 +18,24 @@ } -def session_maker() -> aiohttp.ClientSession: - return aiohttp.ClientSession(headers=http_headers) +def session_maker(**kwargs) -> aiohttp.ClientSession: + """Create a with some default headers. + + This is preferred over creating a base because the TDK + servers block requests that do not have headers. + """ + kwargs["headers"] = {**http_headers, **kwargs.get("headers", {})} + return aiohttp.ClientSession(**kwargs) def with_http_session(func): + """Make optional for a function that requires it. + + Creates a decorator + that provides a default + created by + to the wrapped function. + """ @wraps(func) async def wrapper(*args, **kwargs): if "http_session" in kwargs: diff --git a/src/tdk/internal/utils.py b/src/tdk/internal/utils.py index 2ac1a9d..01c8d53 100644 --- a/src/tdk/internal/utils.py +++ b/src/tdk/internal/utils.py @@ -1,3 +1,9 @@ +""" +This module contains miscellaneous utilities for the library. +""" + +from __future__ import annotations + import asyncio from enum import Enum from functools import wraps @@ -5,8 +11,38 @@ from pydantic import BeforeValidator, AfterValidator +from tdk.etc.enums import MeaningProperty + + +def make_sync(func_to_be_cloned, /): + """Make an async function run synchronously. + + Creates a decorator that runs the async function given as a parameter + synchronously. + + :::{important} + The wrapped function is not used. + ::: + + :::{admonition} Example usage + :class: tip + + ```{code-block} python + :emphasize-lines: 8,9 -def make_sync(func_to_be_cloned): + from tdk.internal.utils import make_sync + + async def wait(): + from asyncio import sleep + await sleep(1) + return "Hello, world!" + + @make_sync(wait) + def wait_sync(): ... + + print(wait_sync()) # Hello, world! + ``` + """ def decorator(_unused_func): @wraps(func_to_be_cloned) def new_func(*args, **kwargs): @@ -17,34 +53,68 @@ def new_func(*args, **kwargs): return decorator -def int_or_none_as_str(value: str) -> int | None: +def int_or_none_as_str(value: str, /) -> int | None: + """Convert a string to an integer or None. + + Empty strings are converted to , + other strings are converted to type . + """ if not value: return None return int(value) IntOrNone = Annotated[int | None, BeforeValidator(int_or_none_as_str)] +"""Pydantic type hint for an integer or None.""" -def str_or_none_as_str(value: str) -> str | None: +def str_or_none_as_str(value: str, /) -> str | None: + """Convert a string to a string or None. + + Empty strings are converted to , + other strings are converted to type . + """ if not value: return None return value StrOrNone = Annotated[str | None, BeforeValidator(str_or_none_as_str)] +"""Pydantic type hint for a string or None.""" + +def sound_url_validator(v: str, /) -> str: + """Convert a sound code to a valid sound URL. -def sound_url_validator(v: str) -> str: + Strings that do not start with `https://` are converted to + `https://sozluk.gov.tr/ses/{}.wav`. + """ if not v.startswith("https://"): return f"https://sozluk.gov.tr/ses/{v}.wav" return v SoundURL = Annotated[str, AfterValidator(sound_url_validator)] +"""Pydantic type hint for a sound URL.""" + + +def image_url_validator(v: str, /) -> str: + """Convert an image code to a valid image URL. + + Strings that do not start with `https://` are converted to + `https://sozluk.gov.tr/dosyalar/tarornek/{}.gif`. + """ + if not v.startswith("https://"): + return f"https://sozluk.gov.tr/dosyalar/tarornek/{v}.gif" + return v + + +ImageURL = Annotated[str, AfterValidator(image_url_validator)] +"""Pydantic type hint for an image URL.""" def adapt_input_to_enum(input: Any, enum: Type[Enum]) -> Enum: + """Get an enum member from an enum instance, value or name.""" if isinstance(input, enum): return input for name, member in enum.__members__.items(): @@ -56,19 +126,35 @@ def adapt_input_to_enum(input: Any, enum: Type[Enum]) -> Enum: NOT_FOUND = {"error": "Sonuç bulunamadı"} +"""A NOT_FOUND response from the API.""" + +def assert_not_found(data: Any, /): + """Assert that the data is a response. -def assert_not_found(data: Any): + :raises TypeError: If the data is not a dict. + :raises ValueError: If the data is not a response. + """ if not isinstance(data, dict): raise TypeError("Expected a dict") if data != NOT_FOUND: raise ValueError("Expected NOT_FOUND") -def image_url_validator(v: str) -> str: - if not v.startswith("https://"): - return f"https://sozluk.gov.tr/dosyalar/tarornek/{v}.gif" - return v +def validate_property(v: str | int | MeaningProperty, /): + """Validate a meaning property. + If the input is a instance, it is returned as is. + Otherwise, is used to find the correct + instance, and it is returned. + """ + if isinstance(v, MeaningProperty): + return v + return MeaningProperty.get(v) -ImageURL = Annotated[str, AfterValidator(image_url_validator)] + +ValidatedProperty = Annotated[ + MeaningProperty, + BeforeValidator(validate_property) +] +"""Pydantic type hint for a validated meaning property."""