ckanext-search-tweaks 0.6.0__py3-none-any.whl → 0.6.1__py3-none-any.whl

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 (23) hide show
  1. ckanext/search_tweaks/__init__.py +0 -3
  2. ckanext/search_tweaks/advanced_search/plugin.py +4 -4
  3. ckanext/search_tweaks/field_relevance/plugin.py +2 -1
  4. ckanext/search_tweaks/plugin.py +7 -8
  5. ckanext/search_tweaks/query_popularity/logic/action.py +28 -7
  6. ckanext/search_tweaks/query_popularity/logic/auth.py +8 -4
  7. ckanext/search_tweaks/query_popularity/logic/schema.py +10 -0
  8. ckanext/search_tweaks/query_popularity/plugin.py +13 -9
  9. ckanext/search_tweaks/query_popularity/score.py +24 -143
  10. ckanext/search_tweaks/query_relevance/plugin.py +2 -1
  11. ckanext/search_tweaks/query_relevance/storage.py +9 -9
  12. ckanext/search_tweaks/spellcheck/helpers.py +8 -2
  13. ckanext/search_tweaks/tests/spellcheck/test_plugin.py +2 -2
  14. ckanext/search_tweaks/tests/test_plugin.py +15 -4
  15. ckanext_search_tweaks-0.6.1-py3.8-nspkg.pth +1 -0
  16. {ckanext_search_tweaks-0.6.0.dist-info → ckanext_search_tweaks-0.6.1.dist-info}/METADATA +2 -1
  17. {ckanext_search_tweaks-0.6.0.dist-info → ckanext_search_tweaks-0.6.1.dist-info}/RECORD +22 -21
  18. {ckanext_search_tweaks-0.6.0.dist-info → ckanext_search_tweaks-0.6.1.dist-info}/WHEEL +1 -1
  19. ckanext_search_tweaks-0.6.0-py3.8-nspkg.pth +0 -1
  20. {ckanext_search_tweaks-0.6.0.dist-info → ckanext_search_tweaks-0.6.1.dist-info}/LICENSE +0 -0
  21. {ckanext_search_tweaks-0.6.0.dist-info → ckanext_search_tweaks-0.6.1.dist-info}/entry_points.txt +0 -0
  22. {ckanext_search_tweaks-0.6.0.dist-info → ckanext_search_tweaks-0.6.1.dist-info}/namespace_packages.txt +0 -0
  23. {ckanext_search_tweaks-0.6.0.dist-info → ckanext_search_tweaks-0.6.1.dist-info}/top_level.txt +0 -0
@@ -1,3 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from .shared import feature_disabled
@@ -72,10 +72,10 @@ class AdvancedSearchPlugin(p.SingletonPlugin):
72
72
  def configure(self, config):
73
73
  try:
74
74
  from ckanext.composite_search.interfaces import ICompositeSearch
75
- except ImportError:
76
- raise CkanConfigurationException(
77
- "ckanext-composite-search is not installed",
78
- )
75
+ except ImportError as err:
76
+ msg = "ckanext-composite-search is not installed"
77
+ raise CkanConfigurationException(msg) from err
78
+
79
79
  if not p.plugin_loaded("composite_search"):
80
80
  msg = "Advanced search requires `composite_search` plugin"
81
81
  raise CkanConfigurationException(msg)
@@ -5,8 +5,9 @@ from typing import Any
5
5
  import ckan.plugins as p
6
6
  import ckan.plugins.toolkit as tk
7
7
 
8
- from ckanext.search_tweaks import feature_disabled
9
8
  from ckanext.search_tweaks.interfaces import ISearchTweaks
9
+ from ckanext.search_tweaks.shared import feature_disabled
10
+
10
11
  from . import views
11
12
 
12
13
  CONFIG_BOOST_FN = "ckanext.search_tweaks.field_relevance.boost_function"
@@ -5,8 +5,10 @@ from typing import Any
5
5
 
6
6
  import ckan.plugins as plugins
7
7
  import ckan.plugins.toolkit as tk
8
- from . import feature_disabled, config
8
+
9
+ from . import config
9
10
  from .interfaces import ISearchTweaks
11
+ from .shared import feature_disabled
10
12
 
11
13
  log = logging.getLogger(__name__)
12
14
  CONFIG_PREFER_BOOST = "ckanext.search_tweaks.common.prefer_boost"
@@ -74,10 +76,7 @@ def _set_qf(search_params: dict[str, Any]) -> None:
74
76
 
75
77
 
76
78
  def _set_fuzzy(search_params: dict[str, Any]) -> None:
77
- if not config.fuzzy():
78
- return
79
-
80
- if feature_disabled("fuzzy", search_params):
79
+ if not config.fuzzy() or feature_disabled("fuzzy", search_params):
81
80
  return
82
81
 
83
82
  distance = _get_fuzzy_distance()
@@ -93,9 +92,9 @@ def _set_fuzzy(search_params: dict[str, Any]) -> None:
93
92
 
94
93
  fuzzy_q = " ".join(
95
94
  map(
96
- lambda s: f"{s}~{distance}"
97
- if s.isalpha() and s not in ("AND", "OR", "TO")
98
- else s,
95
+ lambda s: (
96
+ f"{s}~{distance}" if s.isalpha() and s not in ("AND", "OR", "TO") else s
97
+ ),
99
98
  q.split(),
100
99
  ),
101
100
  )
@@ -1,14 +1,20 @@
1
1
  from __future__ import annotations
2
+
2
3
  from typing import Any
3
- from ckan import types
4
+
4
5
  import ckan.plugins.toolkit as tk
6
+ from ckan import types
7
+ from ckan.logic import validate
5
8
 
6
9
  from ckanext.search_tweaks.query_popularity.score import Score
7
10
 
11
+ from . import schema
12
+
8
13
 
9
14
  @tk.side_effect_free
10
15
  def search_tweaks_query_popularity_list(
11
- context: types.Context, data_dict: dict[str, Any]
16
+ context: types.Context,
17
+ data_dict: dict[str, Any],
12
18
  ) -> list[dict[str, Any]]:
13
19
  score = Score()
14
20
 
@@ -22,17 +28,32 @@ def search_tweaks_query_popularity_list(
22
28
 
23
29
  @tk.side_effect_free
24
30
  def search_tweaks_query_popularity_export(
25
- context: types.Context, data_dict: dict[str, Any]
31
+ context: types.Context,
32
+ data_dict: dict[str, Any],
33
+ ) -> list[Any]:
34
+ score = Score()
35
+
36
+ return score.export()
37
+
38
+
39
+ @validate(schema.query_popularity_import)
40
+ def search_tweaks_query_popularity_import(
41
+ context: types.Context,
42
+ data_dict: dict[str, Any],
26
43
  ) -> dict[str, Any]:
44
+ tk.check_access("sysadmin", context, data_dict)
27
45
  score = Score()
28
46
 
29
- results = score.export()
30
- return {"results": results, "count": len(results)}
47
+ if tk.asbool(data_dict.get("reset")):
48
+ score.reset()
49
+ score.restore(data_dict["snapshot"])
50
+ score.refresh()
51
+ return {"success": True}
31
52
 
32
53
 
33
- @tk.side_effect_free
34
54
  def search_tweaks_query_popularity_ignore(
35
- context: types.Context, data_dict: dict[str, Any]
55
+ context: types.Context,
56
+ data_dict: dict[str, Any],
36
57
  ):
37
58
  q = tk.get_or_bust(data_dict, "q")
38
59
  score = Score()
@@ -1,23 +1,27 @@
1
1
  from __future__ import annotations
2
+
2
3
  from typing import Any
3
- from ckan import types
4
4
 
5
+ from ckan import types
5
6
  from ckan.authz import is_authorized
6
7
 
7
8
 
8
9
  def search_tweaks_query_popularity_list(
9
- context: types.Context, data_dict: dict[str, Any]
10
+ context: types.Context,
11
+ data_dict: dict[str, Any],
10
12
  ) -> types.AuthResult:
11
13
  return is_authorized("sysadmin", context, data_dict)
12
14
 
13
15
 
14
16
  def search_tweaks_query_popularity_export(
15
- context: types.Context, data_dict: dict[str, Any]
17
+ context: types.Context,
18
+ data_dict: dict[str, Any],
16
19
  ) -> types.AuthResult:
17
20
  return is_authorized("sysadmin", context, data_dict)
18
21
 
19
22
 
20
23
  def search_tweaks_query_popularity_ignore(
21
- context: types.Context, data_dict: dict[str, Any]
24
+ context: types.Context,
25
+ data_dict: dict[str, Any],
22
26
  ) -> types.AuthResult:
23
27
  return is_authorized("sysadmin", context, data_dict)
@@ -0,0 +1,10 @@
1
+ from __future__ import annotations
2
+
3
+ from ckan.logic.schema import validator_args
4
+
5
+ @validator_args
6
+ def query_popularity_import(not_empty, boolean_validator, convert_to_json_if_string):
7
+ return {
8
+ "snapshot": [not_empty, convert_to_json_if_string],
9
+ "reset": [boolean_validator],
10
+ }
@@ -1,8 +1,12 @@
1
1
  from __future__ import annotations
2
+
2
3
  from typing import Any
4
+
3
5
  import ckan.plugins as p
4
6
  import ckan.plugins.toolkit as tk
7
+
5
8
  from ckanext.search_tweaks.interfaces import IQueryPopularity
9
+
6
10
  from . import config, score
7
11
 
8
12
 
@@ -16,12 +20,16 @@ class QueryPopularityPlugin(p.SingletonPlugin):
16
20
 
17
21
  def after_dataset_search(self, results: dict[str, Any], params: dict[str, Any]):
18
22
  bp, view = tk.get_endpoint()
19
- if bp and view and f"{bp}.{view}" in config.tracked_endpoints():
20
- if not any(
23
+ if (
24
+ bp
25
+ and view
26
+ and f"{bp}.{view}" in config.tracked_endpoints()
27
+ and not any(
21
28
  plugin.skip_query_popularity(params)
22
29
  for plugin in p.PluginImplementations(IQueryPopularity)
23
- ):
24
- self.score.save(params["q"])
30
+ )
31
+ ):
32
+ self.score.hit(params["q"].strip())
25
33
 
26
34
  return results
27
35
 
@@ -40,8 +48,4 @@ class QueryPopularityPlugin(p.SingletonPlugin):
40
48
 
41
49
  terms = config.ignored_terms()
42
50
 
43
- for term in terms:
44
- if term in q:
45
- return True
46
-
47
- return False
51
+ return any(term in q for term in terms)
@@ -1,13 +1,10 @@
1
1
  from __future__ import annotations
2
- from collections import defaultdict
3
- from datetime import datetime, timedelta
2
+
4
3
  import logging
5
- from hashlib import md5
6
- from typing import Any, Iterable, cast
7
- from operator import itemgetter
8
- from ckan.lib.redis import connect_to_redis
9
- import ckan.plugins.toolkit as tk
10
- from redis import Redis
4
+ from typing import Any, Iterable
5
+
6
+ from ckanext.toolbelt.utils.tracking import DateTracker
7
+
11
8
  from . import config
12
9
 
13
10
  log = logging.getLogger(__name__)
@@ -15,151 +12,35 @@ connect_to_redis: Any
15
12
 
16
13
 
17
14
  class Score:
18
- redis: Redis[bytes]
19
- date_format = "%Y-%m-%d %H-%M"
20
-
21
15
  def __init__(self):
22
- self.redis = connect_to_redis()
23
-
24
- site = tk.config["ckan.site_id"]
25
- self.prefix = f"{site}:search_tweaks:qp"
16
+ self.track = DateTracker(
17
+ "search_tweaks:qp",
18
+ throttling_time=config.throttle(),
19
+ max_age=config.max_age(),
20
+ obsoletion_period=config.obsoletion_period(),
21
+ personalized=True,
22
+ )
26
23
 
27
24
  def export(self):
28
- data: dict[bytes, dict[str, Any]] = {
29
- hash: {"query": query, "records": []}
30
- for hash, query in self.redis.hgetall(self.trans_key()).items()
31
- }
32
- for k, v in self.redis.hscan_iter(self.distribution_key()):
33
- date_str, q_hash = k.split(b"/", 1)
34
- try:
35
- date = datetime.strptime(date_str.decode(), self.date_format)
36
- except ValueError:
37
- continue
38
-
39
- data[q_hash]["records"].append({"date": date, "count": int(v)})
40
-
41
- return list(data.values())
42
-
43
- def save(self, q: str):
44
- q = q.strip()
45
- q_hash = self.hash(q)
46
-
47
- if self.is_ignored(q_hash):
48
- return
25
+ return self.track.snapshot()
49
26
 
50
- if self.is_throttling(q_hash):
51
- return
27
+ def restore(self, snapshot: Any):
28
+ return self.track.restore(snapshot)
52
29
 
53
- self.redis.hset(self.trans_key(), q_hash, q)
30
+ def hit(self, q: str):
31
+ self.track.hit(q)
54
32
 
55
- date_stem = self.format_date_stem(self.now())
33
+ def refresh(self):
34
+ self.track.refresh()
56
35
 
57
- self.redis.hincrby(self.distribution_key(), f"{date_stem}/{q_hash}", 1)
36
+ def stats(self, num: int) -> Iterable[dict[str, str | float]]:
37
+ return self.track.most_common(num)
58
38
 
59
39
  def drop(self, q: str):
60
- q_hash = self.hash(q)
61
- dk = self.distribution_key()
62
-
63
- series = self.redis.hscan_iter(dk, f"*/{q_hash}")
64
- keys = list(map(itemgetter(0), series))
65
- if keys:
66
- self.redis.hdel(dk, *keys)
67
-
68
- self.redis.hdel(self.trans_key(), q_hash)
69
- self.redis.zrem(self.score_key(), q_hash)
70
-
71
- def is_throttling(self, q_hash: str):
72
- user = tk.current_user.name
73
-
74
- throttle_key = f"{self.prefix}:throttle:{user}:{q_hash}"
75
- if self.redis.exists(throttle_key):
76
- return True
77
-
78
- self.redis.set(throttle_key, 1, ex=config.throttle())
79
- return False
40
+ self.track.drop(q)
80
41
 
81
42
  def reset(self):
82
- keys = self.redis.keys(f"{self.prefix}:*")
83
- if keys:
84
- self.redis.delete(*keys)
85
-
86
- def refresh(self):
87
- max_age = timedelta(seconds=config.max_age())
88
- dk = self.distribution_key()
89
- sk = self.score_key()
90
-
91
- expired_dist: set[bytes] = set()
92
- distribution = cast(
93
- "Iterable[tuple[bytes, bytes]]",
94
- self.redis.hscan_iter(dk),
95
- )
96
-
97
- scores: dict[bytes, float] = defaultdict(float)
98
-
99
- for k, v in distribution:
100
- date_str, q_hash = k.split(b"/", 1)
101
- try:
102
- date = datetime.strptime(date_str.decode(), self.date_format)
103
- except ValueError:
104
- log.error("Remove invalid key %s", k)
105
- expired_dist.add(k)
106
- continue
107
-
108
- age = self.now() - date
109
-
110
- if age > max_age:
111
- expired_dist.add(k)
112
- continue
113
-
114
- scores[q_hash] += int(v) / (age.seconds // config.obsoletion_period() + 1)
115
-
116
- if expired_dist:
117
- self.redis.hdel(dk, *expired_dist)
118
-
119
- expired_scores: set[bytes] = set()
120
- for k, v in self.redis.zscan_iter(sk):
121
- if k not in scores:
122
- expired_scores.add(k)
123
- continue
124
- if scores:
125
- self.redis.zadd(sk, cast(Any, scores))
126
-
127
- if expired_scores:
128
- self.redis.zrem(sk, *expired_scores)
129
- self.redis.hdel(self.trans_key(), *expired_scores)
130
-
131
- def hash(self, q: str):
132
- return md5(q.encode()).hexdigest()
133
-
134
- def is_ignored(self, q_hash: str):
135
- return self.redis.sismember(self.ignore_key(), q_hash)
43
+ self.track.reset()
136
44
 
137
45
  def ignore(self, q: str):
138
- return self.redis.sadd(self.ignore_key(), self.hash(q))
139
-
140
- def now(self):
141
- return datetime.utcnow()
142
-
143
- def score_key(self):
144
- return f"{self.prefix}:score"
145
-
146
- def trans_key(self):
147
- return f"{self.prefix}:trans"
148
-
149
- def ignore_key(self):
150
- return f"{self.prefix}:ignore"
151
-
152
- def distribution_key(self):
153
- return f"{self.prefix}:distribution"
154
-
155
- def format_date_stem(self, date: datetime):
156
- return date.strftime(self.date_format)
157
-
158
- def stats(self, num: int) -> Iterable[dict[str, Any]]:
159
- scores: list[tuple[bytes, float]] = self.redis.zrange(
160
- self.score_key(), 0, num - 1, desc=True, withscores=True
161
- )
162
- trans_key = self.trans_key()
163
-
164
- for k, v in scores:
165
- yield {"query": self.redis.hget(trans_key, k), "score": v}
46
+ self.track.ignore(self.track.hash(q))
@@ -6,9 +6,10 @@ from typing import Any
6
6
  import ckan.plugins as plugins
7
7
  import ckan.plugins.toolkit as tk
8
8
 
9
- from ckanext.search_tweaks import feature_disabled
10
9
  from ckanext.search_tweaks.cli import attach_relevance_command
11
10
  from ckanext.search_tweaks.interfaces import ISearchTweaks
11
+ from ckanext.search_tweaks.shared import feature_disabled
12
+
12
13
  from . import QueryScore, cli, normalize_query, update_score_by_url
13
14
 
14
15
  CONFIG_BOOST_STRING = "ckanext.search_tweaks.query_relevance.boost_function"
@@ -1,10 +1,11 @@
1
1
  from __future__ import annotations
2
- from abc import ABC, abstractclassmethod, abstractmethod
2
+
3
+ from abc import ABC, abstractmethod
3
4
  from datetime import date, timedelta
4
- from typing import Any, Iterable, cast, Tuple
5
+ from typing import Any, Iterable, Tuple, cast
5
6
 
6
7
  import ckan.plugins.toolkit as tk
7
- from ckan.lib.redis import connect_to_redis, Redis
8
+ from ckan.lib.redis import Redis, connect_to_redis
8
9
 
9
10
  CONFIG_DAILY_AGE = "ckanext.search_tweaks.query_relevance.daily.age"
10
11
  DEFAULT_DAILY_AGE = 90
@@ -36,13 +37,13 @@ class ScoreStorage(ABC):
36
37
  ...
37
38
 
38
39
  @classmethod
39
- @abstractclassmethod
40
+ @abstractmethod
40
41
  def scan(cls, id_: str | None = None) -> Iterable[ScanItem]:
41
42
  """Get all the scores."""
42
43
  ...
43
44
 
44
45
  @classmethod
45
- @abstractclassmethod
46
+ @abstractmethod
46
47
  def reset_storage(cls):
47
48
  """Remove everything from storage."""
48
49
  ...
@@ -53,6 +54,7 @@ class ScoreStorage(ABC):
53
54
 
54
55
  def align(self) -> None:
55
56
  """Make some cleanup in order to maintain fast and correct value."""
57
+ return
56
58
 
57
59
 
58
60
  class RedisScoreStorage(ScoreStorage):
@@ -80,8 +82,7 @@ class RedisScoreStorage(ScoreStorage):
80
82
  conn.delete(key)
81
83
 
82
84
  @abstractmethod
83
- def _key(self) -> str:
84
- ...
85
+ def _key(self) -> str: ...
85
86
 
86
87
  def reset(self):
87
88
  self.conn.delete(self._key())
@@ -135,8 +136,7 @@ class DailyRedisScoreStorage(RedisScoreStorage):
135
136
  def get(self) -> int:
136
137
  key = self._key()
137
138
  values = self.conn.zrange(key, 0, -1, withscores=True)
138
- total = self._total(values)
139
- return total
139
+ return self._total(values)
140
140
 
141
141
  @staticmethod
142
142
  def _total(values: list[tuple[Any, Any]]) -> int:
@@ -24,7 +24,9 @@ def get_helpers():
24
24
 
25
25
 
26
26
  def spellcheck_did_you_mean(
27
- q: str, min_hits: int = 0, max_suggestions: int = None,
27
+ q: str,
28
+ min_hits: int = 0,
29
+ max_suggestions: int = None,
28
30
  ) -> list[str]:
29
31
  """Return optimal query that can be used instead of the current one.
30
32
 
@@ -71,7 +73,11 @@ def spellcheck_did_you_mean(
71
73
 
72
74
  # TODO: check min hits
73
75
  new_q = " ".join(
74
- [spellcheck.suggestions[w][0] for w in terms if w in spellcheck.suggestions],
76
+ [
77
+ spellcheck.suggestions[w][0]
78
+ for w in terms
79
+ if w in spellcheck.suggestions
80
+ ],
75
81
  )
76
82
  if new_q:
77
83
  collations.append(new_q)
@@ -44,8 +44,8 @@ class TestHelper:
44
44
  Dataset(title="Do not touch me")
45
45
  helper = tk.h.spellcheck_did_you_mean
46
46
  rebuild_dictionary()
47
- assert helper("pick thes") == ["pick test"]
48
- assert helper("do nat touc me") == ["do not touch me"]
47
+ assert helper("pick thes") == ["pick this"]
48
+ assert helper("do nat touc") == ["do not touch"]
49
49
 
50
50
  assert helper("pic", 3) == [
51
51
  "pick",
@@ -3,7 +3,6 @@ import pytest
3
3
  import ckan.lib.search.query as query
4
4
  import ckan.plugins as p
5
5
 
6
- import ckanext.search_tweaks.plugin as plugin
7
6
  import ckanext.search_tweaks.config as config
8
7
  from ckanext.search_tweaks.config import CONFIG_PREFER_BOOST
9
8
 
@@ -76,7 +75,11 @@ class TestFuzzy:
76
75
  @pytest.mark.ckan_config(config.CONFIG_FUZZY, True)
77
76
  @pytest.mark.parametrize("distance", [-10, -1, 0])
78
77
  def test_fuzzy_enabled_with_too_low_distance(
79
- self, search, distance, ckan_config, monkeypatch,
78
+ self,
79
+ search,
80
+ distance,
81
+ ckan_config,
82
+ monkeypatch,
80
83
  ):
81
84
  monkeypatch.setitem(ckan_config, config.CONFIG_FUZZY_DISTANCE, distance)
82
85
  assert search(q="")["q"] == "*:*"
@@ -89,7 +92,11 @@ class TestFuzzy:
89
92
  @pytest.mark.ckan_config(config.CONFIG_FUZZY, True)
90
93
  @pytest.mark.parametrize("distance", [3, 20, 111])
91
94
  def test_fuzzy_enabled_with_too_high_distance(
92
- self, search, distance, ckan_config, monkeypatch,
95
+ self,
96
+ search,
97
+ distance,
98
+ ckan_config,
99
+ monkeypatch,
93
100
  ):
94
101
  monkeypatch.setitem(ckan_config, config.CONFIG_FUZZY_DISTANCE, distance)
95
102
  assert search()["q"] == "*:*"
@@ -101,7 +108,11 @@ class TestFuzzy:
101
108
  @pytest.mark.ckan_config(config.CONFIG_FUZZY, True)
102
109
  @pytest.mark.parametrize("distance", [1, 2])
103
110
  def test_fuzzy_keep_original_query(
104
- self, search, distance, ckan_config, monkeypatch,
111
+ self,
112
+ search,
113
+ distance,
114
+ ckan_config,
115
+ monkeypatch,
105
116
  ):
106
117
  monkeypatch.setitem(ckan_config, config.CONFIG_FUZZY_DISTANCE, distance)
107
118
  assert search()["q"] == "*:*"
@@ -0,0 +1 @@
1
+ import sys, types, os;p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('ckanext',));importlib = __import__('importlib.util');__import__('importlib.machinery');m = sys.modules.setdefault('ckanext', importlib.util.module_from_spec(importlib.machinery.PathFinder.find_spec('ckanext', [os.path.dirname(p)])));m = m or sys.modules.setdefault('ckanext', types.ModuleType('ckanext'));mp = (m or []) and m.__dict__.setdefault('__path__',[]);(p not in mp) and mp.append(p)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ckanext-search-tweaks
3
- Version: 0.6.0
3
+ Version: 0.6.1
4
4
  Home-page: https://github.com/DataShades/ckanext-search-tweaks
5
5
  Author: Sergey Motornyuk
6
6
  Author-email: sergey.motornyuk@linkdigital.com.au
@@ -15,6 +15,7 @@ Description-Content-Type: text/markdown
15
15
  License-File: LICENSE
16
16
  Requires-Dist: freezegun
17
17
  Requires-Dist: typing-extensions >=4.0.0
18
+ Requires-Dist: ckanext-toolbelt >=0.4.11
18
19
  Provides-Extra: advanced-search
19
20
 
20
21
  [![Tests](https://github.com/DataShades/ckanext-search-tweaks/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/DataShades/ckanext-search-tweaks/actions)
@@ -1,52 +1,53 @@
1
- ckanext_search_tweaks-0.6.0-py3.8-nspkg.pth,sha256=VaH--vNo0_vzXvZAeqyq-Bg6m47pBBRlxwvBj0KQxe0,544
2
- ckanext/search_tweaks/__init__.py,sha256=qcODHzdZk2RZsrNAKKcYKL2Y2yJ6Fwwyp7AfwZiJ8SI,73
1
+ ckanext_search_tweaks-0.6.1-py3.8-nspkg.pth,sha256=NXfLjB2L7-vMVBgj11KMWlHly-aPPPj1kuWUW7A1iMM,472
2
+ ckanext/search_tweaks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  ckanext/search_tweaks/cli.py,sha256=Pex34fMESkVycy6kOfODtNmHh8nPMvzFKTeZD0txLvc,308
4
4
  ckanext/search_tweaks/config.py,sha256=NX7rsslGJyxQ8xTZidy9fI-SDkJ4lX4oLTX54lVLGI0,941
5
5
  ckanext/search_tweaks/interfaces.py,sha256=pOu2PyMVxu7XDyGCvP42upm5N4Ws1KR0qzyW8wE2CGY,869
6
- ckanext/search_tweaks/plugin.py,sha256=Pfx3QtdrUrh1dpqd0K7tUsEHDYvmo30BgORIx1NG1PA,3323
6
+ ckanext/search_tweaks/plugin.py,sha256=Bk1ejlTsKxUcIjckuzQBj_nwUbIz7H5t-AwqtmCvaIw,3330
7
7
  ckanext/search_tweaks/shared.py,sha256=9aWN_OXB5-h99lecnZVoZpLY6F8hbIRNX6WUQaoOoYI,325
8
8
  ckanext/search_tweaks/advanced_search/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- ckanext/search_tweaks/advanced_search/plugin.py,sha256=mrJEx12AtfdyF4m1yF3q_RpH5ytpxx7IK1jpo_n3mkQ,3234
9
+ ckanext/search_tweaks/advanced_search/plugin.py,sha256=yYjC-ow-fFfvUOGJfsl3OpkifdrcqA_kWI9j-9lyVhI,3242
10
10
  ckanext/search_tweaks/advanced_search/assets/advanced-search.css,sha256=KlBYOihUJepiu2iiGcRjIWZltogEqI8iGbO-28Wgnqw,584
11
11
  ckanext/search_tweaks/advanced_search/assets/advanced-search.js,sha256=rkgprbv9fUnWoxgISXmoxHkSC4Z9OLXgZoOIICpn9X8,2328
12
12
  ckanext/search_tweaks/advanced_search/assets/webassets.yml,sha256=g0NMsLyHzslxtkIXRFj_Vf-SU6b8MYlBiuHc50SQiAo,439
13
13
  ckanext/search_tweaks/advanced_search/templates/advanced_search/search_form.html,sha256=QlKCxEUDGP1g4oZEOKAGSuopjrJsbcgK2cs28k3X4Vc,4266
14
14
  ckanext/search_tweaks/field_relevance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- ckanext/search_tweaks/field_relevance/plugin.py,sha256=r4wILcdKIpYI6GT43Tbr3eVSltzJkmshZwto1rLiCtI,1424
15
+ ckanext/search_tweaks/field_relevance/plugin.py,sha256=89hK-S_Ox0IwFKbN5wINmyCug4_pRIl-8pvVQVF_xnk,1432
16
16
  ckanext/search_tweaks/field_relevance/views.py,sha256=vtSOFXRgmzcypLkl_ZBs-enDk0raE2GPd_ruIKJv8IA,3214
17
17
  ckanext/search_tweaks/field_relevance/assets/search-tweaks-reflect-range-in-label.js,sha256=WFAzPBvzf6SWaEAQJTxiEGhZm-65o676MN6KttCpvbo,490
18
18
  ckanext/search_tweaks/field_relevance/assets/webassets.yml,sha256=PGr_EC4jOTABCRc3JCIAqYCzCMNgGG1KYE6Ua0S0vfk,184
19
19
  ckanext/search_tweaks/field_relevance/templates/search_tweaks/field_relevance/promote.html,sha256=uqB9Wf7OJzF3-Ep6VZwe3bYICdzy0JhJPJzNPuMLBr0,1118
20
20
  ckanext/search_tweaks/query_popularity/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  ckanext/search_tweaks/query_popularity/config.py,sha256=O-YptWOeDQ6tyVLZ10D3dVs5tGhjOoOtFY3Xw_InmjA,858
22
- ckanext/search_tweaks/query_popularity/plugin.py,sha256=Gd5u2h6U2wv-qmNY2pXt7AMld0EA43ISSCozVVMvRxE,1391
23
- ckanext/search_tweaks/query_popularity/score.py,sha256=CUGT9AuUYxiMFV06HIGbB00C1VuRrJlo-5vg01WtfqY,4794
22
+ ckanext/search_tweaks/query_popularity/plugin.py,sha256=ih9c7CrI-A1ilfe9I1Hb_3BdMOnzNsTyMfJA7c0Qs8A,1391
23
+ ckanext/search_tweaks/query_popularity/score.py,sha256=JfOiR7yj22euNrIX3T_VYjzB7ilGpDmr4hmXFHfsSAc,1052
24
24
  ckanext/search_tweaks/query_popularity/logic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
- ckanext/search_tweaks/query_popularity/logic/action.py,sha256=9yJ9n8HreSiQmLS_1Ld08BGryVwGqMF17f9PBgg6RH4,1041
26
- ckanext/search_tweaks/query_popularity/logic/auth.py,sha256=ozcJK0sLljM95f8CXrpZRWckMcCJIK_zUfx8HhUF1bE,654
25
+ ckanext/search_tweaks/query_popularity/logic/action.py,sha256=uG6IdAX2b8YztmcxiAho3A6-S41IPrRhvyV36CAM95g,1422
26
+ ckanext/search_tweaks/query_popularity/logic/auth.py,sha256=6jddjTxo9NX_a-_jQz_8Mj7273zfkfZz1_BOW6JzHm0,670
27
+ ckanext/search_tweaks/query_popularity/logic/schema.py,sha256=rgjmRyGb7zlBOLZo284XcH9F6VepmIv5yvoxTGxLByA,301
27
28
  ckanext/search_tweaks/query_relevance/__init__.py,sha256=mGpZuwY8UwPMuxjNLhGVYoaXPfLx5UPMixpldIjZuSY,1467
28
29
  ckanext/search_tweaks/query_relevance/cli.py,sha256=7wU3nWdCQNaUi2O_zARy7usvUysE-wnp5h_yRlw7nAo,2576
29
- ckanext/search_tweaks/query_relevance/plugin.py,sha256=ZgtFyBm_RuUCSOldqYdq_gajEbDW1ecmIsKaQJaqJ7c,2440
30
+ ckanext/search_tweaks/query_relevance/plugin.py,sha256=W9qmwWD_wThedqpLNgxNY--N0TsHtPDoW4EfcbaWGhw,2448
30
31
  ckanext/search_tweaks/query_relevance/score.py,sha256=hfrfgNP5OUf7YBBDuFFBZb66ixpiAlnM-KAXzUVexXc,1811
31
- ckanext/search_tweaks/query_relevance/storage.py,sha256=TmeHbeL41Dp5bxN1eNXdb5KG7fNHoExHVnRs73kgz6A,4897
32
+ ckanext/search_tweaks/query_relevance/storage.py,sha256=7SP1arTjTvbHrWDZhzu9E0pWxk4ygz3NcpDk7P4YODk,4852
32
33
  ckanext/search_tweaks/spellcheck/__init__.py,sha256=Af3LHk9L82QtAh4q7C3srzCwJiF6WCtxe4CFTPKhFMQ,1401
33
34
  ckanext/search_tweaks/spellcheck/cli.py,sha256=X1HAXhElqJ6Hrc30USxXG50F-1RS0uvxP2tr3S6jnK0,250
34
- ckanext/search_tweaks/spellcheck/helpers.py,sha256=RXVVFRaJmyAJ7-A3Tp6tsnxPI646mkowWUoZTVnVFRw,4327
35
+ ckanext/search_tweaks/spellcheck/helpers.py,sha256=khlpo5acwxUZ4lDNH9V3EP1BAvLf1-Z6UY_dQCPqOow,4397
35
36
  ckanext/search_tweaks/spellcheck/plugin.py,sha256=lKRNAl5V9REnjTNOhC9e4AfGLAw3wm3oQTwjS8hGofY,592
36
37
  ckanext/search_tweaks/spellcheck/templates/search_tweaks/did_you_mean.html,sha256=5IAoogXrnYb8KecOLaPKQUerYCwkbEP5SQVjekeduHM,654
37
38
  ckanext/search_tweaks/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
39
  ckanext/search_tweaks/tests/conftest.py,sha256=Moxwo1WE8Yl6su50C7bqG6IEH3t38UW4PtfHe1SiiAk,662
39
- ckanext/search_tweaks/tests/test_plugin.py,sha256=ScRWCNf0n_mpiP0rJlwygXhjb1ACNImH0qFItFsq_ac,4713
40
+ ckanext/search_tweaks/tests/test_plugin.py,sha256=WVnGzQP5nHzIht7PJEEIFrJ92tq5XuivQ0o8UNiRXSs,4763
40
41
  ckanext/search_tweaks/tests/query_relevance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
42
  ckanext/search_tweaks/tests/query_relevance/test_plugin.py,sha256=RBraEO6_LMvHx9ekDz_h8LgtpEJV8BkR3q-9QotRGWA,2196
42
43
  ckanext/search_tweaks/tests/query_relevance/test_score.py,sha256=RwG_o8QyW3BZBx3J5Cs1UUkMHi0DGR-mWvlSlk3ibaU,1140
43
44
  ckanext/search_tweaks/tests/query_relevance/test_storage.py,sha256=xBHB69zHE301mHlUB2hz0RXJaqFrhRMesAz2LNYNFE0,2825
44
45
  ckanext/search_tweaks/tests/spellcheck/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
- ckanext/search_tweaks/tests/spellcheck/test_plugin.py,sha256=9xH8dVFJzJarduKJ5yqJguoJ1EVE2-CpwoVCwvCkxBI,2523
46
- ckanext_search_tweaks-0.6.0.dist-info/LICENSE,sha256=2lWcRAHjsQhqavGNnR30Ymxq3GJ9BaYL_dnfGO_-WFA,34500
47
- ckanext_search_tweaks-0.6.0.dist-info/METADATA,sha256=_u5GGldZYOUPYIf1U499o37A6ELhDzx7epss-wKTTJk,12097
48
- ckanext_search_tweaks-0.6.0.dist-info/WHEEL,sha256=Xo9-1PvkuimrydujYJAjF7pCkriuXBpUPEjma1nZyJ0,92
49
- ckanext_search_tweaks-0.6.0.dist-info/entry_points.txt,sha256=0hvD0BILJCAPZBOTH28bAMN8XCbPrltTZ6Q8-mUZGyE,615
50
- ckanext_search_tweaks-0.6.0.dist-info/namespace_packages.txt,sha256=5yjNwq-s42weaiMMUuA5lZ45g99ANsfcRBCvac1JMS4,8
51
- ckanext_search_tweaks-0.6.0.dist-info/top_level.txt,sha256=5yjNwq-s42weaiMMUuA5lZ45g99ANsfcRBCvac1JMS4,8
52
- ckanext_search_tweaks-0.6.0.dist-info/RECORD,,
46
+ ckanext/search_tweaks/tests/spellcheck/test_plugin.py,sha256=4pocLV8uzea2ua8LUTC3IXlyYc3oKbhApODA1uWHNFU,2517
47
+ ckanext_search_tweaks-0.6.1.dist-info/LICENSE,sha256=2lWcRAHjsQhqavGNnR30Ymxq3GJ9BaYL_dnfGO_-WFA,34500
48
+ ckanext_search_tweaks-0.6.1.dist-info/METADATA,sha256=2QXShGSroLXSecuBihN3hKU2gy-ZRlOqTTYrLGQT_28,12138
49
+ ckanext_search_tweaks-0.6.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
50
+ ckanext_search_tweaks-0.6.1.dist-info/entry_points.txt,sha256=0hvD0BILJCAPZBOTH28bAMN8XCbPrltTZ6Q8-mUZGyE,615
51
+ ckanext_search_tweaks-0.6.1.dist-info/namespace_packages.txt,sha256=5yjNwq-s42weaiMMUuA5lZ45g99ANsfcRBCvac1JMS4,8
52
+ ckanext_search_tweaks-0.6.1.dist-info/top_level.txt,sha256=5yjNwq-s42weaiMMUuA5lZ45g99ANsfcRBCvac1JMS4,8
53
+ ckanext_search_tweaks-0.6.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.3)
2
+ Generator: bdist_wheel (0.43.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1 +0,0 @@
1
- import sys, types, os;has_mfs = sys.version_info > (3, 5);p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('ckanext',));importlib = has_mfs and __import__('importlib.util');has_mfs and __import__('importlib.machinery');m = has_mfs and sys.modules.setdefault('ckanext', importlib.util.module_from_spec(importlib.machinery.PathFinder.find_spec('ckanext', [os.path.dirname(p)])));m = m or sys.modules.setdefault('ckanext', types.ModuleType('ckanext'));mp = (m or []) and m.__dict__.setdefault('__path__',[]);(p not in mp) and mp.append(p)