Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hss 30114 increment supported python version to 3 11 #91

Draft
wants to merge 20 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @hearsaycorp/social-content
37 changes: 37 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Run tests

on:
push:
branches:
- '**'
- '!master'
pull_request:
branches:
- '**'
- '!master'

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.9', '3.10', '3.11', '3.12']
env:
PYPI_USERNAME: ${{ secrets.PYPI_READ_USERNAME }}
PYPI_PASSWORD: ${{ secrets.PYPI_READ_PASSWORD }}
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
make test_install

- name: Test with tox
run: tox
16 changes: 8 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
ELASTICMOCK_VERSION='1.8.0'
ELASTICMOCK_VERSION='3.0.0'

install:
pip3 install -r requirements.txt
pip install -r requirements.txt

test_install: install
pip3 install -r requirements_test.txt
pip install -r requirements_test.txt

test: test_install
python3.8 setup.py test
python3 setup.py test

upload: create_dist
pip3 install twine
pip install twine
twine upload dist/*
git push

create_dist: create_dist_no_commit update_pip
rm -rf dist
python3.8 setup.py sdist
python3 setup.py sdist

create_dist_no_commit: update_pip
rm -rf dist
python3.8 setup.py sdist
python3 setup.py sdist

create_dist_commit:
git commit --all -m "Bump version ${ELASTICMOCK_VERSION}"
git tag ${ELASTICMOCK_VERSION}

update_pip:
pip3 install --upgrade pip
pip install --upgrade pip
90 changes: 64 additions & 26 deletions elasticmock/fake_elasticsearch.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from elasticmock.fake_cluster import FakeClusterClient
from elasticmock.fake_indices import FakeIndicesClient
from elasticmock.utilities import (extract_ignore_as_iterable, get_random_id,
get_random_scroll_id)
get_random_scroll_id)
from elasticmock.utilities.decorator import for_all_methods

PY3 = sys.version_info[0] == 3
Expand All @@ -35,6 +35,9 @@ class QueryType:
SHOULD = 'SHOULD'
MINIMUM_SHOULD_MATCH = 'MINIMUM_SHOULD_MATCH'
MULTI_MATCH = 'MULTI_MATCH'
MUST_NOT = 'MUST_NOT'
EXISTS = 'EXISTS'
FIELD = 'FIELD'

@staticmethod
def get_query_type(type_str):
Expand All @@ -60,6 +63,12 @@ def get_query_type(type_str):
return QueryType.MINIMUM_SHOULD_MATCH
elif type_str == 'multi_match':
return QueryType.MULTI_MATCH
elif type_str == 'must_not':
return QueryType.MUST_NOT
elif type_str == 'exists':
return QueryType.EXISTS
elif type_str == 'field':
return QueryType.FIELD
else:
raise NotImplementedError(f'type {type_str} is not implemented for QueryType')

Expand Down Expand Up @@ -107,9 +116,27 @@ def _evaluate_for_query_type(self, document):
return self._evaluate_for_should_query_type(document)
elif self.type == QueryType.MULTI_MATCH:
return self._evaluate_for_multi_match_query_type(document)
elif self.type == QueryType.MUST_NOT:
return self._evaluate_for_must_not_query_type(document)
elif self.type == QueryType.EXISTS:
return self._evaluate_for_exists_query_type(document)
elif self.type == QueryType.FIELD:
return self._evaluate_for_compound_query_type(document)
elif self.type == QueryType.MINIMUM_SHOULD_MATCH:
return True
else:
raise NotImplementedError('Fake query evaluation not implemented for query type: %s' % self.type)

def _evaluate_for_must_not_query_type(self, document):
return not self._evaluate_for_compound_query_type(document)

def _evaluate_for_exists_query_type(self, document):
doc_source = document['_source']
return_val = False
for field, value in self.condition.items():
return_val = value in doc_source.keys() and doc_source[value] is not None
return return_val

def _evaluate_for_match_query_type(self, document):
return self._evaluate_for_field(document, True)

Expand Down Expand Up @@ -170,6 +197,9 @@ def _evaluate_for_range_query_type(self, document):
if isinstance(doc_val, list):
return False

if doc_val != 0 and not doc_val:
return True

for sign, value in comparisons.items():
if isinstance(doc_val, datetime.datetime):
value = dateutil.parser.isoparse(value)
Expand Down Expand Up @@ -488,7 +518,7 @@ def mget(self, body, index, doc_type='_all', params=None, headers=None):
for id in ids:
try:
results.append(self.get(index, id, doc_type=doc_type,
params=params, headers=headers))
params=params, headers=headers))
except:
pass
if not results:
Expand Down Expand Up @@ -517,20 +547,11 @@ def get_source(self, index, doc_type, id, params=None, headers=None):
def count(self, index=None, doc_type=None, body=None, params=None, headers=None):
searchable_indexes = self._normalize_index_to_list(index)

i = 0
for searchable_index in searchable_indexes:
for document in self.__documents_dict[searchable_index]:
if doc_type and document.get('_type') != doc_type:
continue
i += 1
contents = self.search(index=index, doc_type=doc_type, body=body, params=params, headers=headers)

result = {
'count': i,
'_shards': {
'successful': 1,
'skipped': 0,
'failed': 0,
'total': 1
}
'count': contents['hits']['hits'].__len__(),
'_shards': contents['_shards']
}

return result
Expand Down Expand Up @@ -643,6 +664,16 @@ def search(self, index=None, doc_type=None, body=None, params=None, headers=None
if aggregations:
result['aggregations'] = aggregations

if body is not None and 'sort' in body:
for key, value in body['sort'][0].items():
if body['sort'][0][key]['order'] == 'desc':
hits = sorted(hits, key=lambda k: k['_source'][key], reverse=True)
else:
hits = sorted(hits, key=lambda k: k['_source'][key])

if body is not None and 'from' in body and 'size' in body and body['from'] + body['size'] > 0:
hits = hits[body['from']:body['from'] + body['size']]

if 'scroll' in params:
result['_scroll_id'] = str(get_random_scroll_id())
params['size'] = int(params.get('size', 10))
Expand Down Expand Up @@ -774,26 +805,33 @@ def make_bucket(bucket_key, bucket):
"doc_count": len(bucket),
}

for metric_key, metric_definition in aggregation["aggs"].items():
metric_type_str = list(metric_definition)[0]
metric_type = MetricType.get_metric_type(metric_type_str)
attr = metric_definition[metric_type_str]["field"]
data = [doc[attr] for doc in bucket]
if "aggs" in aggregation.keys():
for metric_key, metric_definition in aggregation["aggs"].items():
metric_type_str = list(metric_definition)[0]
metric_type = MetricType.get_metric_type(metric_type_str)
attr = metric_definition[metric_type_str]["field"]
data = [doc[attr] for doc in bucket]

if metric_type == MetricType.CARDINALITY:
value = len(set(data))
else:
raise NotImplementedError(f"Metric type '{metric_type}' not implemented")
if metric_type == MetricType.CARDINALITY:
value = len(set(data))
else:
raise NotImplementedError(f"Metric type '{metric_type}' not implemented")

out[metric_key] = {"value": value}
out[metric_key] = {"value": value}
return out

agg_sources = aggregation["composite"]["sources"]
buckets = defaultdict(list)
bucket_key_fields = [list(src)[0] for src in agg_sources]
for document in documents:
doc_src = document["_source"]
key = tuple(make_key(doc_src, agg_src) for agg_src in aggregation["composite"]["sources"])
key = ()
for agg_src in aggregation["composite"]["sources"]:
k=make_key(doc_src, agg_src)
if isinstance(k, list):
key += tuple(k)
else:
key += tuple([k])
buckets[key].append(doc_src)

buckets = sorted(((k, v) for k, v in buckets.items()), key=lambda x: x[0])
Expand Down
2 changes: 1 addition & 1 deletion requirements_test.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
tox
parameterized
tox-gh
6 changes: 5 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import setuptools

__version__ = '1.8.0'
__version__ = '3.0.0'

# read the contents of your readme file
from os import path
Expand Down Expand Up @@ -34,6 +34,10 @@
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
"License :: OSI Approved :: MIT License",
'Topic :: Software Development :: Libraries :: Python Modules'
]
Expand Down
19 changes: 19 additions & 0 deletions tests/fake_elasticsearch/test_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,25 @@ def test_search_bool_should_match_query(self):
self.assertEqual(len(hits), 3)
self.assertEqual(hits[0]['_source'], {'data': 'test_0'})

def test_search_bool_must_not_match_query(self):
for i in range(0, 10):
self.es.index(index='index_for_search', doc_type=DOC_TYPE, body={'data': 'test_{0}'.format(i)})

response = self.es.search(index='index_for_search', doc_type=DOC_TYPE,
body={
'query': {
'bool': {
'must_not': [
{'match': {'data': 'test_0'}},
]
}
}
})
self.assertEqual(response['hits']['total']['value'], 9)
hits = response['hits']['hits']
self.assertEqual(len(hits), 9)
self.assertEqual(hits[0]['_source'], {'data': 'test_1'})

def test_msearch(self):
for i in range(0, 10):
self.es.index(index='index_for_search1', doc_type=DOC_TYPE, body={
Expand Down
33 changes: 33 additions & 0 deletions tests/fake_elasticsearch/test_sort.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from tests import TestElasticmock, INDEX_NAME, DOC_TYPE


class TestSearch(TestElasticmock):

def test_sort_by_field_asc(self):
index_quantity = 10
result = []
for i in range(0, index_quantity):
body = {'data': 'test_{0}'.format(i), 'sort_param':'{0}'.format(i)}
result.append(body)
self.es.index(index=INDEX_NAME, doc_type=DOC_TYPE, body=body)

search = self.es.search(body={'query': {'match_all': {}},
'sort': [{ "sort_param" : {"order" : "asc"}}]
})
search_result = [hit.get('_source') for hit in search.get('hits').get('hits')]
self.assertListEqual(result, search_result)

def test_sort_by_field_desc(self):
index_quantity = 10
result = []
for i in range(0, index_quantity):
body = {'data': 'test_{0}'.format(i), 'sort_param':'{0}'.format(i)}
result.append(body)
self.es.index(index=INDEX_NAME, doc_type=DOC_TYPE, body=body)

search = self.es.search(body={'query': {'match_all': {}},
'sort': [{ "sort_param" : {"order" : "desc"}}]
})
search_result = [hit.get('_source') for hit in search.get('hits').get('hits')]
result.reverse()
self.assertListEqual(result, search_result)
17 changes: 13 additions & 4 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
# content of: tox.ini , put in same dir as setup.py
[tox]
isolated_build = True
envlist =
py36-elasticsearch{1,2,5,6,7}
py37-elasticsearch{1,2,5,6,7}
py38-elasticsearch{1,2,5,6,7}
py39-elasticsearch{1,2,5,6,7}
py310-elasticsearch{1,2,5,6,7}
py311-elasticsearch{1,2,5,6,7}
py312-elasticsearch{1,2,5,6,7}

[testenv]
deps =
parameterized
pytest==4.6.9
pytest==6.2.5
pytest-cov==2.8.1
elasticsearch1: elasticsearch ==1.9.0
elasticsearch2: elasticsearch >=2.0.0, <5.0.0
Expand All @@ -18,3 +20,10 @@ deps =
commands =
python -c "import tests.tox_banner"
py.test --cov-report term-missing --cov=elasticmock

[gh]
python =
3.9 = py39-elasticsearch{1,2,5,6,7}
3.10 = py310-elasticsearch{1,2,5,6,7}
3.11 = py311-elasticsearch{1,2,5,6,7}
3.12 = py312-elasticsearch{1,2,5,6,7}