{"id":40171876,"url":"https://github.com/cubewise-code/mdxpy","last_synced_at":"2026-01-19T17:07:06.743Z","repository":{"id":40414229,"uuid":"257066960","full_name":"cubewise-code/mdxpy","owner":"cubewise-code","description":"A simple, yet elegant MDX library for TM1","archived":false,"fork":false,"pushed_at":"2024-12-18T10:44:03.000Z","size":366,"stargazers_count":33,"open_issues_count":4,"forks_count":11,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-09-28T13:26:56.869Z","etag":null,"topics":["mdx","planning-analytics","python","tm1","tm1-rest-api","tm1py"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cubewise-code.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-04-19T17:57:41.000Z","updated_at":"2025-03-01T06:24:01.000Z","dependencies_parsed_at":"2024-06-19T04:11:53.090Z","dependency_job_id":"67d5c6af-9838-4aaa-bbca-8c877cb9dc17","html_url":"https://github.com/cubewise-code/mdxpy","commit_stats":{"total_commits":69,"total_committers":6,"mean_commits":11.5,"dds":0.5217391304347826,"last_synced_commit":"07489c2e23cdab02ef4e33149da5a1bba85004c0"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/cubewise-code/mdxpy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cubewise-code%2Fmdxpy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cubewise-code%2Fmdxpy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cubewise-code%2Fmdxpy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cubewise-code%2Fmdxpy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cubewise-code","download_url":"https://codeload.github.com/cubewise-code/mdxpy/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cubewise-code%2Fmdxpy/sbom","scorecard":{"id":312244,"data":{"date":"2025-08-11","repo":{"name":"github.com/cubewise-code/mdxpy","commit":"9b8d38a0ee73941ee78fd75cfd3610ad156b473c"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.4,"checks":[{"name":"Code-Review","score":6,"reason":"Found 8/12 approved changesets -- score normalized to 6","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 27 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-17T23:22:30.948Z","repository_id":40414229,"created_at":"2025-08-17T23:22:30.949Z","updated_at":"2025-08-17T23:22:30.949Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28577208,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-19T16:29:19.148Z","status":"ssl_error","status_checked_at":"2026-01-19T16:29:17.772Z","response_time":67,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mdx","planning-analytics","python","tm1","tm1-rest-api","tm1py"],"created_at":"2026-01-19T17:07:06.217Z","updated_at":"2026-01-19T17:07:06.731Z","avatar_url":"https://github.com/cubewise-code.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Logo](./images/logo.png)\n\n\n## MDXpy\n\nA simple, yet elegant MDX library for TM1\n\n## Install\n\n    pip install mdxpy\n\n## Usage\n\nCreate MDX queries programmatically with the `Member`, `MdxTuple`, `MdxHierarchySet`, `MdxBuilder` classes.\n\nBenefits of using MDXpy over hacking raw MDX queries in your code\n- Faster to write\n- Requires less MDX knowledge\n- Eliminates syntax errors (e.g. forget `}`, `]`, `)` in a query) forever\n- Makes code more robust and easier to refactor\n- Escaping of `]` in object names is taken care of \n\n### Member\n\n`Member` is used in `MdxTuple` and `MdxHierarchySet`. \ncreate a `Member` with the static `Member.of(*args: str)` method.\n\n``` python\n\u003e\u003e\u003e member = Member.of(\"Product\", \"Product1\")\n\u003e\u003e\u003e print(member.unique_name)\n[PRODUCT].[PRODUCT].[PRODUCT1]\n\n\u003e\u003e\u003e member = Member.of(\"Region\", \"ByGeography\", \"UK\")\n\u003e\u003e\u003e print(member.unique_name)\n[REGION].[BYGEOGRAPHY].[UK]\n```\n\n### MdxTuple\n\nCreate a `MdxTuple` with the static `of(*args: Member)` method. The MDX expression of the tuple is generated with the `to_mdx` method.\n\n``` python\n\u003e\u003e\u003e mdx_tuple = MdxTuple.of(Member.of(\"Product\", \"Product1\"), Member.of(\"Region\", \"US\"))\n\n\u003e\u003e\u003e print(mdx_tuple.to_mdx())\n([PRODUCT].[PRODUCT].[PRODUCT1],[REGION].[REGION].[US])\n\n\u003e\u003e\u003e mdx_tuple = MdxTuple.of(Member.of(\"Product\", \"ByType\", \"Product1\"), Member.of(\"Region\", \"ByGeography\", \"North America\"))\n\n\u003e\u003e\u003e print(mdx_tuple.to_mdx())\n([PRODUCT].[BYTYPE].[PRODUCT1],[REGION].[BYGEOGRAPHY].[North America])\n\n```     \n\nyou can add a `Member` to a `MdxTuple`\n\n``` python\n\u003e\u003e\u003e mdx_tuple = MdxTuple.of(Member.of(\"Product\", \"ByType\", \"Product1\"))\n\n\u003e\u003e\u003e mdx_tuple.add_member(Member.of(\"Region\", \"ByGeography\", \"North America\"))\n\n\u003e\u003e\u003e print(mdx_tuple.to_mdx())\n([PRODUCT].[BYTYPE].[PRODUCT1],[REGION].[BYGEOGRAPHY].[NORTHAMERICA])\n```\n\n### MdxHierarchySet\n\n`MdxHierarchySet` is created with any of the static methods on the `MdxHierarchySet` class. The `MDX` expression of the set is generated with the `to_mdx` method.\n\n``` python\n\u003e\u003e\u003e mdx_set = MdxHierarchySet.tm1_subset_all(\"Product\")\n\u003e\u003e\u003e print(mdx_set.to_mdx())\n{TM1SUBSETALL([Product].[Product])}\n\n\u003e\u003e\u003e mdx_set = MdxHierarchySet.tm1_subset_to_set(\"Region\", \"By Geography\", \"Default\")\n\u003e\u003e\u003e print(mdx_set.to_mdx())\n{TM1SUBSETTOSET([REGION].[BYGEOGRAPHY],'Default')}\n\n\u003e\u003e\u003e mdx_set = MdxHierarchySet.all_leaves(\"Region\")\n\u003e\u003e\u003e print(mdx_set.to_mdx())\n{TM1FILTERBYLEVEL({TM1SUBSETALL([REGION].[REGION])},0)}\n\n\u003e\u003e\u003e mdx_set = MdxHierarchySet.members([Member.of(\"Region\", \"US\"), Member.of(\"Product\", \"Product1\")])\n\u003e\u003e\u003e print(mdx_set.to_mdx())\n{[REGION].[REGION].[US],[PRODUCT].[PRODUCT].[PRODUCT1]}\n```\n\nFunctions on `MdxHierarchySet` can be concatenated to arbitrary length in a functional style:\n\n``` python\n\u003e\u003e\u003e mdx_set = MdxHierarchySet.tm1_subset_all(\"Region\").filter_by_level(0).filter_by_pattern(\"I*\").tm1_sort()\n\u003e\u003e\u003e print(mdx_set.to_mdx())\n{TM1SORT({TM1FILTERBYPATTERN({TM1FILTERBYLEVEL({TM1SUBSETALL([REGION].[REGION])},0)},'I*')},ASC)}\n```\n\n### MdxBuilder\n\nThe `MdxBuilder` is used to build MDX queries. `MdxHierarchySet` or `MdxTuple` are placed on the axes. Zero suppression can be switched on or off per axis. The actual `MDX` expression is generated with the `to_mdx` method. \n\n``` python\n\u003e\u003e\u003e query = MdxBuilder.from_cube(\"Cube\").add_hierarchy_set_to_column_axis(MdxHierarchySet.all_leaves(\"Product\"))\n\u003e\u003e\u003e print(query.to_mdx())\nSELECT {TM1FILTERBYLEVEL({TM1SUBSETALL([PRODUCT].[PRODUCT])},0)} ON 0\nFROM [CUBE] \n\n\u003e\u003e\u003e query = MdxBuilder.from_cube(\"Cube\").add_hierarchy_set_to_column_axis(MdxHierarchySet.member(Member.of(\"Product\", \"Product1\")))\n\u003e\u003e\u003e print(query.to_mdx())\nSELECT {[PRODUCT].[PRODUCT].[PRODUCT1]} ON 0\nFROM [CUBE] \n\n\u003e\u003e\u003e query =  MdxBuilder.from_cube(\"Cube\").add_member_tuple_to_axis(0, Member.of(\"Product\", \"Product1\"), Member.of(\"Region\", \"EMEA\"))\n\u003e\u003e\u003e print(query.to_mdx())\nSELECT\n{([PRODUCT].[PRODUCT].[PRODUCT1],[REGION].[REGION].[EMEA])} ON 0\nFROM [CUBE] \n\n\u003e\u003e\u003e query = MdxBuilder.from_cube(\"Cube\").columns_non_empty().add_hierarchy_set_to_column_axis(MdxHierarchySet.member(Member.of(\"Product\", \"Product1\")))\n\u003e\u003e\u003e print(query.to_mdx())\nSELECT\nNON EMPTY {[PRODUCT].[PRODUCT].[PRODUCT1]} ON 0 \nFROM [CUBE]\n```\n\nMDX queries can have any number of axes. Axis 0 _(=columns)_ must be defined.\n\n``` python\n\u003e\u003e\u003e mdx = MdxBuilder.from_cube(\"Cube\") \\\n    .add_hierarchy_set_to_axis(0, MdxHierarchySet.member(Member.of(\"Region\", \"US\"))) \\\n    .add_hierarchy_set_to_axis(1, MdxHierarchySet.all_leaves(\"Product\")) \\\n    .add_hierarchy_set_to_axis(2, MdxHierarchySet.member(Member.of(\"Version\", \"Actual\"))) \\\n    .add_hierarchy_set_to_axis(3, MdxHierarchySet.tm1_subset_to_set(\"Time\", \"Time\", \"2020-Q1\")) \\\n    .to_mdx()\n\n\u003e\u003e\u003e print(mdx)\nSELECT\n{[REGION].[REGION].[US]} ON 0,\n{TM1FILTERBYLEVEL({TM1SUBSETALL([PRODUCT].[PRODUCT])},0)} ON 1,\n{[VERSION].[VERSION].[ACTUAL]} ON 2,\n{TM1SUBSETTOSET([TIME].[TIME],'2020-Q1')} ON 3\nFROM [CUBE]\n```\n\n\n### MultiMdxBuilder\n\nThe `MultiMdxBuilder` can be used to build a List of MDX queries based on subsets.\n\n``` python\n\u003e\u003e\u003e from mdxpy import MdxHierarchySet, MultiMdxBuilder\n\n\u003e\u003e\u003e query = MultiMdxBuilder.from_cube(\n    cube=\"Cube\",\n    multi_dimension='Month',\n    multi_hierarchy='Month',\n    multi_subsets=['Q1', 'Q2', 'Q3', 'Q4'],\n    multi_axis=1)\n    \n\u003e\u003e\u003e queries = query.add_hierarchy_set_to_column_axis(MdxHierarchySet.all_leaves(\"Product\"))\n\u003e\u003e\u003e print(queries)\n['SELECT\\r\\n{TM1FILTERBYLEVEL({TM1SUBSETALL([product].[product])},0)} DIMENSION PROPERTIES MEMBER_NAME ON 0,\\r\\n{TM1SUBSETTOSET([month].[month],\"Q1\")} DIMENSION PROPERTIES MEMBER_NAME ON 1\\r\\nFROM [cube]', 'SELECT\\r\\n{TM1FILTERBYLEVEL({TM1SUBSETALL([product].[product])},0)} DIMENSION PROPERTIES MEMBER_NAME ON 0,\\r\\n{TM1SUBSETTOSET([month].[month],\"Q2\")} DIMENSION PROPERTIES MEMBER_NAME ON 1\\r\\nFROM [cube]', 'SELECT\\r\\n{TM1FILTERBYLEVEL({TM1SUBSETALL([product].[product])},0)} DIMENSION PROPERTIES MEMBER_NAME ON 0,\\r\\n{TM1SUBSETTOSET([month].[month],\"Q3\")} DIMENSION PROPERTIES MEMBER_NAME ON 1\\r\\nFROM [cube]', 'SELECT\\r\\n{TM1FILTERBYLEVEL({TM1SUBSETALL([product].[product])},0)} DIMENSION PROPERTIES MEMBER_NAME ON 0,\\r\\n{TM1SUBSETTOSET([month].[month],\"Q4\")} DIMENSION PROPERTIES MEMBER_NAME ON 1\\r\\nFROM [cube]']\n```\n\nThis can be used to great effect in conjunction with TM1py's `execute_mdx_dataframe_async` function.\n\n\nThe `CalculatedMember` class is used to define query-scoped calculated members. They are used with the `MdxBuilder` through the `with_member` function.\n\n``` python\n\u003e\u003e\u003e mdx = MdxBuilder.from_cube(cube=\"Record Rating\").with_member(\n        CalculatedMember.avg(\n            dimension=\"Period\",\n            hierarchy=\"Period\",\n            element=\"AVG 2016\",\n            cube=\"Record Rating\",\n            mdx_set=MdxHierarchySet.children(member=Member.of(\"Period\", \"2016\")),\n            mdx_tuple=MdxTuple.of(Member.of(\"Chart\", \"Total Charts\"), Member.of(\"Record Rating Measure\", \"Rating\")))) \\\n        .add_hierarchy_set_to_row_axis(\n        MdxHierarchySet\n            .children(Member.of(\"Record\", \"Total Records\"))\n            .top_count(cube=\"Record Rating\", mdx_tuple=MdxTuple.of(Member.of(\"Period\", \"AVG 2016\")), top=5)) \\\n        .add_member_tuple_to_columns(Member.of(\"Period\", \"AVG 2016\")) \\\n        .where(Member.of(\"Chart\", \"Total Charts\"), Member.of(\"Record Rating Measure\", \"Rating\")) \\\n        .to_mdx()\n\n\u003e\u003e\u003e print(mdx)\nWITH \nMEMBER [PERIOD].[PERIOD].[AVG2016] AS AVG({[PERIOD].[PERIOD].[2016].CHILDREN},[Record Rating].([CHART].[CHART].[TOTALCHARTS],[RECORDRATINGMEASURE].[RECORDRATINGMEASURE].[RATING]))\nSELECT\n{([PERIOD].[PERIOD].[AVG2016])} ON 0,\n{TOPCOUNT({[RECORD].[RECORD].[TOTALRECORDS].CHILDREN},5,[RECORDRATING].([PERIOD].[PERIOD].[AVG2016]))} ON 1\nFROM [RECORDRATING]\nWHERE ([CHART].[CHART].[TOTALCHARTS],[RECORDRATINGMEASURE].[RECORDRATINGMEASURE].[RATING])\n```\n\nThe `DimensionProperty` class is used to query attributes in conjunction with data. \nIt is used with the `MdxBuilder` through the `add_properties_to_row_axis`, `add_hierarchy_set_to_column_axis` functions.\n\n``` python\nfrom mdxpy import DimensionProperty, MdxHierarchySet, MdxBuilder, Member\n\nquery = MdxBuilder.from_cube(\"Sales\")\n\nquery = query.rows_non_empty()\nquery = query.add_hierarchy_set_to_row_axis(MdxHierarchySet.all_leaves(\"Product\"))\nquery = query.add_properties_to_row_axis(DimensionProperty.of(\"Product\", \"Description\"))\n\nquery = query.columns_non_empty()\nquery = query.add_hierarchy_set_to_column_axis(MdxHierarchySet.member(Member.of(\"Sales Measure\", \"Revenue\")))\n\nquery = query.where(Member.of(\"Year\", \"2022\"), Member.of(\"Region\", \"Switzerland\"))\n\nprint(query.to_mdx())\n\n\u003e\u003e\u003e print(mdx)\nSELECT\nNON EMPTY {[salesmeasure].[salesmeasure].[revenue]} DIMENSION PROPERTIES MEMBER_NAME ON 0,\nNON EMPTY {TM1FILTERBYLEVEL({TM1SUBSETALL([product].[product])},0)} DIMENSION PROPERTIES [product].[product].[description] ON 1\nFROM [sales]\nWHERE ([year].[year].[2022],[region].[region].[switzerland])\n```\n\nTo see all samples checkout the `test.py` file\n\n## Supported MDX Functions\n\n- TM1SUBSETALL\n- MEMBERS\n- TM1SUBSETTOSET\n- DEFAULTMEMBER\n- PARENT\n- FIRSTCHILD\n- LASTCHILD\n- CHILDREN\n- ANCESTORS\n- ANCESTOR\n- DRILLDOWNLEVEL\n- FILTER\n- TM1FILTERBYPATTERN\n- TM1FILTERBYLEVEL\n- TM1SORT\n- HEAD\n- TAIL\n- SUBSET\n- TOPCOUNT\n- BOTTOMCOUNT\n- UNION\n- INTERSECT\n- EXCEPT\n- ORDER\n\n## Tests\n\nAll tests in `test.py`\n\n## Contribution\n\nContribution is welcome. If you find a bug or feel like you can contribute please fork the repository, update the code and then create a pull request so we can merge in the changes.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcubewise-code%2Fmdxpy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcubewise-code%2Fmdxpy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcubewise-code%2Fmdxpy/lists"}