Skip to content

🔧 Fix CI installation failure for json2html caused by setuptools 78.0.1 update #7415

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

Merged
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: 0 additions & 1 deletion services/web/server/requirements/_base.in
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ faker # Only used in dev-mode for proof-of-concepts
gunicorn[setproctitle]
httpx
jinja_app_loader # email
json2html
jsondiff
msgpack
openpyxl # excel
Expand Down
2 changes: 0 additions & 2 deletions services/web/server/requirements/_base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -308,8 +308,6 @@ jinja2==3.1.2
# -c requirements/../../../../requirements/constraints.txt
# aiohttp-jinja2
# swagger-ui-py
json2html==1.3.0
# via -r requirements/_base.in
jsondiff==2.0.0
# via -r requirements/_base.in
jsonschema==3.2.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from aiohttp import MultipartReader, hdrs, web
from common_library.json_serialization import json_dumps
from json2html import json2html # type: ignore[import-untyped]
from servicelib.aiohttp import status
from servicelib.mimetype_constants import (
MIMETYPE_APPLICATION_JSON,
Expand All @@ -15,6 +14,7 @@
from ..login.storage import AsyncpgStorage, get_plugin_storage
from ..login.utils_email import AttachmentTuple, send_email_from_template, themed
from ..products import products_web
from ._utils import json2html

_logger = logging.getLogger(__name__)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
"""
This module provides functionality to convert JSON data into an HTML table format.
It is a snapshot of the `json2html` library to avoid compatibility issues with
specific versions of `setuptools`.

Classes:
- Json2Html: A class that provides methods to convert JSON data into HTML tables
or lists, with options for customization.

Functions:
----------
- Json2Html.convert: Converts JSON data into an HTML table or list format.
- Json2Html.column_headers_from_list_of_dicts: Determines column headers for a list of dictionaries.
- Json2Html.convert_json_node: Dispatches JSON input based on its type and processes it into HTML.
- Json2Html.convert_list: Converts a JSON list into an HTML table or list.
- Json2Html.convert_object: Converts a JSON object into an HTML table.

Attributes:
-----------
- json2html: An instance of the Json2Html class for direct use.

Notes:
------
- This module supports Python 2.7+ and Python 3.x.
- It uses `OrderedDict` to preserve the order of keys in JSON objects.
- The `html_escape` function is used to escape HTML characters in text.

License:
MIT License

Source:
-------
Snapshot of https://github.com/softvar/json2html/blob/0a223c7b3e5dce286811fb12bbab681e7212ebfe/json2html/jsonconv.py
JSON 2 HTML Converter
=====================

(c) Varun Malhotra 2013
Source Code: https://github.com/softvar/json2html


Contributors:
-------------
1. Michel Müller (@muellermichel), https://github.com/softvar/json2html/pull/2
2. Daniel Lekic (@lekic), https://github.com/softvar/json2html/pull/17

LICENSE: MIT
--------
"""

# pylint: skip-file
#
# NOTE: Snapshot of https://github.com/softvar/json2html/blob/0a223c7b3e5dce286811fb12bbab681e7212ebfe/json2html/jsonconv.py
# to avoid failure to install this module with `setuptools 78.0.1` due to
# deprecated feature that this library still uses
#


import sys

if sys.version_info[:2] < (2, 7):
import simplejson as json_parser
from ordereddict import OrderedDict
else:
import json as json_parser
from collections import OrderedDict

if sys.version_info[:2] < (3, 0):
from cgi import escape as html_escape

text = unicode
text_types = (unicode, str)
else:
from html import escape as html_escape

text = str
text_types = (str,)


class Json2Html:
def convert(
self,
json="",
table_attributes='border="1"',
clubbing=True,
encode=False,
escape=True,
):
"""
Convert JSON to HTML Table format
"""
# table attributes such as class, id, data-attr-*, etc.
# eg: table_attributes = 'class = "table table-bordered sortable"'
self.table_init_markup = "<table %s>" % table_attributes
self.clubbing = clubbing
self.escape = escape
json_input = None
if not json:
json_input = {}
elif type(json) in text_types:
try:
json_input = json_parser.loads(json, object_pairs_hook=OrderedDict)
except ValueError as e:
# so the string passed here is actually not a json string
# - let's analyze whether we want to pass on the error or use the string as-is as a text node
if "Expecting property name" in text(e):
# if this specific json loads error is raised, then the user probably actually wanted to pass json, but made a mistake
raise e
json_input = json
else:
json_input = json
converted = self.convert_json_node(json_input)
if encode:
return converted.encode("ascii", "xmlcharrefreplace")
return converted

def column_headers_from_list_of_dicts(self, json_input):
"""
This method is required to implement clubbing.
It tries to come up with column headers for your input
"""
if (
not json_input
or not hasattr(json_input, "__getitem__")
or not hasattr(json_input[0], "keys")
):
return None
column_headers = json_input[0].keys()
for entry in json_input:
if (
not hasattr(entry, "keys")
or not hasattr(entry, "__iter__")
or len(entry.keys()) != len(column_headers)
):
return None
for header in column_headers:
if header not in entry:
return None
return column_headers

def convert_json_node(self, json_input):
"""
Dispatch JSON input according to the outermost type and process it
to generate the super awesome HTML format.
We try to adhere to duck typing such that users can just pass all kinds
of funky objects to json2html that *behave* like dicts and lists and other
basic JSON types.
"""
if type(json_input) in text_types:
if self.escape:
return html_escape(text(json_input))
else:
return text(json_input)
if hasattr(json_input, "items"):
return self.convert_object(json_input)
if hasattr(json_input, "__iter__") and hasattr(json_input, "__getitem__"):
return self.convert_list(json_input)
return text(json_input)

def convert_list(self, list_input):
"""
Iterate over the JSON list and process it
to generate either an HTML table or a HTML list, depending on what's inside.
If suppose some key has array of objects and all the keys are same,
instead of creating a new row for each such entry,
club such values, thus it makes more sense and more readable table.

@example:
jsonObject = {
"sampleData": [
{"a":1, "b":2, "c":3},
{"a":5, "b":6, "c":7}
]
}
OUTPUT:
_____________________________
| | | | |
| | a | c | b |
| sampleData |---|---|---|
| | 1 | 3 | 2 |
| | 5 | 7 | 6 |
-----------------------------

@contributed by: @muellermichel
"""
if not list_input:
return ""
converted_output = ""
column_headers = None
if self.clubbing:
column_headers = self.column_headers_from_list_of_dicts(list_input)
if column_headers is not None:
converted_output += self.table_init_markup
converted_output += "<thead>"
converted_output += (
"<tr><th>" + "</th><th>".join(column_headers) + "</th></tr>"
)
converted_output += "</thead>"
converted_output += "<tbody>"
for list_entry in list_input:
converted_output += "<tr><td>"
converted_output += "</td><td>".join(
[
self.convert_json_node(list_entry[column_header])
for column_header in column_headers
]
)
converted_output += "</td></tr>"
converted_output += "</tbody>"
converted_output += "</table>"
return converted_output

# so you don't want or need clubbing eh? This makes @muellermichel very sad... ;(
# alright, let's fall back to a basic list here...
converted_output = "<ul><li>"
converted_output += "</li><li>".join(
[self.convert_json_node(child) for child in list_input]
)
converted_output += "</li></ul>"
return converted_output

def convert_object(self, json_input):
"""
Iterate over the JSON object and process it
to generate the super awesome HTML Table format
"""
if not json_input:
return "" # avoid empty tables
converted_output = self.table_init_markup + "<tr>"
converted_output += "</tr><tr>".join(
[
"<th>%s</th><td>%s</td>"
% (self.convert_json_node(k), self.convert_json_node(v))
for k, v in json_input.items()
]
)
converted_output += "</tr></table>"
return converted_output


json2html = Json2Html()
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
""" publications management subsystem
"""publications management subsystem"""

"""
import logging

from aiohttp import web
Expand All @@ -9,22 +8,22 @@

from ..email.plugin import setup_email
from ..products.plugin import setup_products
from . import _handlers
from . import _rest

logger = logging.getLogger(__name__)
_logger = logging.getLogger(__name__)


@app_module_setup(
__name__,
ModuleCategory.ADDON,
depends=["simcore_service_webserver.rest"],
settings_name="WEBSERVER_PUBLICATIONS",
logger=logger,
logger=_logger,
)
def setup_publications(app: web.Application):
assert app[APP_SETTINGS_KEY].WEBSERVER_PUBLICATIONS # nosec

setup_email(app)
setup_products(app)

app.router.add_routes(_handlers.routes)
app.router.add_routes(_rest.routes)
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from aiohttp import web
from aiohttp.test_utils import make_mocked_request
from faker import Faker
from json2html import json2html
from pytest_mock import MockerFixture
from pytest_simcore.helpers.typing_env import EnvVarsDict
from simcore_service_webserver.application_settings import setup_settings
Expand All @@ -23,6 +22,7 @@
get_template_path,
send_email_from_template,
)
from simcore_service_webserver.publications._utils import json2html
from simcore_service_webserver.statics._constants import FRONTEND_APPS_AVAILABLE


Expand Down
Loading