Skip to content

Conversion

Utilities for converting and serializing between different data formats.

from prairielearn import ...

from_json

from_json(v: _JSONSerializedType | Any) -> Any

Converts a JSON serialized value (from to_json) back to its original type.

If v has the format {'_type': ..., '_value': ...} as would have been created using to_json(...), then it is replaced according to the following table:

JSON _type field Python type
complex complex
np_scalar numpy scalar defined by _concrete_type
ndarray non-complex ndarray
complex_ndarray complex ndarray
sympy sympy.Expr
sympy_matrix sympy.Matrix
dataframe pandas.DataFrame
dataframe_v2 pandas.DataFrame
networkx_graph corresponding networkx graph
missing input value v returned

If v encodes an ndarray and has the field '_dtype', this function recovers its dtype.

If v does not have the format {'_type': ..., '_value': ...}, then it is returned without change.

Returns:

Type Description
Any

The deserialized value

Raises:

Type Description
ValueError

If the JSON object is not in the expected format.

is_int_json_serializable

is_int_json_serializable(n: int) -> bool

Check if an integer is less than Number.MAX_SAFE_INTEGER and greater than Number.MIN_SAFE_INTEGER.

See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER.

Returns:

Type Description
bool

True if it can be serialized by JS code.

latex_from_2darray

latex_from_2darray(
    A: _NumericScalarType | NDArray[Any],
    presentation_type: str = "f",
    digits: int = 2,
) -> str

Convert a NumPy array to LaTeX.

This function assumes that A is one of these things:

  • a number (float or complex)
  • a 2D ndarray (float or complex)

If A is a scalar, the string is a single number, not wrapped in brackets.

It A is a numpy 2D array, it returns a string with the format:

\begin{bmatrix} ... & ... \\ ... & ... \end{bmatrix}

If presentation_type is 'sigfig', each number is formatted using the to_precision module to 'digits' significant figures.

Otherwise, each number is formatted as '{:.{digits}{presentation_type}}'.

Returns:

Type Description
str

The input formatted in LaTeX.

Raises:

Type Description
TypeError

If A is not a numpy array or scalar.

ValueError

If A is not a 2D numpy array.

Examples:

>>> latex_from_2darray(np.array([[1, 2], [3, 4]]))
\begin{bmatrix}  1 & 2\\  3 & 4\\\end{bmatrix}

numpy_to_matlab

numpy_to_matlab(
    np_object: _NumericScalarType | NDArray[Any],
    ndigits: int = 2,
    wtype: str = "f",
    style: Literal["legacy", "space", "comma"] = "legacy",
) -> str

Converts np_object to a MATLAB-formatted string in which each number has "ndigits" digits after the decimal and is formatted as "wtype" (e.g., 'f', 'g', etc.).

This function assumes that np_object is one of these things:

  • a number (float or complex)
  • a 2D ndarray (float or complex)

The style argument must be one of three values:

  • legacy: formats 1D arrays with commas and 2D arrays with spaces
  • comma: formats all arrays with commas
  • space: formats all arrays with spaces

Returns:

Type Description
str

A MATLAB-formatted string

numpy_to_matlab_sf

numpy_to_matlab_sf(
    A: _NumericScalarType | NDArray[Any],
    ndigits: int = 2,
    style: Literal["legacy", "comma", "space"] = "legacy",
) -> str

Convert A to a MATLAB-formatted string in which each number has ndigits significant digits.

This function assumes that A is one of these things:

  • a number (float or complex)
  • a 2D ndarray (float or complex)

The style argument must be one of three values:

  • legacy: formats 1d arrays with commas and 2d arrays with spaces
  • comma: formats all arrays with commas
  • space: formats all arrays with spaces

Returns:

Type Description
str

A as a MATLAB-formatted string

Examples:

>>> numpy_to_matlab_sf(np.array([[1 + 2j, 3 + 4j], [5 + 6j, 7 + 8j]]), style="space")
[1.0+2.0j 3.0+4.0j; 5.0+6.0j 7.0+8.0j]

string_fraction_to_number

string_fraction_to_number(
    a_sub: str | None,
    allow_fractions: bool = True,
    allow_complex: bool = True,
) -> (
    tuple[None, _PartialDataFormatErrors]
    | tuple[
        float64 | complex128, _PartialDataSubmittedAnswers
    ]
)

Parse a string containing a decimal number with support for answers expressing as a fraction.

On successful parsing, "data" will contain a 'submitted_answers' key that is the JSON encoded parsed answer.

If parsing failed, the first entry will be 'None' and the "data" entry will contain a 'format_errors' key.

Returns:

Type Description
tuple[None, _PartialDataFormatErrors] | tuple[float64 | complex128, _PartialDataSubmittedAnswers]

A tuple with the parsed value in the first entry and a dictionary with the intended value of "data" in the second entry.

Examples:

>>> string_fraction_to_number("1/2", allow_fractions=False, allow_complex=False)
(None, {"format_errors": "Fractional answers are not allowed in this input."})
>>> string_fraction_to_number("1/2", allow_fractions=True, allow_complex=False)
(0.5, {"submitted_answers": 0.5})

string_from_number_sigfig

string_from_number_sigfig(
    a: _NumericScalarType | str, digits: int = 2
) -> str

Convert a number to a string with the specified significant digits.

This function assumes that a is of type float or complex.

Returns:

Type Description
str

a as a string in which the number, or both the real and imaginary parts of the

number, have digits significant digits.

string_from_numpy

string_from_numpy(
    A: _NumericScalarType | NDArray[Any],
    language: _FormatLanguage = "python",
    presentation_type: str = "f",
    digits: int = 2,
) -> str

Return A as a string.

This function assumes that A is one of these things:

  • a number (float or complex)
  • a 1D ndarray (float or complex)
  • a 2D ndarray (float or complex)

If language is 'python' and A is a 2D ndarray, the string looks like this:

[[ ..., ... ], [ ..., ... ]]

If A is a 1D ndarray, the string looks like this:

[ ..., ..., ... ]

If language is 'matlab' and A is a 2D ndarray, the string looks like this:

[ ... ... ; ... ... ]

If A is a 1D ndarray, the string looks like this:

[ ..., ..., ... ]

If language is 'mathematica' and A is a 2D ndarray, the string looks like this:

{{ ..., ... },{ ..., ... }}

If A is a 1D ndarray, the string looks like this:

{ ..., ..., ... }

If language is 'r' and A is a 2D ndarray, the string looks like this:

matrix(c(., ., .), nrow=NUM_ROWS, ncol=NUM_COLS, byrow = TRUE)

If A is a 1D ndarray, the string looks like this:

c(., ., .)

If language is 'sympy' and A is a 2D ndarray, the string looks like this:

Matrix([[ ..., ... ], [ ..., ... ]])

If A is a 1D ndarray, the string looks like this:

Matrix([ ..., ..., ... ])

In either case, if A is not a 1D or 2D ndarray, the string is a single number, not wrapped in brackets.

If presentation_type is 'sigfig', each number is formatted using the to_precision module to 'digits' significant figures.

Otherwise, each number is formatted as '{:.{digits}{presentation_type}}'.

Returns:

Type Description
str

A formatted version of the NumPy array.

Raises:

Type Description
TypeError

If A is not a scalar or a numpy array.

Examples:

>>> string_from_numpy(np.zeros((2, 2)), language="mathematica")
"{{0.00, 0.00}, {0.00, 0.00}}"
>>> string_from_numpy(np.zeros((2, 2)), language="r")
"matrix(c(0.00, 0.00, 0.00, 0.00), nrow = 2, ncol = 2, byrow = TRUE)"
>>> string_from_numpy(np.zeros((2, 2)), language="sympy")
"Matrix([[0.00, 0.00], [0.00, 0.00]])"

string_partition_first_interval

string_partition_first_interval(
    s: str, left: str = "[", right: str = "]"
) -> tuple[str, str, str]

Split a string at the first occurrence of left and right delimiters.

string_partition_outer_interval

string_partition_outer_interval(
    s: str, left: str = "[", right: str = "]"
) -> tuple[str, str, str]

Split a string at the first left delimiter and last right delimiter.

string_to_2darray

string_to_2darray(
    s: str, *, allow_complex: bool = True
) -> tuple[NDArray[Any] | None, dict[str, str]]

Parse a string that is either a scalar or a 2D array in matlab or python format. Each number must be interpretable as type float or complex.

Returns:

Type Description
tuple[NDArray[Any] | None, dict[str, str]]

A 2-element tuple with the value, and any errors.

Raises:

Type Description
ValueError

If the input isn't the right type or is infinite.

string_to_integer

string_to_integer(s: str, base: int = 10) -> int | None

Parse a string that is an integer.

Returns:

Type Description
int | None

An integer or None on parse error.

string_to_number

string_to_number(
    s: str, *, allow_complex: bool = True
) -> float64 | complex128 | None

Parse a string that can be interpreted either as float or (optionally) complex.

Returns:

Type Description
float64 | complex128 | None

A number with type np.float64 or np.complex128, or None on parse error.

to_json

to_json(
    v: Any | _JSONPythonType,
    *,
    df_encoding_version: Literal[1, 2] = 1,
    np_encoding_version: Literal[1, 2] = 1,
) -> Any | _JSONSerializedType

Convert a value to a JSON serializable format.

If v has a standard type that cannot be json serialized, it is replaced with a {'_type': ..., '_value': ...} pair that can be json serialized.

This is a complete table of the mappings:

Type JSON _type field notes
complex scalar complex including numpy
non-complex ndarray ndarray assumes each element can be json serialized
complex ndarray complex_ndarray
sympy.Expr sympy any scalar SymPy expression
sympy.Matrix sympy_matrix
pandas.DataFrame dataframe df_encoding_version=1
pandas.DataFrame dataframe_v2 df_encoding_version=2
networkx graph type networkx_graph
numpy scalar np_scalar np_encoding_version=2
any v if v can be json serialized

Note

The 'dataframe_v2' encoding allows for missing and date time values whereas the 'dataframe' (default) does not. However, the 'dataframe' encoding allows for complex numbers while 'dataframe_v2' does not.

If np_encoding_version is set to 2, then numpy scalars serialize using '_type': 'np_scalar'.

If df_encoding_version is set to 2, then pandas DataFrames serialize using '_type': 'dataframe_v2'.

See from_json for details about the differences between encodings.

If v is an ndarray, this function preserves its dtype (by adding '_dtype' as a third field in the dictionary).

If v can be JSON serialized or does not have a standard type, then it is returned without change.

Returns:

Type Description
Any | _JSONSerializedType

The serialized value

Raises:

Type Description
ValueError

If np_encoding_version or df_encoding_version is invalid.