ssb-klass-python 0.0.8__tar.gz → 0.0.10__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.
Files changed (25) hide show
  1. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/PKG-INFO +2 -2
  2. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/pyproject.toml +39 -27
  3. ssb_klass_python-0.0.10/src/klass/__init__.py +97 -0
  4. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/src/klass/classes/classification.py +1 -1
  5. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/src/klass/classes/codes.py +4 -3
  6. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/src/klass/classes/correspondence.py +2 -2
  7. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/src/klass/classes/family.py +1 -1
  8. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/src/klass/classes/search.py +2 -2
  9. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/src/klass/classes/variant.py +2 -2
  10. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/src/klass/classes/version.py +1 -1
  11. ssb_klass_python-0.0.8/src/klass/__init__.py +0 -75
  12. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/LICENSE +0 -0
  13. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/README.md +0 -0
  14. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/src/klass/classes/__init__.py +0 -0
  15. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/src/klass/config.py +0 -0
  16. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/src/klass/py.typed +0 -0
  17. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/src/klass/requests/__init__.py +0 -0
  18. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/src/klass/requests/klass_requests.py +0 -0
  19. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/src/klass/requests/sections.py +0 -0
  20. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/src/klass/requests/types.py +0 -0
  21. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/src/klass/requests/validate.py +0 -0
  22. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/src/klass/utility/classification.py +0 -0
  23. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/src/klass/utility/codes.py +0 -0
  24. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/src/klass/widgets/__init__.py +0 -0
  25. {ssb_klass_python-0.0.8 → ssb_klass_python-0.0.10}/src/klass/widgets/search_ipywidget.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ssb-klass-python
3
- Version: 0.0.8
3
+ Version: 0.0.10
4
4
  Summary: A Python package built on top of KLASS's API for retrieving classifications, codes, correspondences etc.
5
5
  Home-page: https://github.com/statisticsnorway/ssb-klass-python
6
6
  License: MIT
@@ -13,7 +13,7 @@ Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Programming Language :: Python :: 3.10
14
14
  Classifier: Programming Language :: Python :: 3.11
15
15
  Classifier: Programming Language :: Python :: 3.12
16
- Requires-Dist: dapla-toolbelt (>=1.3.2)
16
+ Requires-Dist: dapla-toolbelt (>=2.0.6)
17
17
  Requires-Dist: ipywidgets (>=8.0.6)
18
18
  Requires-Dist: pandas (>=1.5.3)
19
19
  Requires-Dist: pandas-stubs (>=2.1.1.230928)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "ssb-klass-python"
3
- version = "0.0.8"
3
+ version = "0.0.10"
4
4
  description = "A Python package built on top of KLASS's API for retrieving classifications, codes, correspondences etc."
5
5
  authors = ["Carl Corneil, ssb-pythonistas <ssb-pythonistas@ssb.no>"]
6
6
  license = "MIT"
@@ -16,7 +16,7 @@ Changelog = "https://github.com/statisticsnorway/ssb-klass-python/releases"
16
16
 
17
17
  [tool.poetry.dependencies]
18
18
  python = ">=3.10,<4.0"
19
- dapla-toolbelt = ">=1.3.2"
19
+ dapla-toolbelt = ">=2.0.6"
20
20
  python-dateutil = ">=2.8.2"
21
21
  toml = ">=0.10.2"
22
22
  ipywidgets = ">=8.0.6"
@@ -30,7 +30,7 @@ types-toml = ">=0.10.8.7"
30
30
 
31
31
  [tool.poetry.group.dev.dependencies]
32
32
  pygments = ">=2.10.0"
33
- black = { extras = ["jupyter"], version = ">=23.1.0" }
33
+ black = { extras = ["jupyter"], version = ">=24.3.0" }
34
34
  coverage = { extras = ["toml"], version = ">=6.2" }
35
35
  darglint = ">=1.8.1"
36
36
  furo = ">=2021.11.12"
@@ -55,6 +55,7 @@ myst-parser = { version = ">=0.16.1" }
55
55
  [tool.pytest.ini_options]
56
56
  pythonpath = ["src"]
57
57
 
58
+
58
59
  [tool.coverage.paths]
59
60
  source = ["src", "*/site-packages"]
60
61
  tests = ["tests", "*/tests"]
@@ -62,6 +63,7 @@ tests = ["tests", "*/tests"]
62
63
  [tool.coverage.run]
63
64
  branch = true
64
65
  source = ["klass", "tests"]
66
+ relative_files = true
65
67
 
66
68
  [tool.coverage.report]
67
69
  show_missing = true
@@ -85,11 +87,22 @@ ignore_missing_imports = true
85
87
  force-exclude = true # Apply excludes to pre-commit
86
88
  show-fixes = true
87
89
  src = ["src", "tests"]
88
- target-version = "py39" # Minimum Python version supported
90
+ target-version = "py310" # Minimum Python version supported
91
+
92
+ include = ["*.py", "*.pyi", "**/pyproject.toml", "*.ipynb"]
93
+ extend-exclude = [
94
+ "__pycache__",
95
+ "old",
96
+ ".ipynb_checkpoints",
97
+ "noxfile.py",
98
+ "docs/conf.py",
99
+ ]
89
100
 
90
101
  # Ruff rules may be customized as desired: https://docs.astral.sh/ruff/rules/
102
+ [tool.ruff.lint]
91
103
  select = [
92
104
  "A", # prevent using keywords that clobber python builtins
105
+ "ANN", # check type annotations
93
106
  "B", # bugbear: security warnings
94
107
  "D", # documentation
95
108
  "E", # pycodestyle
@@ -101,43 +114,42 @@ select = [
101
114
  ]
102
115
  ignore = [
103
116
  "ANN101", # Supress missing-type-self.
104
- "D100", # Supress undocumented-public-module. Only doc of public api required.
105
- "E402", # Supress module-import-not-at-top-of-file, needed in jupyter notebooks.
106
- "E501", # Supress line-too-long warnings: trust black's judgement on this one.
107
- ]
108
- include = ["*.py", "*.pyi", "**/pyproject.toml", "*.ipynb"]
109
- extend-exclude = [
110
- "__pycache__",
111
- "old",
112
- ".ipynb_checkpoints",
113
- "noxfile.py",
114
- "docs/conf.py",
115
- "*.ipynb", # Custom ignore for klass-package, notebooks are only for "demo", waiting for a B018 ignore on notebooks in ruff
116
- # https://github.com/astral-sh/ruff/pull/8872 <- has been merged in main, but not yet released?
117
+ "ANN102", # Supress missing-type-cls.
118
+ "ANN202", # Don't requiere return type annotation for private functions.
119
+ "ANN401", # Allow type annotation with type Any.
120
+ "D100", # Supress undocumented-public-module. Only doc of public api required.
121
+ "E402", # Supress module-import-not-at-top-of-file, needed in jupyter notebooks.
122
+ "E501", # Supress line-too-long warnings: trust black's judgement on this one.
117
123
  ]
118
124
 
119
- [tool.ruff.isort]
125
+ [tool.ruff.lint.isort]
120
126
  force-single-line = true
121
127
 
122
- [tool.ruff.mccabe]
128
+ [tool.ruff.lint.mccabe]
123
129
  max-complexity = 15
124
130
 
125
- [tool.ruff.pydocstyle]
131
+ [tool.ruff.lint.pydocstyle]
126
132
  convention = "google" # You can also use "numpy".
127
133
 
128
- [tool.ruff.pep8-naming]
134
+ [tool.ruff.lint.pep8-naming]
129
135
  classmethod-decorators = ["classmethod", "validator", "root_validator", "pydantic.validator"]
130
136
 
131
- [tool.ruff.per-file-ignores]
137
+ [tool.ruff.lint.per-file-ignores]
132
138
  "*/__init__.py" = ["F401"]
133
139
  "**/tests/*" = [
134
- # asserts are encouraged in pytest
135
- "S101",
136
- # return annotations don't add value for test functions
137
- "ANN201",
138
- # docstrings are overkill for test functions
140
+ "ANN001", # type annotations don't add value for test functions
141
+ "ANN002", # type annotations don't add value for test functions
142
+ "ANN003", # type annotations don't add value for test functions
143
+ "ANN201", # type annotations don't add value for test functions
144
+ "ANN204", # type annotations don't add value for test functions
145
+ "ANN205", # type annotations don't add value for test functions
146
+ "ANN206", # type annotations don't add value for test functions
147
+ "D100", # docstrings are overkill for test functions
148
+ "D101",
149
+ "D102",
139
150
  "D103",
140
151
  "D100",
152
+ "S101", # asserts are encouraged in pytest
141
153
  ]
142
154
 
143
155
  [build-system]
@@ -0,0 +1,97 @@
1
+ """A Python package built on top of Statistics Norway's code- and classification-system "KLASS".
2
+
3
+ The package aims to make Klass's API for retrieving data easier to use by re-representing Klass's internal hierarchy as python-classes.
4
+ Containing methods for easier traversal down, search classes and widgets, reasonable defaults to parameters etc.
5
+ Where data is possible to fit into pandas DataFrames, this will be preferred, but hirerachical data will be kept as json / dict structure.
6
+ """
7
+
8
+ import importlib
9
+ import importlib.metadata
10
+
11
+ import toml
12
+
13
+
14
+ def _try_getting_pyproject_toml(e: Exception | None = None) -> str:
15
+ if e is None:
16
+ passed_excep: Exception = Exception("")
17
+ else:
18
+ passed_excep = e
19
+ try:
20
+ version: str = toml.load("pyproject.toml")["tool"]["poetry"]["version"]
21
+ return version
22
+ except Exception as e:
23
+ version_missing: str = "0.0.0"
24
+ print(
25
+ f"Error from ssb-klass-pythons __init__, not able to get version-number, setting it to {version_missing}: {passed_excep}"
26
+ )
27
+ return version_missing
28
+
29
+
30
+ # Gets the installed version from pyproject.toml, then there is no need to update this file
31
+ try:
32
+ __version__ = importlib.metadata.version("ssb-klass-python")
33
+ except importlib.metadata.PackageNotFoundError as e:
34
+ __version__ = _try_getting_pyproject_toml(e)
35
+
36
+
37
+ from klass.classes.classification import KlassClassification
38
+ from klass.classes.codes import KlassCodes
39
+ from klass.classes.correspondence import KlassCorrespondence
40
+ from klass.classes.family import KlassFamily
41
+ from klass.classes.search import KlassSearchClassifications
42
+ from klass.classes.search import KlassSearchFamilies
43
+ from klass.classes.variant import KlassVariant
44
+ from klass.classes.variant import KlassVariantSearchByName
45
+ from klass.classes.version import KlassVersion
46
+ from klass.requests.klass_requests import changes
47
+ from klass.requests.klass_requests import classification_by_id
48
+ from klass.requests.klass_requests import classification_search
49
+ from klass.requests.klass_requests import classificationfamilies
50
+ from klass.requests.klass_requests import classificationfamilies_by_id
51
+ from klass.requests.klass_requests import classifications
52
+ from klass.requests.klass_requests import codes
53
+ from klass.requests.klass_requests import codes_at
54
+ from klass.requests.klass_requests import correspondence_table_by_id
55
+ from klass.requests.klass_requests import corresponds
56
+ from klass.requests.klass_requests import corresponds_at
57
+ from klass.requests.klass_requests import variant
58
+ from klass.requests.klass_requests import variant_at
59
+ from klass.requests.klass_requests import variants_by_id
60
+ from klass.requests.klass_requests import version_by_id
61
+ from klass.requests.sections import sections_dict
62
+ from klass.requests.sections import sections_list
63
+ from klass.utility.classification import get_classification
64
+ from klass.utility.codes import get_codes
65
+ from klass.widgets.search_ipywidget import search_classification
66
+
67
+ __all__ = [
68
+ "classifications",
69
+ "classification_search",
70
+ "classification_by_id",
71
+ "codes",
72
+ "codes_at",
73
+ "version_by_id",
74
+ "variant",
75
+ "variant_at",
76
+ "variants_by_id",
77
+ "corresponds",
78
+ "corresponds_at",
79
+ "correspondence_table_by_id",
80
+ "changes",
81
+ "classificationfamilies",
82
+ "classificationfamilies_by_id",
83
+ "sections_list",
84
+ "sections_dict",
85
+ "KlassCodes",
86
+ "KlassCorrespondence",
87
+ "KlassClassification",
88
+ "KlassFamily",
89
+ "KlassSearchClassifications",
90
+ "KlassSearchFamilies",
91
+ "KlassVariant",
92
+ "KlassVariantSearchByName",
93
+ "KlassVersion",
94
+ "get_codes",
95
+ "get_classification",
96
+ "search_classification",
97
+ ]
@@ -58,7 +58,7 @@ class KlassClassification:
58
58
 
59
59
  def __init__(
60
60
  self, classification_id: str, language: str = "nb", include_future: bool = False
61
- ):
61
+ ) -> None:
62
62
  """Get the data for the classification from the API."""
63
63
  self.classification_id = classification_id
64
64
  self.language = language
@@ -48,7 +48,7 @@ class KlassCodes:
48
48
  presentation_name_pattern: str = "",
49
49
  language: str = "nb",
50
50
  include_future: bool = False,
51
- ):
51
+ ) -> None:
52
52
  """Get the data from the KLASS-api belonging to the code-list."""
53
53
  self.classification_id = classification_id
54
54
  if not from_date:
@@ -187,7 +187,7 @@ class KlassCodes:
187
187
  value = "presentationName"
188
188
  else:
189
189
  value = "name"
190
- mapping = dict(zip(self.data[key], self.data[value]))
190
+ mapping = dict(zip(self.data[key], self.data[value], strict=False))
191
191
  if other:
192
192
  mapping = defaultdict(lambda: other, mapping)
193
193
  return mapping
@@ -212,7 +212,8 @@ class KlassCodes:
212
212
  keep = ["code", "name"]
213
213
  df = pd.DataFrame()
214
214
  lev_previous = 1
215
- for lev in self.data["level"].unique():
215
+ sorted_levels = sorted(self.data["level"].unique())
216
+ for lev in sorted_levels:
216
217
  temp = self.data[self.data["level"] == lev].copy()
217
218
  temp.columns = [f"{c}_{lev}" for c in temp.columns]
218
219
  if len(df):
@@ -56,7 +56,7 @@ class KlassCorrespondence:
56
56
  contain_quarter: int = 0,
57
57
  language: str = "nb",
58
58
  include_future: bool = False,
59
- ):
59
+ ) -> None:
60
60
  """Get the correspondence-data from the API."""
61
61
  self.correspondence_id = correspondence_id
62
62
  self.source_classification_id = source_classification_id
@@ -197,7 +197,7 @@ class KlassCorrespondence:
197
197
  Returns:
198
198
  dict | defaultdict: The dictionary of the correspondence.
199
199
  """
200
- mapping = dict(zip(self.data[key], self.data[value]))
200
+ mapping = dict(zip(self.data[key], self.data[value], strict=False))
201
201
  if other:
202
202
  mapping = defaultdict(lambda: other, mapping)
203
203
  return mapping
@@ -20,7 +20,7 @@ class KlassFamily:
20
20
  family_id (str): The ID of the family.
21
21
  """
22
22
 
23
- def __init__(self, family_id: str):
23
+ def __init__(self, family_id: str) -> None:
24
24
  """Get the family data from the klass-api, setting it as attributes on the object."""
25
25
  self.family_id = family_id
26
26
  # Setting for mypy
@@ -32,7 +32,7 @@ class KlassSearchClassifications:
32
32
  include_codelists: bool = True, # Opposite default of API, cause why not
33
33
  ssbsection: str = "",
34
34
  no_dupes: bool = False,
35
- ):
35
+ ) -> None:
36
36
  """Get data from the KLASS-api, setting it as attributes on this object."""
37
37
  self.query = query
38
38
  self.include_codelists = include_codelists
@@ -168,7 +168,7 @@ class KlassSearchFamilies:
168
168
  ssbsection: str = "",
169
169
  include_codelists: bool = False,
170
170
  language: str = "nb",
171
- ):
171
+ ) -> None:
172
172
  """Get data from the KLASS-api, setting it as attributes on this object."""
173
173
  self.ssbsection = ssbsection
174
174
  self.include_codelists = include_codelists
@@ -49,7 +49,7 @@ class KlassVariant:
49
49
  variant_id: str,
50
50
  select_level: int = 0,
51
51
  language: str = "nb",
52
- ):
52
+ ) -> None:
53
53
  """Get the data from the KLASS-api to populate this objects attributes."""
54
54
  self.variant_id = variant_id
55
55
  self.select_level = select_level
@@ -169,7 +169,7 @@ class KlassVariantSearchByName:
169
169
  presentation_name_pattern: str = "",
170
170
  language: str = "nb",
171
171
  include_future: bool = False,
172
- ):
172
+ ) -> None:
173
173
  """Get the data from the KLASS-api, setting it as attributes on the object."""
174
174
  self.classification_id = classification_id
175
175
  self.variant_name = variant_name
@@ -41,7 +41,7 @@ class KlassVersion:
41
41
  select_level: int = 0,
42
42
  language: str = "nb",
43
43
  include_future: bool = False,
44
- ):
44
+ ) -> None:
45
45
  """Set up the object with data from the KLASS-API."""
46
46
  self.version_id = version_id
47
47
  self.select_level = select_level
@@ -1,75 +0,0 @@
1
- """A Python package built on top of Statistics Norway's code- and classification-system "KLASS".
2
-
3
- The package aims to make Klass's API for retrieving data easier to use by re-representing Klass's internal hierarchy as python-classes.
4
- Containing methods for easier traversal down, search classes and widgets, reasonable defaults to parameters etc.
5
- Where data is possible to fit into pandas DataFrames, this will be preferred, but hirerachical data will be kept as json / dict structure.
6
- """
7
-
8
- import importlib
9
-
10
- import toml
11
-
12
-
13
- # Split into function for testing
14
- def _try_getting_pyproject_toml(e: Exception | None = None) -> str:
15
- if e is None:
16
- passed_excep: Exception = Exception("")
17
- else:
18
- passed_excep = e
19
- try:
20
- version: str = toml.load("../pyproject.toml")["tool"]["poetry"]["version"]
21
- return version
22
- except Exception as e:
23
- version_missing: str = "0.0.0"
24
- print(
25
- f"Error from ssb-klass-pythons __init__, not able to get version-number, setting it to {version_missing}: {passed_excep}"
26
- )
27
- return version_missing
28
-
29
-
30
- # Gets the installed version from pyproject.toml, then there is no need to update this file
31
- try:
32
- __version__ = importlib.metadata.version("ssb-klass-python")
33
- except importlib.metadata.PackageNotFoundError as e:
34
- __version__ = _try_getting_pyproject_toml(e)
35
-
36
-
37
- __all__ = []
38
-
39
- # Everything we want to be directly importable from under "klass"-package
40
- local_imports = {
41
- "requests.klass_requests": [
42
- "classifications",
43
- "classification_search",
44
- "classification_by_id",
45
- "codes",
46
- "codes_at",
47
- "version_by_id",
48
- "variant",
49
- "variant_at",
50
- "variants_by_id",
51
- "corresponds",
52
- "corresponds_at",
53
- "correspondence_table_by_id",
54
- "changes",
55
- "classificationfamilies",
56
- "classificationfamilies_by_id",
57
- ],
58
- "classes.codes": ["KlassCodes"],
59
- "classes.correspondence": ["KlassCorrespondence"],
60
- "classes.classification": ["KlassClassification"],
61
- "classes.family": ["KlassFamily"],
62
- "classes.search": ["KlassSearchClassifications", "KlassSearchFamilies"],
63
- "requests.sections": ["sections_list", "sections_dict"],
64
- "classes.variant": ["KlassVariant", "KlassVariantSearchByName"],
65
- "classes.version": ["KlassVersion"],
66
- "utility.codes": ["get_codes"],
67
- "utility.classification": ["get_classification"],
68
- "widgets.search_ipywidget": ["search_classification"],
69
- }
70
-
71
- # Loop that imports local files into this namespace and appends to __all__ for star imports
72
- for file, funcs in local_imports.items():
73
- for func in funcs:
74
- globals()[func] = getattr(importlib.import_module(f"klass.{file}", func), func)
75
- __all__.append(func)