Skip to content

Commit

Permalink
Merge pull request Sefaria#1754 from Sefaria/api-final
Browse files Browse the repository at this point in the history
Api final
  • Loading branch information
YishaiGlasner authored Jan 11, 2024
2 parents 696456e + 902f20e commit c978c70
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 33 deletions.
6 changes: 3 additions & 3 deletions api/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def text_api_virtual_node(self):

def test_api_get_text_bad_text(self):
response = c.get('/api/v3/texts/Life_of_Pi.13.13')
self.assertEqual(400, response.status_code)
self.assertEqual(404, response.status_code)
data = json.loads(response.content)
self.assertEqual(data["error"], "Could not find title in reference: Life of Pi.13.13")

Expand All @@ -135,13 +135,13 @@ def test_api_get_text_too_many_hyphens(self):

def test_api_get_text_bad_sections(self):
response = c.get('/api/v3/texts/Job.6-X')
self.assertEqual(400, response.status_code)
self.assertEqual(404, response.status_code)
data = json.loads(response.content)
self.assertEqual(data["error"], "Couldn't understand text sections: 'Job.6-X'.")

def test_api_get_text_empty_ref(self):
response = c.get("/api/v3/texts/Berakhot.1a")
self.assertEqual(400, response.status_code)
self.assertEqual(404, response.status_code)
data = json.loads(response.content)
self.assertEqual(data["error"], "We have no text for Berakhot 1a.")

Expand Down
8 changes: 4 additions & 4 deletions api/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from sefaria.model import *
from sefaria.model.text_manager import TextManager
from sefaria.model.text_reuqest_adapter import TextRequestAdapter
from sefaria.client.util import jsonResponse
from django.views import View
from .api_warnings import *
Expand All @@ -13,7 +13,7 @@ def dispatch(self, request, *args, **kwargs):
try:
self.oref = Ref.instantiate_ref_with_legacy_parse_fallback(kwargs['tref'])
except Exception as e:
return jsonResponse({'error': getattr(e, 'message', str(e))}, status=400)
return jsonResponse({'error': getattr(e, 'message', str(e))}, status=404)
return super().dispatch(request, *args, **kwargs)

@staticmethod
Expand Down Expand Up @@ -43,7 +43,7 @@ def _handle_warnings(self, data):

def get(self, request, *args, **kwargs):
if self.oref.is_empty() and not self.oref.index_node.is_virtual:
return jsonResponse({'error': f'We have no text for {self.oref}.'}, status=400)
return jsonResponse({'error': f'We have no text for {self.oref}.'}, status=404)
versions_params = request.GET.getlist('version', [])
if not versions_params:
versions_params = ['primary']
Expand All @@ -52,7 +52,7 @@ def get(self, request, *args, **kwargs):
return_format = request.GET.get('return_format', 'default')
if return_format not in self.RETURN_FORMATS:
return jsonResponse({'error': f'return_format should be one of those formats: {self.RETURN_FORMATS}.'}, status=400)
text_manager = TextManager(self.oref, versions_params, fill_in_missing_segments, return_format)
text_manager = TextRequestAdapter(self.oref, versions_params, fill_in_missing_segments, return_format)
data = text_manager.get_versions_for_query()
data = self._handle_warnings(data)
return jsonResponse(data)
42 changes: 22 additions & 20 deletions sefaria/model/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -1334,12 +1334,12 @@ class Version(AbstractTextRecord, abst.AbstractMongoRecord, AbstractSchemaConten
"purchaseInformationImage",
"purchaseInformationURL",
"hasManuallyWrappedRefs", # true for texts where refs were manually wrapped in a-tags. no need to run linker at run-time.
"actualLanguage",
'languageFamilyName',
"isBaseText",
'isSource',
'isPrimary',
'direction', # 'rtl' or 'ltr'
"actualLanguage", # ISO language code
'languageFamilyName', # full name of the language, but without specificity (for Judeo Arabic actualLanguage=jrb, languageFamilyName=arabic
"isBaseText", # should be deprecated (needs some changes on client side)
'isSource', # bool, True if this version is not a translation
'isPrimary', # bool, True if we see it as a primary version (usually equals to isSource, but Hebrew Kuzarif or example is primary but not source)
'direction', # 'rtl' or 'ltr'
]

def __str__(self):
Expand Down Expand Up @@ -1696,8 +1696,14 @@ def __call__(cls, *args, **kwargs):


class TextRange:
"""
This class is planned to replace TextChunk, using real language rather than he/en
For now it's used by v3 texts api
It can be used for getting text, but not yet for saving
The versions param is for better performance when the version(s) were already loaded from mongo
"""

def __init__(self, oref, lang, vtitle, merge_versions=False):
def __init__(self, oref, lang, vtitle, merge_versions=False, versions=None):
if isinstance(oref.index_node, JaggedArrayNode) or isinstance(oref.index_node, DictionaryEntryNode): #text cannot be SchemaNode
self.oref = oref
elif oref.has_default_child(): #use default child:
Expand All @@ -1707,22 +1713,18 @@ def __init__(self, oref, lang, vtitle, merge_versions=False):
self.lang = lang
self.vtitle = vtitle
self.merge_versions = merge_versions
self._versions = []
self._text = None
self.sources = None
self._set_versions(versions)

@property
def versions(self):
if self._versions == []:
def _set_versions(self, versions):
if versions:
self._validate_versions(versions)
self._versions = versions
else:
condition_query = self.oref.condition_query(self.lang) if self.merge_versions else \
{'title': self.oref.index.title, 'languageFamilyName': self.lang, 'versionTitle': self.vtitle}
self._versions = VersionSet(condition_query, proj=self.oref.part_projection())
return self._versions

@versions.setter
def versions(self, versions):
self._validate_versions(versions)
self._versions = versions

def _validate_versions(self, versions):
if not self.merge_versions and len(versions) > 1:
Expand Down Expand Up @@ -1753,15 +1755,15 @@ def _trim_text(self, text):
@property
def text(self):
if self._text is None:
if self.merge_versions and len(self.versions) > 1:
merged_text, sources = self.versions.merge(self.oref.index_node, prioritized_vtitle=self.vtitle)
if self.merge_versions and len(self._versions) > 1:
merged_text, sources = self._versions.merge(self.oref.index_node, prioritized_vtitle=self.vtitle)
self._text = self._trim_text(merged_text)
if len(sources) > 1:
self.sources = sources
elif self.oref.index_node.is_virtual:
self._text = self.oref.index_node.get_text()
else:
self._text = self._trim_text(self.versions[0].content_node(self.oref.index_node)) #todo if there is no version it will fail
self._text = self._trim_text(self._versions[0].content_node(self.oref.index_node)) #todo if there is no version it will fail
return self._text


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@
from sefaria.system.exceptions import InputError
from sefaria.datatype.jagged_array import JaggedTextArray

class TextManager:
class TextRequestAdapter:
"""
This class is used for getting texts for client side (API or SSR)
It takes the same params as the api/v3/text (ref, version_params that are language and versionTitle, fill_in_missing_segments, and return_format
It returns a JSON-like object for an HTTP response.
"""
ALL = 'all'
PRIMARY = 'primary'
SOURCE = 'source'
Expand Down Expand Up @@ -38,15 +43,15 @@ def _append_version(self, version):
for attr in ['chapter', 'title']:
fields.remove(attr)
version_details = {f: getattr(version, f, "") for f in fields}
text_range = TextRange(self.oref, version.languageFamilyName, version.versionTitle, self.fill_in_missing_segments)

if self.fill_in_missing_segments:
# we need a new VersionSet of only the relevant versions for merging. copy should be better than calling for mongo
relevant_versions = copy.copy(self.all_versions)
relevant_versions.remove(lambda v: v.languageFamilyName != version.languageFamilyName)
else:
relevant_versions = [version]
text_range.versions = relevant_versions
text_range = TextRange(self.oref, version.languageFamilyName, version.versionTitle,
self.fill_in_missing_segments, relevant_versions)
version_details['text'] = text_range.text

sources = getattr(text_range, 'sources', None)
Expand Down
2 changes: 1 addition & 1 deletion static/js/VersionBlock/VersionBlock.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ class VersionBlock extends Component {
}
}
makeSelectVersionLanguage(){
let voc = this.props.version.isBaseText ? 'Version' : "Translation";
let voc = this.props.version.isSource ? 'Version' : "Translation";
return this.props.isCurrent ? Sefaria._("Current " + voc) : Sefaria._("Select "+ voc);
}

Expand Down
4 changes: 2 additions & 2 deletions static/js/sefaria/sefaria.js
Original file line number Diff line number Diff line change
Expand Up @@ -692,13 +692,13 @@ Sefaria = extend(Sefaria, {
},
getTranslations: async function(ref) {
/**
* Gets all versions except Hebrew versions that have isBaseText true
* Gets all versions except Hebrew versions that have isSource true
* @ref {string} ref
* @returns {string: [versions]} Versions by language
*/
return Sefaria.getVersions(ref).then(result => {
let versions = Sefaria.filterVersionsObjByLangs(result, ['he'], false);
let heVersions = Sefaria.filterVersionsArrayByAttr(result?.he || [], {isBaseText: false});
let heVersions = Sefaria.filterVersionsArrayByAttr(result?.he || [], {isSource: false});
if (heVersions.length) {
versions.he = heVersions;
}
Expand Down

0 comments on commit c978c70

Please sign in to comment.