This commit is contained in:
Bellybutn278 2021-04-01 01:53:42 +00:00 committed by GitHub
commit b3ec028479
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 1781 additions and 1 deletions

986
3.x Normal file
View File

@ -0,0 +1,986 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
try
{
// executing a failing JSON Patch operation
json value = R"({
"best_biscuit": {
"name": "Oreo"
}
})"_json;
json patch = R"([{
"op": "test",
"path": "/best_biscuit/name",
"value": "Choco Leibniz"
}])"_json;
value.patch(patch);
}
catch (json::other_error& e)
{
// output exception information
std::cout << "message: " << e.what() << '\n'
<< "exception id: " << e.id << std::endl;
}
}using number_float_t = NumberFloatType;define MergePatch(Target, Patch):
if Patch is an Object:
if Target is not an Object:
Target = {} // Ignore the contents and set it to an empty Object
for each Name/Value pair in Patch:
if Value is null:
if Name exists in Target:
remove the Name/Value pair from Target
else:
Target[Name] = MergePatch(Target[Name], Value)
return Target
else:
return Patch{
"compiler": {
"c++": "201103",
"family": "clang",
"version": "12.0.0 (clang-1200.0.32.28)"
},
"copyright": "(C) 2013-2021 Niels Lohmann",
"name": "JSON for Modern C++",
"platform": "apple",
"url": "https://github.com/nlohmann/json",
"version": {
"major": 3,
"minor": 9,
"patch": 1,
"string": "3.9.1"
}
}#include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// call meta()
std::cout << std::setw(4) << json::meta() << '\n';
}static basic_json meta();size_type max_size() const noexcept;key: one, value: 1
key: two, value: 2
key: 0, value: 1
key: 1, value: 2
key: 2, value: 4
key: 3, value: 8
key: 4, value: 16for (auto& [key, val] : j_object.items())
{
std::cout << "key: " << key << ", value:" << val << '\n';
}for (auto& el : j_object.items())
{
std::cout << "key: " << el.key() << ", value:" << el.value() << '\n';
}for (auto it : j_object)
{
// "it" is of type json::reference and has no key() member
std::cout << "value: " << it << '\n';
}for (auto it = j_object.begin(); it != j_object.end(); ++it)
{
std::cout << "key: " << it.key() << ", value:" << it.value() << '\n';
}iteration_proxy<iterator> items() noexcept;
iteration_proxy<const_iterator> items() const noexcept;true
true
true
true
true
false
false
true
true#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// create JSON values
json j_null;
json j_boolean = true;
json j_number_integer = 17;
json j_number_float = 23.42;
json j_number_unsigned_integer = 12345678987654321u;
json j_object = {{"one", 1}, {"two", 2}};
json j_array = {1, 2, 4, 8, 16};
json j_string = "Hello, world";
json j_binary = json::binary({1, 2, 3});
// call is_primitive()
std::cout << std::boolalpha;
std::cout << j_null.is_primitive() << '\n';
std::cout << j_boolean.is_primitive() << '\n';
std::cout << j_number_integer.is_primitive() << '\n';
std::cout << j_number_unsigned_integer.is_primitive() << '\n';
std::cout << j_number_float.is_primitive() << '\n';
std::cout << j_object.is_primitive() << '\n';
std::cout << j_array.is_primitive() << '\n';
std::cout << j_string.is_primitive() << '\n';
std::cout << j_binary.is_primitive() << '\n';
}constexpr bool is_primitive() const noexcept
{
return is_null() || is_string() || is_boolean() || is_number() || is_binary();
}false
false
false
false
false
false
false
false
true#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
try
{
// calling iterator::key() on non-object iterator
json j = "string";
json::iterator it = j.begin();
auto k = it.key();
}
catch (json::invalid_iterator& e)
{
// output exception information
std::cout << "message: " << e.what() << '\n'
<< "exception id: " << e.id << std::endl;
}
}static allocator_type get_allocator();ValueType ret;
JSONSerializer<ValueType>::from_json(*this, ret);
return ret;// (1)
template<typename InputType>
static basic_json from_cbor(InputType&& i,
const bool strict = true,
const bool allow_exceptions = true,
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error);
// (2)
template<typename IteratorType>
static basic_json from_cbor(IteratorType first, IteratorType last,
const bool strict = true,
const bool allow_exceptions = true,
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error);// (1)
template<typename InputType>
static basic_json from_bson(InputType&& i,
const bool strict = true,
const bool allow_exceptions = true);
// (2)
template<typename IteratorType>
static basic_json from_bson(IteratorType first, IteratorType last,
const bool strict = true,
const bool allow_exceptions = true);basic_json flatten() const;#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// create a JSON object
json j_object = {{"one", 1}, {"two", 2}};
// call find
auto it_two = j_object.find("two");
auto it_three = j_object.find("three");
// print values
std::cout << std::boolalpha;
std::cout << "\"two\" was found: " << (it_two != j_object.end()) << '\n';
std::cout << "value at key \"two\": " << *it_two << '\n';
std::cout << "\"three\" was found: " << (it_three != j_object.end()) << '\n';
}"two" was found: true
value at key "two": 2
"three" was found: falseenum class error_handler_t {
strict,
replace,
ignore
};5iterator end() noexcept;
const_iterator end() const noexcept;[1,2,3,4,5]
null
[1,2,3,4,5,6]
["first",["second","second","second"]]#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// create JSON values
json array = {1, 2, 3, 4, 5};
json null;
// print values
std::cout << array << '\n';
std::cout << null << '\n';
// add values
array.emplace_back(6);
null.emplace_back("first");
null.emplace_back(3, "second");
// print values
std::cout << array << '\n';
std::cout << null << '\n';
}j_object contains 'key': true
j_object contains 'another': false
j_array contains 'key': false#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// create some JSON values
json j_object = R"( {"key": "value"} )"_json;
json j_array = R"( [1, 2, 3] )"_json;
// call contains
std::cout << std::boolalpha <<
"j_object contains 'key': " << j_object.contains("key") << '\n' <<
"j_object contains 'another': " << j_object.contains("another") << '\n' <<
"j_array contains 'key': " << j_array.contains("key") << std::endl;
}const_iterator cbegin() const noexcept;using boolean_t = BooleanType;1
"foo"
[1,2]
2
[json.exception.parse_error.109] parse error: array index 'one' is not a number
[json.exception.out_of_range.401] array index 4 is out of range
[json.exception.out_of_range.402] array index '-' (2) is out of range
[json.exception.out_of_range.403] key 'foo' not found
[json.exception.out_of_range.404] unresolved reference token 'foo'#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// create a JSON value
const json j =
{
{"number", 1}, {"string", "foo"}, {"array", {1, 2}}
};
// read-only access
// output element with JSON pointer "/number"
std::cout << j.at("/number"_json_pointer) << '\n';
// output element with JSON pointer "/string"
std::cout << j.at("/string"_json_pointer) << '\n';
// output element with JSON pointer "/array"
std::cout << j.at("/array"_json_pointer) << '\n';
// output element with JSON pointer "/array/1"
std::cout << j.at("/array/1"_json_pointer) << '\n';
// out_of_range.109
try
{
// try to use an array index that is not a number
json::const_reference ref = j.at("/array/one"_json_pointer);
}
catch (json::parse_error& e)
{
std::cout << e.what() << '\n';
}
// out_of_range.401
try
{
// try to use a an invalid array index
json::const_reference ref = j.at("/array/4"_json_pointer);
}
catch (json::out_of_range& e)
{
std::cout << e.what() << '\n';
}
// out_of_range.402
try
{
// try to use the array index '-'
json::const_reference ref = j.at("/array/-"_json_pointer);
}
catch (json::out_of_range& e)
{
std::cout << e.what() << '\n';
}
// out_of_range.403
try
{
// try to use a JSON pointer to an nonexistent object key
json::const_reference ref = j.at("/foo"_json_pointer);
}
catch (json::out_of_range& e)
{
std::cout << e.what() << '\n';
}
// out_of_range.404
try
{
// try to use a JSON pointer that cannot be resolved
json::const_reference ref = j.at("/number/foo"_json_pointer);
}
catch (json::out_of_range& e)
{
std::cout << e.what() << '\n';
}
}1
"foo"
[1,2]
2
"bar"
[1,21]
[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'
[json.exception.parse_error.109] parse error: array index 'one' is not a number
[json.exception.out_of_range.401] array index 4 is out of range
[json.exception.out_of_range.402] array index '-' (2) is out of range
[json.exception.out_of_range.403] key 'foo' not found
[json.exception.out_of_range.404] unresolved reference token 'foo'#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// create a JSON value
json j =
{
{"number", 1}, {"string", "foo"}, {"array", {1, 2}}
};
// read-only access
// output element with JSON pointer "/number"
std::cout << j.at("/number"_json_pointer) << '\n';
// output element with JSON pointer "/string"
std::cout << j.at("/string"_json_pointer) << '\n';
// output element with JSON pointer "/array"
std::cout << j.at("/array"_json_pointer) << '\n';
// output element with JSON pointer "/array/1"
std::cout << j.at("/array/1"_json_pointer) << '\n';
// writing access
// change the string
j.at("/string"_json_pointer) = "bar";
// output the changed string
std::cout << j["string"] << '\n';
// change an array element
j.at("/array/1"_json_pointer) = 21;
// output the changed array
std::cout << j["array"] << '\n';
// out_of_range.106
try
{
// try to use an array index with leading '0'
json::reference ref = j.at("/array/01"_json_pointer);
}
catch (json::parse_error& e)
{
std::cout << e.what() << '\n';
}
// out_of_range.109
try
{
// try to use an array index that is not a number
json::reference ref = j.at("/array/one"_json_pointer);
}
catch (json::parse_error& e)
{
std::cout << e.what() << '\n';
}
// out_of_range.401
try
{
// try to use a an invalid array index
json::reference ref = j.at("/array/4"_json_pointer);
}
catch (json::out_of_range& e)
{
std::cout << e.what() << '\n';
}
// out_of_range.402
try
{
// try to use the array index '-'
json::reference ref = j.at("/array/-"_json_pointer);
}
catch (json::out_of_range& e)
{
std::cout << e.what() << '\n';
}
// out_of_range.403
try
{
// try to use a JSON pointer to an nonexistent object key
json::const_reference ref = j.at("/foo"_json_pointer);
}
catch (json::out_of_range& e)
{
std::cout << e.what() << '\n';
}
// out_of_range.404
try
{
// try to use a JSON pointer that cannot be resolved
json::reference ref = j.at("/number/foo"_json_pointer);
}
catch (json::out_of_range& e)
{
std::cout << e.what() << '\n';
}
}"il brutto"
[json.exception.type_error.304] cannot use at() with string
out of range"third"
["first","second","third","fourth"]
[json.exception.type_error.304] cannot use at() with string
[json.exception.out_of_range.401] array index 5 is out of rangeusing array_t = ArrayType<basic_json, AllocatorType<basic_json>>;#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// create JSON arrays
json j_no_init_list = json::array();
json j_empty_init_list = json::array({});
json j_nonempty_init_list = json::array({1, 2, 3, 4});
json j_list_of_pairs = json::array({ {"one", 1}, {"two", 2} });
// serialize the JSON arrays
std::cout << j_no_init_list << '\n';
std::cout << j_empty_init_list << '\n';
std::cout << j_nonempty_init_list << '\n';
std::cout << j_list_of_pairs << '\n';
}true false#include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// a valid JSON text
auto valid_text = R"(
{
"numbers": [1, 2, 3]
}
)";
// an invalid JSON text
auto invalid_text = R"(
{
"strings": ["extra", "comma", ]
}
)";
std::cout << std::boolalpha
<< json::accept(valid_text) << ' '
<< json::accept(invalid_text) << '\n';
}// (1)
template<typename InputType>
static bool accept(InputType&& i,
const bool ignore_comments = false);
// (2)
template<typename IteratorType>
static bool accept(IteratorType first, IteratorType last,
const bool ignore_comments = false);brew tap nlohmann/json
brew install nlohmann-json --HEADbrew tap nlohmann/json
brew install nlohmann-json#include <nlohmann/json.hpp>
#include <iostream>
using json = nlohmann::json;
int main()
{
std::cout << json::meta() << std::endl;
}# thirdparty/CMakeLists.txt
...
if(FOO_USE_EXTERNAL_JSON)
find_package(nlohmann_json 3.2.0 REQUIRED)
else()
set(JSON_BuildTests OFF CACHE INTERNAL "")
add_subdirectory(nlohmann_json)
endif()
...# Top level CMakeLists.txt
project(FOO)
...
option(FOO_USE_EXTERNAL_JSON "Use an external JSON library" OFF)
...
add_subdirectory(thirdparty)
...
add_library(foo ...)
...
# Note that the namespaced target will always be available regardless of the
# import method
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)include(FetchContent)
FetchContent_Declare(json
GIT_REPOSITORY https://github.com/nlohmann/json
GIT_TAG v3.7.3)
FetchContent_GetProperties(json)
if(NOT json_POPULATED)
FetchContent_Populate(json)
add_subdirectory(${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL)
endif()
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)# Typically you don't care so much for a third party library's tests to be
# run from your own project's code.
set(JSON_BuildTests OFF CACHE INTERNAL "")
# If you only include this third party in PRIVATE source files, you do not
# need to install it when your main project gets installed.
# set(JSON_Install OFF CACHE INTERNAL "")
# Don't use include(nlohmann_json/CMakeLists.txt) since that carries with it
# unintended consequences that will break the build. It's generally
# discouraged (although not necessarily well documented as such) to use
# include(...) for pulling in other CMake projects anyways.
add_subdirectory(nlohmann_json)
...
add_library(foo ...)
...
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)# CMakeLists.txt
find_package(nlohmann_json 3.2.0 REQUIRED)
...
add_library(foo ...)
...
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)#include <nlohmann/json.hpp>
// for convenience
using json = nlohmann::json;std::vector<
basic_json, // value_type
std::allocator<basic_json> // allocator_type
>template<
template<typename U, typename V, typename... Args> class ObjectType = std::map,
template<typename U, typename... Args> class ArrayType = std::vector,
class StringType = std::string,
class BooleanType = bool,
class NumberIntegerType = std::int64_t,
class NumberUnsignedType = std::uint64_t,
class NumberFloatType = double,
template<typename U> class AllocatorType = std::allocator,
template<typename T, typename SFINAE = void> class JSONSerializer = adl_serializer,
class BinaryType = std::vector<std::uint8_t>
>
class basic_json;json j = "Hello, world!";
auto s = j.get<std::string>();json j = "Hello, world!";
std::string s = j;// example enum type declaration
enum TaskState {
TS_STOPPED,
TS_RUNNING,
TS_COMPLETED,
TS_INVALID=-1,
};
// map TaskState values to JSON as strings
NLOHMANN_JSON_SERIALIZE_ENUM( TaskState, {
{TS_INVALID, nullptr},
{TS_STOPPED, "stopped"},
{TS_RUNNING, "running"},
{TS_COMPLETED, "completed"},
})// called when null is parsed
bool null();
// called when a boolean is parsed; value is passed
bool boolean(bool val);
// called when a signed or unsigned integer number is parsed; value is passed
bool number_integer(number_integer_t val);
bool number_unsigned(number_unsigned_t val);
// called when a floating-point number is parsed; value and original string is passed
bool number_float(number_float_t val, const string_t& s);
// called when a string is parsed; value is passed and can be safely moved away
bool string(string_t& val);
// called when a binary value is parsed; value is passed and can be safely moved away
bool binary(binary& val);
// called when an object or array begins or ends, resp. The number of elements is passed (or -1 if not known)
bool start_object(std::size_t elements);
bool end_object();
bool start_array(std::size_t elements);
bool end_array();
// called when an object key is parsed; value is passed and can be safely moved away
bool key(string_t& val);
// called when a parse error occurs; byte position, the last token, and an exception is passed
bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex);#include <iostream>
#include "json.hpp"
using json = nlohmann::json;
class sax_no_exception : public nlohmann::detail::json_sax_dom_parser<json>
{
public:
sax_no_exception(json& j)
: nlohmann::detail::json_sax_dom_parser<json>(j, false)
{}
bool parse_error(std::size_t position,
const std::string& last_token,
const json::exception& ex)
{
std::cerr << "parse error at input byte " << position << "\n"
<< ex.what() << "\n"
<< "last read: \"" << last_token << "\""
<< std::endl;
return false;
}
};
int main()
{
std::string myinput = "[1,2,3,]";
json result;
sax_no_exception sax(result);
bool parse_result = json::sax_parse(myinput, &sax);
if (!parse_result)
{
std::cerr << "parsing unsuccessful!" << std::endl;
}
std::cout << "parsed value: " << result << std::endl;
}parse error at input byte 8
[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal
last read: "3,]"
parsing unsuccessful!
parsed value: [1,2,3]bool parse_error(std::size_t position,
const std::string& last_token,
const json::exception& ex);if (!json::accept(my_input))
{
std::cerr << "parse error" << std::endl;
}json j = json::parse(my_input, nullptr, false);
if (j.is_discarded())
{
std::cerr << "parse error" << std::endl;
}json j;
try
{
j = json::parse(my_input);
}
catch (json::parse_error& ex)
{
std::cerr << "parse error at byte " << ex.byte << std::endl;
}{
"one": 1,
"two": 2,
"three": 3
}#include <iostream>
#include <nlohmann/json.hpp>
using ordered_json = nlohmann::ordered_json;
int main()
{
ordered_json j;
j["one"] = 1;
j["two"] = 2;
j["three"] = 3;
std::cout << j.dump(2) << '\n';
}{
"one": 1,
"three": 3,
"two": 2
}#include <iostream>
#include "json.hpp"
using json = nlohmann::json;
int main()
{
json j;
j["one"] = 1;
j["two"] = 2;
j["three"] = 3;
std::cout << j.dump(2) << '\n';
}{
"author": {
"givenName": "Heather Jones"
},
"content": "This will be unchanged",
"phoneNumber": "+01-123-456-7890",
"tags": [
"example"
],
"title": "Hello!"#include <iostream>
#include <nlohmann/json.hpp>
#include <iomanip> // for std::setw
using json = nlohmann::json;
int main()
{
// the original document
json document = R"({
"title": "Goodbye!",
"author": {
"givenName": "John",
"familyName": "Doe"
},
"tags": [
"example",
"sample"
],
"content": "This will be unchanged"
})"_json;
// the patch
json patch = R"({
"title": "Hello!",
"phoneNumber": "+01-123-456-7890",
"author": {
"familyName": null
},
"tags": [
"example"
]
})"_json;
// apply the patch
document.merge_patch(patch);
// output original and patched document
std::cout << std::setw(4) << document << std::endl;
}[
{
"op": "replace",
"path": "/baz",
"value": "boo"
},
{
"op": "remove",
"path": "/foo"
},
{
"op": "add",
"path": "/hello",
"value": [
"world"
]
}
]
{
"baz": "boo",
"hello": [
"world"
]
}#include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// the source document
json source = R"(
{
"baz": "qux",
"foo": "bar"
}
)"_json;
// the target document
json target = R"(
{
"baz": "boo",
"hello": [
"world"
]
}
)"_json;
// create the patch
json patch = json::diff(source, target);
// roundtrip
json patched_source = source.patch(patch);
// output patch and roundtrip result
std::cout << std::setw(4) << patch << "\n\n"
<< std::setw(4) << patched_source << std::endl;
}// a JSON value
json j_original = R"({
"baz": ["one", "two", "three"],
"foo": "bar"
})"_json;
// access members with a JSON pointer (RFC 6901)
j_original["/baz/1"_json_pointer];
// "two"#include <iostream>
#define JSON_TRY_USER if(true)
#define JSON_CATCH_USER(exception) if(false)
#define JSON_THROW_USER(exception) \
{std::clog << "Error in " << __FILE__ << ":" << __LINE__ \
<< " (function " << __FUNCTION__ << ") - " \
<< (exception).what() << std::endl; \
std::abort();}
#include <nlohmann/json.hpp>Python Examples
Basics Strings Lists Dictionary Files Logging sqlite3 OpenCV Pillow Pandas Numpy PyMongo
Python *args
Contents
Example: Python *args
args in *args is just a name
args in *args is a tuple
*args with other parameters
*args with **kwargs
Summary
Python *args parameter in a function definition allows the function to accept multiple arguments without knowing how many arguments. In other words it lets the function accept a variable number of arguments.
Datatype of args is tuple. Inside the function, you can access all the arguments passed as *args using a for loop. Or, you can use index to access the individual arguments. We will verify the datatype of args in an example below.
In this tutorial, we will learn how to use *args in function definition with the help of example programs.
Example: Python *args
We already know that *args parameter lets the function accept any number of arguments. In this example, we will write an addition function that can accept any number of arguments and returns the addition of all these arguments.
Python Program
def addition(*args):
result = 0
for arg in args:
result += arg
return result
if __name__ == "__main__":
sum = addition(2, 5, 1, 9)
print(sum)
sum = addition(5)
print(sum)
sum = addition(5, 4, 0.5, 1.5, 9, 2)
print(sum)
Run
Output
17
5
22.0
args in *args is just a name
args is just the parameter name. You can provide any name, instead of args, just like any other parameter in function definition. Asterisk symbol (*) before the parameter name is the important part. It tells Python that this parameter is going to accept a variable number of arguments. Because of its functionality, the asterisk symbol is called unpacking operator.
We shall use the same example above, and use a different name for args, say numbers.
Python Program
def addition(*numbers):
result = 0
for number in numbers:
result += number
return result
if __name__ == "__main__":
sum = addition(2, 5, 1, 9)
print(sum)
Run
Output
17
args in *args is a tuple
Based on the previous examples, it is already established that we can use args as an iterator. Well! if we could use an iterator on args, then what could be the datatype of args. Only one way to find out. Use Python type() builtin function.
Python Program
def addition(*numbers):
print(type(numbers))
if __name__ == "__main__":
addition(2, 5, 1, 9)
Run
Output
<class 'tuple'>
Loud and clear as it says. The datatype of args parameter is tuple. So, we get a tuple when we use unpacking operator with parameter (*args) to accept variable number of arguments.
Since tuple is immutable (at least shallow level), it is logical to keep the datatype of args as tuple instead of list.
*args with other parameters
*args is just another parameter that can accept multiple number of positional arguments. You can use *args with other parameters in your function definition.
In the following example, we will create a function that will accept arguments for some specified parameters, and then any number of arguments using *args.
Python Program
def calculator(operation, *numbers):
if operation == "add":
result = 0
for num in numbers:
result += num
return result
if operation == "product":
result = 1
for num in numbers:
result *= num
return result
if __name__ == "__main__":
x = calculator("add", 2, 5, 1, 9)
print(x)
x = calculator("product", 3, 5, 2)
print(x)
Run
Output
17
30
*args with **kwargs
While *args can accept any number of positional arguments, Python **kwargs can accept any number of named arguments.
You can use *args and **kwargs in a function definition to accept both positional arguments and named arguments, whose count is unknown.
In the following example, we will define a function with both *args and **kwargs.
Python Program
def myFunction(*args, **kwargs):
print(args)
print(kwargs)
if __name__ == "__main__":
myFunction("hello", "mars", a = 24, b = 87, c = 3, d = 46)
Run
Output
('hello', 'mars')
{'a': 24, 'b': 87, 'c': 3, 'd': 46}
Just to remind, the datatype of args is tuple, and the datatype of kwargs is dictionary.
Summary
In this tutorial of Python Examples, we learned how to use *args to write functions that can accept any number of arguments.
Sitemap Privacy Policy Terms of Use Contact Us
permalinkPin copied text snippets to stop them expiring after 1 hour
}

795
README.md
View File

@ -1,4 +1,797 @@
[![JSON for Modern C++](https://raw.githubusercontent.com/nlohmann/json/master/doc/json.gif)](https://github.com/nlohmann/json/releases)
https://runkit.com/chaostheorx/es6-and-es7-supportx
[JSON Data Set Sample
The JSON output from different Server APIs can range from simple to highly nested and complex. The examples on this page attempt to illustrate how the JSON Data Set treats specific formats, and gives examples of the different constructor options that allow the user to tweak its behavior. See our JSON Primer for more information.
Example 1 - JSON Array with simple data types as elements.
Example 2 - JSON Array with objects as elements
Example 3 - JSON Object
Example 4 - The "path" constructor option.
Example 5 - The "path" constructor option and JSON Array with objects as elements.
Example 6 - The "subPaths" constructor option with a single path.
Example 7 - The "subPaths" constructor option with multiple paths.
Example 8 - "path" constructor option example.
Example 9 - Multiple matches for a single sub path.
Example 10 - Multiple matches for multiple sub paths.
Example 11 - The JSON Nested Data Set.
Example 12 - Sorting with the JSON Nested Data Set
Be sure to check out the "What's Not Supported" section.
Example 1
If the JSON data describes an array, and each element of that array is of a basic type (number, string, boolean, or null):
[ 100, 500, 300, 200, 400 ]
the JSON DataSet will create a row for each element in the JSON array, and store its value in a column named "column0".
var dsExample1 = new Spry.Data.JSONDataSet("../../data/json/array-01.js");
...
<div class="liveSample" spry:region="dsExample1">
Values from array: <span spry:repeatchildren="dsExample1">{column0} </span>
</div>
Here is a live example:
Values from array: 100 500 300 200 400
Example 2
If the JSON data describes an array, and each element of that array is an object:
[
{
color: "red",
value: "#f00"
},
{
color: "green",
value: "#0f0"
},
{
color: "blue",
value: "#00f"
},
{
color: "cyan",
value: "#0ff"
},
{
color: "magenta",
value: "#f0f"
},
{
color: "yellow",
value: "#ff0"
},
{
color: "black",
value: "#000"
}
]
the JSON Data Set will create a row for each object in the array, and each property on the object will become a column.
var dsExample2 = new Spry.Data.JSONDataSet("../../data/json/array-02.js");
...
<div class="liveSample" spry:region="dsExample2">
Values from array: <span spry:repeatchildren="dsExample2">{color}({value}) </span>
</div>
Here's a live example:
Values from array: red(#f00) green(#0f0) blue(#00f) cyan(#0ff) magenta(#f0f) yellow(#ff0) black(#000)
Example 3
If the JSON data describes an object:
{
color: "red",
value: "#f00"
}
the JSON Data Set will create a single row for the object, and each property on the object will become a column. The data set will only contain one row of data.
var dsExample3 = new Spry.Data.JSONDataSet("../../data/json/array-03.js");
...
<div class="liveSample" spry:region="dsExample3">
Values from object: {color}({value})
</div>
Here is a live example:
Values from object: red(#f00)
Example 4
The objects returned from most Server APIs are highly nested:
{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
}
If the data you want to extract out is not at the top-level of the JSON object, you can tell the JSON data set where to find it by using the "path" constructor option. In this example, we want to extract out all of the "batter" data:
var dsExample4 = new Spry.Data.JSONDataSet("../../data/json/object-02.js", { path: "batters.batter" });
...
<div class="liveSample" spry:region="dsExample4">
<p>Batters:</p>
<ul>
<li spry:repeat="dsExample4">{type} ({id})</li>
</ul>
</div>
The path is simply the set of properties used to traverse the object's structure, separated by dots. Here's a live example:
Batters:
Regular (1001)
Chocolate (1002)
Blueberry (1003)
Devil's Food (1004)
Example 5
In the case where you have an array of highly nested objects:
[
{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
},
{
"id": "0002",
"type": "donut",
"name": "Raised",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
},
{
"id": "0003",
"type": "donut",
"name": "Old Fashioned",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
}
]
the JSON data set uses the "path" constructor option to extract the matching data out from each object in the array. Each match then becomes a row in the data set. In this example, we want the data set to select all of the "batter" objects and flatten them into rows:
var dsExample5 = new Spry.Data.JSONDataSet("../../data/json/array-03.js", { path: "batters.batter" });
...
<div class="liveSample" spry:region="dsExample5">
<p>Batters:</p>
<ul>
<li spry:repeat="dsExample5">{type} ({id})</li>
</ul>
</div>
Here's a live example:
Batters:
Regular (1001)
Chocolate (1002)
Blueberry (1003)
Devil's Food (1004)
Regular (1001)
Regular (1001)
Chocolate (1002)
Example 6
Some JSON formats use nested structures to simply group data together. An example of this would be the "image" and "thumbnail" properties in the following example:
{
"id": "0001",
"type": "donut",
"name": "Cake",
"image":
{
"url": "images/0001.jpg",
"width": 200,
"height": 200
},
"thumbnail":
{
"url": "images/thumbnails/0001.jpg",
"width": 32,
"height": 32
}
}
It is sometimes desirable to flatten these structures so they are also available as columns in the data set. You can use the "subPaths" constructor option to tell the JSON Data Set to include these nested structures when it flattens the top-level JSON object, or the data selected by the "path" constructor option. In this particular example, because we have not specified a "path" constructor option, the JSON data set will attempt to flatten the top-level object. Since we want to also include the data from the "image" nested structure, we specify the path to the data which is simply "image".
var dsExample6 = new Spry.Data.JSONDataSet("../../data/json/object-03.js", { subPaths: "image" });
...
<div class="liveSample" spry:region="dsExample6">
<table class="dataTable">
<tr>
<th>id</th>
<th>type</th>
<th>name</th>
<th>image.width</th>
<th>image.height</th>
<th>image.url</th>
</tr>
<tr>
<td>{id}</td>
<td>{type}</td>
<td>{name}</td>
<td>{image.width}</td>
<td>{image.height}</td>
<td>{image.url}</td>
</tr>
</table>
</div>
The properties within the nested "image" structure are now accessible from within the data set. Notice that the names of the columns are all prefixed by "image.". Here's a live example:
id type name image.width image.height image.url
0001 donut Cake 200 200 images/0001.jpg
Example 7
You can specify multiple paths in the "subPaths" constructor option. So if you wanted to include both "image" and "thumbnail" in the flattening process, you simply pass an array of strings:
var dsExample7 = new Spry.Data.JSONDataSet("../../data/json/object-03.js", { subPaths: [ "image", "thumbnail" ] });
...
<div class="liveSample" spry:region="dsExample7">
<table class="dataTable">
<tr>
<th>id</th>
<th>type</th>
<th>name</th>
<th>image.width</th>
<th>image.height</th>
<th>image.url</th>
<th>thumbnail.width</th>
<th>thumbnail.height</th>
<th>thumbnail.url</th>
</tr>
<tr>
<td>{id}</td>
<td>{type}</td>
<td>{name}</td>
<td>{image.width}</td>
<td>{image.height}</td>
<td>{image.url}</td>
<td>{thumbnail.width}</td>
<td>{thumbnail.height}</td>
<td>{thumbnail.url}</td>
</tr>
</table>
</div>
Here is a live example:
id type name image.width image.height image.url thumbnail.width thumbnail.height thumbnail.url
0001 donut Cake 200 200 images/0001.jpg 32 32 images/thumbnails/0001.jpg
Example 8
This example shows the use of the "path" constructor option to extract out the data items. This is nothing different from some of the previous examples, but we will build on this in the next example. An abbreviated version of the JSON data is included here for reference. You can see the full JSON data used by this example here.
{
"items":
{
"item":
[
{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
},
...
]
}
}
In this example, we are simply going to list the types of items in our JSON object. We are going to use the "path" constructor option to select out all of the "item" objects, and then display the info we get in a table:
var dsExample8 = new Spry.Data.JSONDataSet("../../data/json/donuts.js", { path: "items.item" });
...
<div class="liveSample" spry:region="dsExample8">
<table class="dataTable">
<tr>
<th spry:sort="id">id</th>
<th spry:sort="type">type</th>
<th spry:sort="name">name</th>
</tr>
<tr spry:repeat="dsExample8">
<td>{id}</td>
<td>{type}</td>
<td>{name}</td>
</tr>
</table>
</div>
Using the path "items.item" will result in a data set that has the following columns defined for each row:
ds_RowID id type name ppu
Here is a live example:
id type name
0001 donut Cake
0002 donut Raised
0003 donut Old Fashioned
0004 bar Bar
0005 twist Twist
0006 filled Filled
Example 9
This example builds on Example 8 to show what happens when you select a set of repeating structures with the "subPaths" constructor option.
{
"items":
{
"item":
[
{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
},
...
]
}
}
In this example, we are going to also select the "batter" objects with our "subPaths" constructor option, then display all of our data set rows in a table.
var dsExample9 = new Spry.Data.JSONDataSet("../../data/json/donuts.js", { path: "items.item", subPaths: "batters.batter" });
...
<div class="liveSample" spry:region="dsExample9">
<table class="dataTable">
<tr>
<th spry:sort="id">id</th>
<th spry:sort="type">type</th>
<th spry:sort="name">name</th>
<th spry:sort="batters.batter.type">batter</th>
</tr>
<tr spry:repeat="dsExample9">
<td>{id}</td>
<td>{type}</td>
<td>{name}</td>
<td>{batters.batter.type}</td>
</tr>
</table>
</div>
Using the path "items.item" and subPath "batters.batter" will result in a data set that has the following columns defined for each row:
ds_RowID id type name ppu batters.batter.id batters.batter.type
Here is a live example:
id type name batter
0001 donut Cake Regular
0001 donut Cake Chocolate
0001 donut Cake Blueberry
0001 donut Cake Devil's Food
0002 donut Raised Regular
0003 donut Old Fashioned Regular
0003 donut Old Fashioned Chocolate
0004 bar Bar Regular
0005 twist Twist Regular
0006 filled Filled Regular
If you compare the results above against what you see in Example 8, the first thing you will notice is that we now have more rows then we used to. What is basically happening here is that each top-level object matched by the "path" constructor option is merged with any objects that were matched by the paths in the "subPaths" constructor option. If more than one object is matched below a given top-level object, a row is created for every object matched so that its data can be accommodated.
Example 10
This example builds on Example 9 to show what happens when you select another set of repeating structures with the "subPaths" constructor option.
9{
"items":
{
"item":
[
{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
},
...
]
}
}
In this example, we are going to also select the "topping" objects with our "subPaths" constructor option, then display all of our data set rows in a table.
var dsExample10 = new Spry.Data.JSONDataSet("../../data/json/donuts.js", { path: "items.item", subPaths: [ "batters.batter", "topping" ] });
...
<div class="liveSample" spry:region="dsExample10">
<table class="dataTable">
<tr>
<th spry:sort="id">id</th>
<th spry:sort="type">type</th>
<th spry:sort="name">name</th>
<th spry:sort="batters.batter.type">batter</th>
<th spry:sort="topping.type">topping</th>
</tr>
<tr spry:repeat="dsExample10">
<td>{id}</td>
<td>{type}</td>
<td>{name}</td>
<td>{batters.batter.type}</td>
<td>{topping.type}</td>
</tr>
</table>
</div>
Using the path "items.item" and sub paths "batters.batter" and "topping", will result in a data set that has the following columns defined for each row:
ds_RowID id type name ppu batters.batter.id batters.batter.type topping.id topping.type
Here is a live example:
id type name batter topping
0001 donut Cake Regular None
0001 donut Cake Regular Glazed
0001 donut Cake Regular Sugar
0001 donut Cake Regular Powdered Sugar
0001 donut Cake Regular Chocolate with Sprinkles
0001 donut Cake Regular Chocolate
0001 donut Cake Regular Maple
0001 donut Cake Chocolate None
0001 donut Cake Chocolate Glazed
0001 donut Cake Chocolate Sugar
0001 donut Cake Chocolate Powdered Sugar
0001 donut Cake Chocolate Chocolate with Sprinkles
0001 donut Cake Chocolate Chocolate
0001 donut Cake Chocolate Maple
0001 donut Cake Blueberry None
0001 donut Cake Blueberry Glazed
0001 donut Cake Blueberry Sugar
0001 donut Cake Blueberry Powdered Sugar
0001 donut Cake Blueberry Chocolate with Sprinkles
0001 donut Cake Blueberry Chocolate
0001 donut Cake Blueberry Maple
0001 donut Cake Devil's Food None
0001 donut Cake Devil's Food Glazed
0001 donut Cake Devil's Food Sugar
0001 donut Cake Devil's Food Powdered Sugar
0001 donut Cake Devil's Food Chocolate with Sprinkles
0001 donut Cake Devil's Food Chocolate
0001 donut Cake Devil's Food Maple
0002 donut Raised Regular None
0002 donut Raised Regular Glazed
0002 donut Raised Regular Sugar
0002 donut Raised Regular Chocolate
0002 donut Raised Regular Maple
0003 donut Old Fashioned Regular None
0003 donut Old Fashioned Regular Glazed
0003 donut Old Fashioned Regular Chocolate
0003 donut Old Fashioned Regular Maple
0003 donut Old Fashioned Chocolate None
0003 donut Old Fashioned Chocolate Glazed
0003 donut Old Fashioned Chocolate Chocolate
0003 donut Old Fashioned Chocolate Maple
0004 bar Bar Regular Chocolate
0004 bar Bar Regular Maple
0005 twist Twist Regular Glazed
0005 twist Twist Regular Sugar
0006 filled Filled Regular Glazed
0006 filled Filled Regular Powdered Sugar
0006 filled Filled Regular Chocolate
0006 filled Filled Regular Maple
We get even more rows than we had in Example 9 because the "topping" path also selected multiple objects in some cases. So for every top-level object matched by the "paths" constructor option, we get 'm*n' rows, where 'm' is the number of matches by the "batters.batter" sub path, and 'n' is the number of matches by the "topping" sub path.
Example 11 - Nested JSON Data Sets
Sometimes you want to work with nested structures, but you don't want to deal with the explosion of rows as shown in Example 10. Imagine you want to show a list of the different types of items, and under each item, you also want to list the different types of batters and toppings available. Doing that with the data set used in Example 10 would require some JavaScript logic embedded in spry attribute conditionals to control when things showed up. A simpler approach would be to use NestedJSONDataSets.
In this example we use the same JSON data used in Example 10, but we will use 2 nested JSON data sets to track the "batter" and "topping" data. Nested data sets are special data sets that stay in sync with the current row of their parent data set. As the current row of the parent data set changes, so does the data inside of the nested data set.
var dsExample11_Items = new Spry.Data.JSONDataSet("../../data/json/donuts.js", { path: "items.item" });
var dsExample11_Batters = new Spry.Data.NestedJSONDataSet(dsExample11_Items, "batters.batter");
var dsExample11_Toppings = new Spry.Data.NestedJSONDataSet(dsExample11_Items, "topping");
...
<div class="liveSample" spry:region="dsExample11_Items dsExample11_Batters dsExample11_Toppings">
<ul>
<li spry:repeat="dsExample11_Items">
{dsExample11_Items::name}
<ul>
<li>Batters:
<ul>
<li spry:repeat="dsExample11_Batters">{dsExample11_Batters::type}</li>
</ul>
</li>
<li>
Toppings:
<ul>
<li spry:repeat="dsExample11_Toppings">{dsExample11_Toppings::type}</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
The other interesting thing about nested data sets is that if their parent data set is used in a spry:repeat or spry:repeatchildren context, any data references from the nested data set are kept in sync with whatever the current row is that is being processed by the loop.
Here is a live example.
Cake
Batters:
Regular
Chocolate
Blueberry
Devil's Food
Toppings:
None
Glazed
Sugar
Powdered Sugar
Chocolate with Sprinkles
Chocolate
Maple
Raised
Batters:
Regular
Toppings:
None
Glazed
Sugar
Chocolate
Maple
Old Fashioned
Batters:
Regular
Chocolate
Toppings:
None
Glazed
Chocolate
Maple
Bar
Batters:
Regular
Toppings:
Chocolate
Maple
Twist
Batters:
Regular
Toppings:
Glazed
Sugar
Filled
Batters:
Regular
Toppings:
Glazed
Powdered Sugar
Chocolate
Maple
Example 12
Although you can use nested data sets to produce a table that looks like the one in Example 9, there's an important difference. Nested data sets can only sort and filter within groups constrained by the parent's row it is associated with. It is easier to illustrate this with an example. In this example, we have a table that looks like the one in Example 9 on the left side, and on the right side, we have the same data presented as a set of nested lists.
var dsExample12_Items = new Spry.Data.JSONDataSet("../../data/json/donuts.js", { path: "items.item" });
var dsExample12_Batters = new Spry.Data.NestedJSONDataSet(dsExample12_Items, "batters.batter");
...
<div class="liveSample">
<table>
<tr>
<td spry:region="dsExample12_Items dsExample12_Batters">
<table class="dataTable">
<tr>
<th spry:sort="dsExample12_Items id">id</th>
<th spry:sort="dsExample12_Items type">type</th>
<th spry:sort="dsExample12_Items name">name</th>
<th spry:sort="dsExample12_Batters type">batter</th>
</tr>
<tbody spry:repeatchildren="dsExample12_Items">
<tr spry:repeat="dsExample12_Batters">
<td>{dsExample12_Items::id}</td>
<td>{dsExample12_Items::type}</td>
<td>{dsExample12_Items::name}</td>
<td>{dsExample12_Batters::type}</td>
</tr>
</tbody>
</table>
</td>
<td spry:region="dsExample12_Items dsExample12_Batters">
<ul>
<li spry:repeat="dsExample12_Items">
{dsExample12_Items::name}
<ul>
<li>Batters:
<ul>
<li spry:repeat="dsExample12_Batters">{dsExample12_Batters::type}</li>
</ul>
</li>
</ul>
</li>
</ul>
</td>
</tr>
</table>
</div>
Here's the live example:
id type name batter
0001 donut Cake Regular
0001 donut Cake Chocolate
0001 donut Cake Blueberry
0001 donut Cake Devil's Food
0002 donut Raised Regular
0003 donut Old Fashioned Regular
0003 donut Old Fashioned Chocolate
0004 bar Bar Regular
0005 twist Twist Regular
0006 filled Filled Regular
Cake
Batters:
Regular
Chocolate
Blueberry
Devil's Food
Raised
Batters:
Regular
Old Fashioned
Batters:
Regular
Chocolate
Bar
Batters:
Regular
Twist
Batters:
Regular
Filled
Batters:
Regular
Notice that when you sort any column associated with the parent data set, all of the rows in the table shift around, whereas when you click on the batter column, it seems as if only the data in the batter column is moving around. If you look at what happens in the list on the right as you sort, it becomes more apparent what is happening.
What is not yet supported:
Arrays of arrays.
Arrays that contain elements of different types. Example: [ 100, { "foo": "bar" }, true, null ][JSON for Modern C++](https://raw.githubusercontent.com/nlohmann/json/master/doc/json.gif)](https://github.com/nlohmann/json/releases)
[![Build Status](https://travis-ci.org/nlohmann/json.svg?branch=master)](https://travis-ci.org/nlohmann/json)
[![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk/branch/develop?svg=true)](https://ci.appveyor.com/project/nlohmann/json)

1
jupyter-playfab Normal file
View File

@ -0,0 +1 @@
PlayFab EditorExtensions: Caught an error:Invalid JSON string UnityEngine.Debug:LogError(Object) PlayFab.PfEditor.PlayFabEditor:StateUpdateHandler(EdExStates, String, String) (at Assets/PlayFabEditorExtensions/Editor/PlayFabEditor.cs:332) PlayFab.PfEditor.PlayFabEditor:RaiseStateUpdate(EdExStates, String, String) (at Assets/PlayFabEditorExtensions/Editor/PlayFabEditor.cs:247) PlayFab.PfEditor.PlayFabEditorHelper:SharedErrorCallback(PlayFabError) (at Assets/PlayFabEditorExtensions/Editor/Scripts/Utils/PlayFabEditorHelper.cs:127) PlayFab.PfEditor.<>c:<OnLoginButtonClicked>b__14_1(PlayFabError) (at Assets/PlayFabEditorExtensions/Editor/Scripts/Panels/PlayFabEditorAuthenticate.cs:299) PlayFab.PfEditor.PlayFabEditorHttp:OnWwwError(Action`1, String) (at Assets/PlayFabEditorExtensions/Editor/Scripts/PlayFabEditorSDK/PlayFabEditorHttp.cs:130) PlayFab.PfEditor.<>c__DisplayClass2_0`2:<MakeApiCall>b__1(String) (at Assets/PlayFabEditorExtensions/Editor/Scripts/PlayFabEditorSDK/PlayFabEditorHttp.cs:95) PlayFab.PfEditor.<Post>d__7:MoveNext() (at Assets/PlayFabEditorExtensions/Editor/Scripts/PlayFabEditorSDK/PlayFabEditorHttp.cs:177) PlayFab.PfEditor.EditorCoroutine:Update() (at Assets/PlayFabEditorExtensions/Editor/Scripts/Utils/EditorCoroutine.cs:103) UnityEditor.EditorApplication:Internal_CallUpdateFunctions()