{"id":31974677,"url":"https://github.com/splitio/python-api","last_synced_at":"2026-03-12T13:37:44.120Z","repository":{"id":37546953,"uuid":"91126167","full_name":"splitio/python-api","owner":"splitio","description":"Split public API for Python","archived":false,"fork":false,"pushed_at":"2025-12-04T22:10:30.000Z","size":421,"stargazers_count":3,"open_issues_count":1,"forks_count":4,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-08T05:53:30.410Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/splitio.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.txt","contributing":null,"funding":null,"license":null,"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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2017-05-12T20:09:48.000Z","updated_at":"2025-11-27T03:09:22.000Z","dependencies_parsed_at":"2022-07-12T16:22:31.456Z","dependency_job_id":"b610bb77-0354-40a9-9c19-77e57ba95e02","html_url":"https://github.com/splitio/python-api","commit_stats":{"total_commits":92,"total_committers":8,"mean_commits":11.5,"dds":0.5543478260869565,"last_synced_commit":"14ae0a6b55a8a378133b0afca6087b6716890a43"},"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/splitio/python-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/splitio%2Fpython-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/splitio%2Fpython-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/splitio%2Fpython-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/splitio%2Fpython-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/splitio","download_url":"https://codeload.github.com/splitio/python-api/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/splitio%2Fpython-api/sbom","scorecard":{"id":485543,"data":{"date":"2025-08-11","repo":{"name":"github.com/splitio/python-api","commit":"01e357fc71a189aa62cefc83297e0f40a4613c27"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4,"checks":[{"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":"Code-Review","score":1,"reason":"Found 1/9 approved changesets -- score normalized to 1","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":"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":"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":"Maintained","score":10,"reason":"17 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"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":"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":"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":"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":"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":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"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":"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":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"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-19T17:40:01.360Z","repository_id":37546953,"created_at":"2025-08-19T17:40:01.360Z","updated_at":"2025-08-19T17:40:01.360Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30427339,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-12T12:46:33.731Z","status":"ssl_error","status_checked_at":"2026-03-12T12:42:20.405Z","response_time":114,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: 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":[],"created_at":"2025-10-14T20:20:08.838Z","updated_at":"2026-03-12T13:37:44.113Z","avatar_url":"https://github.com/splitio.png","language":"Python","readme":"# Split Python API\n\nThis API wrapper is designed to work with [Split](https://www.split.io), the platform for controlled rollouts, serving features to your users via the Split feature flag to manage your complete customer experience.\n\nFor specific instructions on how to use Split Admin REST API refer to our [official API documentation](https://docs.split.io/reference).\n\nFull documentation on this Python wrapper is available in [this link](https://help.split.io/hc/en-us/articles/4412331052685-Python-PyPi-library-for-Split-REST-Admin-API).\n\n## Using in Harness Mode\n\nStarting with version 3.5.0, the Split API client supports operating in \"harness mode\" to interact with both Split and Harness APIs. This is required for usage in environments that have been migrated to Harness **and** want to use the new features. Operating not in harness mode will work as it did before with existing Split bearer tokens, but the deprecated endpoints mentioned below will not function.\n\nFor detailed information about Harness API endpoints, please refer to the [official Harness API documentation](https://apidocs.harness.io/).\n\n### Authentication in Harness Mode\n\n**Important:** Harness mode requires a `harness_token` (Harness API key). Split API keys (`apikey`) are **not supported** in harness mode.\n\nIf your account has been migrated to Harness, you should create a new Harness API key to use with this client. The `harness_token` is used for both Split API endpoints and Harness-specific endpoints via the `x-api-key` header.\n\nFor non-migrated accounts that need to use Split API keys with Bearer authentication, use the standard (non-harness) mode instead.\n\n### Base URLs and Endpoints\n\n- Existing, non-deprecated Split endpoints continue to use the Split base URLs\n- New Harness-specific endpoints use the Harness base URL (https://app.harness.io/)\n\n### Deprecated Endpoints\n\nThe following Split endpoints are deprecated and cannot be used in harness mode:\n- `/workspaces`: POST, PATCH, DELETE, PUT verbs are deprecated\n- `/apiKeys`: POST verb for apiKeyType == 'admin' is deprecated\n- `/users`: all verbs are deprecated\n- `/groups`: all verbs are deprecated\n- `/restrictions`: all verbs are deprecated\n\nNon-deprecated endpoints will continue to function as they did before the migration.\n\n### Basic Usage\n\nTo use the client in harness mode:\n\n```python\nfrom splitapiclient.main import get_client\n\n# Basic harness mode setup with required harness_token\nclient = get_client({\n    'harness_mode': True,\n    'harness_token': 'YOUR_HARNESS_TOKEN',  # Required: Harness API key\n    'account_identifier': 'YOUR_HARNESS_ACCOUNT_ID'  # Required for Harness operations\n})\n\n# Include optional org_identifier and project_identifier\nclient = get_client({\n    'harness_mode': True,\n    'harness_token': 'YOUR_HARNESS_TOKEN',\n    'account_identifier': 'YOUR_HARNESS_ACCOUNT_ID',\n    'org_identifier': 'YOUR_ORG_ID',        # Optional: organization identifier\n    'project_identifier': 'YOUR_PROJECT_ID' # Optional: project identifier\n})\n```\n\n### Working with Split Resources in Harness Mode\n\nYou can still access standard Split resources with some restrictions:\n\n```python\n# List workspaces (read-only in harness mode)\nfor ws in client.workspaces.list():\n    print(f\"Workspace: {ws.name}, Id: {ws.id}\")\n\n# Find a specific workspace\nws = client.workspaces.find(\"Default\")\n\n# List environments in a workspace\nfor env in client.environments.list(ws.id):\n    print(f\"Environment: {env.name}, Id: {env.id}\")\n```\n\n### Working with Harness-specific Resources\n\nHarness mode provides access to several Harness-specific resources through dedicated microclients:\n\n- token\n- harness_apikey\n- service_account\n- harness_user\n- harness_group\n- role\n- resource_group\n- role_assignment\n- harness_project\n\nBasic example:\n\n```python\n# Account identifier is required for all Harness operations\naccount_id = 'YOUR_ACCOUNT_IDENTIFIER'\n\n# List all tokens (org_identifier and project_identifier are optional)\ntokens = client.token.list(account_id)\nfor token in tokens:\n    print(f\"Token: {token.name}, ID: {token.id}\")\n\n# List service accounts with org and project identifiers\norg_id = 'YOUR_ORG_IDENTIFIER'\nproject_id = 'YOUR_PROJECT_IDENTIFIER'\nservice_accounts = client.service_account.list(account_id, org_identifier=org_id, project_identifier=project_id)\nfor sa in service_accounts:\n    print(f\"Service Account: {sa.name}, ID: {sa.id}\")\n\n# If org_identifier and project_identifier are set at client initialization, you can omit them\nclient = get_client({\n    'harness_mode': True,\n    'harness_token': 'YOUR_HARNESS_TOKEN',\n    'account_identifier': account_id,\n    'org_identifier': org_id,\n    'project_identifier': project_id\n})\n\n# Now you can call methods without specifying identifiers\nservice_accounts = client.service_account.list()  # Uses default identifiers\nprojects = client.harness_project.list()  # Uses default identifiers\n```\n\nFor most creation, update, and delete endpoints for harness specific resources, you will need to pass through the JSON body directly. \n\nExample:\n```python\n# Create a new service account\nsa_data = {\n    'name': sa_name,\n    'identifier': sa_identifier,\n    'email': \"test@harness.io\",\n    'accountIdentifier': account_id,\n    'description': 'Service account for test',\n    'tags': {'test': 'test tag'}\n}\n        \nnew_sa = client.service_account.create(sa_data, account_id)\n```\n\n```python\n# Add a user to a group\nclient.harness_user.add_user_to_groups(user.id, [group.id], account_id)\n```\n\n### Harness Groups\n\nThe `harness_group.list()` method supports an optional `filterType` parameter to filter groups:\n\n```python\n# List all groups (default behavior)\nall_groups = client.harness_group.list()\n\n# List groups with filterType to exclude inherited groups\ngroups = client.harness_group.list(filterType='EXCLUDE_INHERITED_GROUPS')\n\n# List groups with filterType and other optional parameters\ngroups = client.harness_group.list(\n    account_identifier='YOUR_ACCOUNT_ID',\n    org_identifier='YOUR_ORG_ID',\n    project_identifier='YOUR_PROJECT_ID',\n    filterType='INCLUDE_INHERITED_GROUPS'\n)\n```\n\n**Note:** The `filterType` parameter is optional. When not provided (or set to `None`), it will be omitted from the API request. Valid values depend on the Harness API specification.\n\n\nFor detailed examples and API specifications for each resource, please refer to the [Harness API documentation](https://apidocs.harness.io/).\n\n### Setting Default Identifiers\n\nTo avoid specifying identifiers with every request, you can set default values when creating the client:\n\n```python\n# Set default identifiers when creating the client\nclient = get_client({\n    'harness_mode': True,\n    'harness_token': 'YOUR_HARNESS_TOKEN',\n    'account_identifier': 'YOUR_ACCOUNT_IDENTIFIER',  # Required\n    'org_identifier': 'YOUR_ORG_IDENTIFIER',          # Optional\n    'project_identifier': 'YOUR_PROJECT_IDENTIFIER'   # Optional\n})\n\n# Now you can make calls without specifying identifiers in each request\ntokens = client.token.list()  # account_identifier is automatically included\nprojects = client.harness_project.list()  # account_identifier and org_identifier are automatically included (project_identifier is not used for projects endpoint)\n```\n\n**Note on Optional Identifiers:**\n- `account_identifier` is **required** for all Harness operations\n- `org_identifier` and `project_identifier` are **optional** and will be omitted from API requests if not provided\n- If `org_identifier` or `project_identifier` are not set, they will not appear in the URL at all (not even as empty parameters)\n- **Important:** The `harness_project` microclient does **not** support `project_identifier` as a query parameter. The projects endpoint only uses `org_identifier` (and `account_identifier`). Other microclients (service_account, token, role, etc.) do support `project_identifier`.\n- You can override default identifiers by passing them as parameters to individual method calls:\n\n```python\n# Override default identifiers for a specific request\n# Note: project_identifier is not used for harness_project endpoints\nprojects = client.harness_project.list(\n    account_identifier='DIFFERENT_ACCOUNT_ID',\n    org_identifier='DIFFERENT_ORG_ID'\n)\n\n# Use default identifiers but override only org_identifier\n# Note: project_identifier is not used for harness_project endpoints\nprojects = client.harness_project.list(org_identifier='DIFFERENT_ORG_ID')\n```\n\n## Quick Setup\n\nInstall the splitapiclient:\n```\npip install splitapiclient\n```\n\nImport the client object and initialize connection using an Admin API Key:\n\n```python\nfrom splitapiclient.main import get_client\nclient = get_client({'apikey': 'ADMIN API KEY'})\n```\n\nEnable optional logging:\n\n```python\nimport logging\nlogging.basicConfig(level=logging.DEBUG)\n```\n\n## Standard Split API Usage\n\n### Workspaces\n\nFetch all workspaces:\n\n```python\nfor ws in client.workspaces.list():\n    print(\"\\nWorkspace:\" + ws.name + \", Id: \" + ws.id)\n```\n\nFind a specific workspace:\n\n```python\nws = client.workspaces.find(\"Defaults\")\nprint(\"\\nWorkspace:\" + ws.name + \", Id: \" + ws.id)\n```\n\n### Environments\n\nFetch all Environments:\n\n```python\nws = client.workspaces.find(\"Defaults\")\nfor env in client.environments.list(ws.id):\n    print(\"\\nEnvironment: \" + env.name + \", Id: \" + env.id)\n```\n\nAdd new environment:\n\n```python\nws = client.workspaces.find(\"Defaults\")\nenv = ws.add_environment({'name': 'new_environment', 'production': False})\n```\n\n### Splits\nFetch all Splits:\n\n```python\nws = client.workspaces.find(\"Defaults\")\nfor split in client.splits.list(ws.id):\n    print(\"\\nSplit: \" + split.name + \", \" + split._workspace_id)\n```\n\nAdd new Split:\n\n```python\nsplit = ws.add_split({'name': 'split_name', 'description': 'new UI feature'}, \"user\")\nprint(split.name)\n```\n\nAdd tags:\n\n```python\nsplit.associate_tags(['my_new_tag', 'another_new_tag'])\n```\n\nAdd Split to environment:\n\n```python\nws = client.workspaces.find(\"Defaults\")\nsplit = client.splits.find(\"new_feature\", ws.id) \nenv = client.environments.find(\"Production\", ws.id)\ntr1 = treatment.Treatment({\"name\":\"on\",\"configurations\":\"\"})\ntr2 = treatment.Treatment({\"name\":\"off\",\"configurations\":\"\"})\nbk1 = bucket.Bucket({\"treatment\":\"on\",\"size\":50})\nbk2 = bucket.Bucket({\"treatment\":\"off\",\"size\":50})\nmatch = matcher.Matcher({\"attribute\":\"group\",\"type\":\"IN_LIST_STRING\",\"strings\":[\"employees\"]})\ncond = condition.Condition({'matchers':[match.export_dict()]})\nrl = rule.Rule({'condition':cond.export_dict(), 'buckets':[bk1.export_dict(), bk2.export_dict()]})\ndefrl = default_rule.DefaultRule({\"treatment\":\"off\",\"size\":100}) \ndata={\"treatments\":[tr1.export_dict() ,tr2.export_dict()],\"defaultTreatment\":\"off\", \"baselineTreatment\": \"off\",\"rules\":[rl.export_dict()],\"defaultRule\":[defrl.export_dict()], \"comment\": \"adding split to production\"}\nsplitdef = split.add_to_environment(env.id, data)\n```\n\nKill Split:\n\n```python\nws = client.workspaces.find(\"Defaults\")\nenv = client.environments.find(\"Production\", ws.id)\nsplitDef = client.split_definitions.find(\"new_feature\", env.id, ws.id)\nsplitDef.kill()\n```\n\nRestore Split:\n\n```python\nsplitDef.restore()\n```\n\nFetch all Splits in an Environment:\n\n```python\nws = client.workspaces.find(\"Defaults\")\nenv = client.environments.find(\"Production\", ws.id)\nfor spDef in client.split_definitions.list(env.id, ws.id):\n    print(spDef.name + str(spDef._default_rule))\n```\n\nSubmit a Change request to update a Split definition:\n\n```python\nsplitDef = client.split_definitions.find(\"new_feature\", env.id, ws.id)\ndefinition= {\"treatments\":[ {\"name\":\"on\"},{\"name\":\"off\"}],\n    \"defaultTreatment\":\"off\", \"baselineTreatment\": \"off\",\n    \"rules\": [],\n    \"defaultRule\":[{\"treatment\":\"off\",\"size\":100}],\"comment\": \"updating default rule\"\n}\nsplitDef.submit_change_request(definition, 'UPDATE', 'updating default rule', 'comment', ['user@email.com'], '')\n```\n\n### Rule-Based Segments\n\nRule-based segments allow you to define audience segments using complex rule structures and exclusion logic. Added in version 3.5.1, they offer enhanced functionality for targeting users.\n\nFetch all Rule-Based Segments:\n\n```python\nws = client.workspaces.find(\"Defaults\")\nfor segment in client.rule_based_segments.list(ws.id):\n    print(\"\\nRule-Based Segment: \" + segment.name + \", \" + segment.description)\n```\n\nAdd new Rule-Based Segment:\n\n```python\nsegment_data = {\n    'name': 'advanced_users',\n    'description': 'Users who match advanced criteria'\n}\nrule_segment = ws.add_rule_based_segment(segment_data, \"user\")\nprint(rule_segment.name)\n```\n\nAdd Rule-Based Segment to environment:\n\n```python\nws = client.workspaces.find(\"Defaults\")\nsegment = client.rule_based_segments.find(\"advanced_users\", ws.id)\nenv = client.environments.find(\"Production\", ws.id)\nsegdef = segment.add_to_environment(env.id)\n```\n\nRemove Rule-Based Segment from environment:\n\n```python\nws = client.workspaces.find(\"Defaults\")\nsegment = client.rule_based_segments.find(\"advanced_users\", ws.id)\nenv = client.environments.find(\"Production\", ws.id)\nsuccess = segment.remove_from_environment(env.id)\n```\nRemove Rule based segment from workspace\n\n```python\nws = client.workspaces.find(\"Defaults\")\nsuccess = ws.delete_rule_based_segment(\"advanced_users\")\n```\n\n#### Rule-Based Segment Structure\n\nRule-based segment definitions support multiple rule types and matching conditions:\n\n```python\n# Examples of different matcher types\nmatchers = [\n    # String matching\n    {\n        'type': 'IN_LIST_STRING',\n        'attribute': 'device',\n        'strings': ['mobile', 'tablet']\n    },\n    # Numeric comparisons\n    {\n        'type': 'GREATER_THAN_OR_EQUAL_NUMBER',\n        'attribute': 'age',\n        'number': 21\n    },\n    {\n        'type': 'LESS_THAN_OR_EQUAL_NUMBER',\n        'attribute': 'account_age_days',\n        'number': 30\n    },\n    {\n        'type': 'BETWEEN_NUMBER',\n        'attribute': 'purchases',\n        'between': {'from': 5, 'to': 20}\n    },\n    # Boolean conditions\n    {\n        'type': 'BOOLEAN',\n        'attribute': 'subscribed',\n        'bool': True\n    },\n    # Date/time matching\n    {\n        'type': 'ON_DATE',\n        'attribute': 'sign_up_date',\n        'date': 1623456789000  # timestamp in milliseconds\n    },\n    # Dependency on another split\n    {\n        'type': 'IN_SPLIT',\n        'attribute': '',\n        'depends': {'splitName': 'another_split', 'treatment': 'on'}\n    }\n]\n\n# Multiple conditions using combiners\ncondition = {\n    'combiner': 'AND',  # Can only be 'AND'\n    'matchers': matchers\n}\n```\n\nUpdate Rule-Based Segment definition with rules:\n\n```python\nws = client.workspaces.find(\"Defaults\")\nenv = client.environments.find(\"Production\", ws.id)\nsegdef = client.rule_based_segment_definitions.find(\"advanced_users\", env.id, ws.id)\n\n# Define rules that match users in a certain list\nrules_data = {\n    'rules': [\n        {\n            'condition': {\n                'combiner': 'AND',\n                'matchers': [\n                    {\n                        'type': 'GREATER_THAN_OR_EQUAL_NUMBER',\n                        'attribute': 'age',\n                        'number': 30\n                    },\n                    {\n                        'type': 'BOOLEAN',\n                        'attribute': 'completed_tutorials',\n                        'bool': True\n                    }\n                ]\n            }\n        }\n    ]\n}\n\n# Update the segment definition with the rules\nupdated_segdef = segdef.update(rules_data) # the workspace id is passed in from the find operation - so it's not needed here\n```\n\nUpdate Rule-Based Segment definition with excluded keys and excluded segments:\n\n```python\nws = client.workspaces.find(\"Defaults\")\nenv = client.environments.find(\"Production\", ws.id)\nsegdef = client.rule_based_segment_definitions.find(\"advanced_users\", env.id, ws.id)\n\n# Define rules and exclusion data\nupdate_data = {\n    'rules': [\n        {\n            'condition': {\n                'combiner': 'AND',\n                'matchers': [\n                    {\n                        'type': 'GREATER_THAN_OR_EQUAL_NUMBER',\n                        'attribute': 'age',\n                        'number': 30\n                    }\n                ]\n            }\n        }\n    ],\n    'excludedKeys': ['user1', 'user2', 'user3'],\n    'excludedSegments': [\n        {\n            'name': 'beta_testers',\n            'type': 'standard_segment'\n        }\n    ]\n}\n\n# Update the segment definition with rules and exclusions\nupdated_segdef = segdef.update(update_data)\n```\n\nSubmit a Change request to update a Rule-Based Segment definition:\n\n```python\nws = client.workspaces.find(\"Defaults\")\nenv = client.environments.find(\"Production\", ws.id)\nsegdef = client.rule_based_segment_definitions.find(\"advanced_users\", env.id, ws.id)\n\n# New rules for the change request\nrules = [\n    {\n        'condition': {\n            'combiner': 'AND',\n            'matchers': [\n                {\n                    'type': 'GREATER_THAN_OR_EQUAL_NUMBER',\n                    'attribute': 'age',\n                    'number': 25\n                },\n                {\n                    'type': 'BOOLEAN',\n                    'attribute': 'completed_tutorials',\n                    'bool': True\n                }\n            ]\n        }\n    }\n]\n\n# Define excluded keys and segments for the change request\nexcluded_keys = ['user1', 'user2']\nexcluded_segments = [\n    {\n        'name': 'test_users',\n        'type': 'rule_based_segment'\n    }\n]\n\n# Submit change request with all parameters\nsegdef.submit_change_request(\n    rules=rules,\n    excluded_keys=excluded_keys,\n    excluded_segments=excluded_segments,\n    operation_type='UPDATE',\n    title='Lower age threshold to 25',\n    comment='Including more users in advanced segment',\n    approvers=['user@email.com'],\n    workspace_id=ws.id\n)\n```\n\nList all change requests:\n\n```python\nfor cr in client.change_requests.list():\n    if cr._split is not None:\n        print(cr._id + \", \" + cr._split['name'] + \", \" + cr._title + \", \" + str(cr._split['environment']['id'])) \n    if cr._segment is not None:\n        print(cr._id + \", \" + cr._segment['name'] + \", \" + cr._title)\n```\n\nApprove specific change request:\n\n```python\nfor cr in client.change_requests.list():\n    if cr._split['name'] == 'new_feature':\n        cr.update_status(\"APPROVED\", \"done\")\n```\n\n### Users and Groups\n\nFetch all Active users:\n\n```python\nfor user in client.users.list('ACTIVE'):\n    print(user.email + \", \" + user._id) \n```\n\nInvite new user:\n\n```python\ngroup = client.groups.find('Administrators')\nuserData = {'email': 'user@email.com', 'groups': [{'id': '', 'type': 'group'}]}\nuserData['groups'][0]['id'] = group._id\nclient.users.invite_user(userData)\n```\n\nDelete a pending invite:\n\n```python\nfor user in client.users.list('PENDING'):\n    print(user.email + \", \" + user._id + \", \" + user._status)\n    if user.email == 'user@email.com': \n        client.users.delete(user._id)\n```\n\nUpdate user info:\n\n```python\ndata = {'name': 'new_name', 'email': 'user@email.com', '2fa': False, 'status': 'ACTIVE'}\nuser = client.users.find('user@email.com')\nuser.update_user(user._id, data)\n```\n\nFetch all Groups:\n\n```python\nfor group in client.groups.list():\n    print(group._id + \", \" + group._name)\n```\n\nCreate Group:\n\n```python\nclient.groups.create_group({'name': 'new_group', 'description': ''})\n```\n\nDelete Group:\n\n```python\ngroup = client.groups.find('new_group')\nclient.groups.delete_group(group._id)\n```\n\nReplace existing user group:\n\n```python\nuser = client.users.find('user@email.com')\ngroup = client.groups.find('Administrators')\ndata = [{'op': 'replace', 'path': '/groups/0', 'value': {'id': '\u003cgroupId\u003e', 'type': 'group'}}]\ndata[0]['value']['id'] = group._id\nuser.update_user_group(data)\n```\n\nAdd user to new group\n\n```python\nuser = client.users.find('user@email.com')\ngroup = client.groups.find('Administrators')\ndata = [{'op': 'add', 'path': '/groups/-', 'value': {'id': '\u003cgroupId\u003e', 'type': 'group'}}]\ndata[0]['value']['id'] = group._id\nuser.update_user_group(data)\n```\n\n## About Split\n\n### Commitment to Quality:\n\nSplit's APIs are in active development and are constantly tested for quality. Unit tests are developed for each wrapper based on the unique needs of that language, and integration tests, load and performance tests, and behavior consistency tests are running 24/7 via automated bots. In addition, monitoring instrumentation ensures that these wrappers behave under the expected parameters of memory, CPU, and I/O.\n\n### About Split:\n\nSplit is the leading platform for intelligent software delivery, helping businesses of all sizes deliver exceptional user experiences, and mitigate risk, by providing an easy, secure way to target features to customers. Companies like WePay, LendingTree and thredUP rely on Split to safely launch and test new features and derive insights on their use. Founded in 2015, Split's team comes from some of the most innovative enterprises in Silicon Valley, including Google, LinkedIn, Salesforce and Splunk. Split is based in Redwood City, California and backed by Accel Partners and Lightspeed Venture Partners. To learn more about Split, contact hello@split.io, or start a 14-day free trial at www.split.io/trial.\n\n**Try Split for Free:**\n\nSplit is available as a 14-day free trial. To create an account, visit [split.io/trial](https://www.split.io/trial).\n\n**Learn more about Split:** \n\nVisit [split.io/product](https://www.split.io/product) for an overview of Split, or visit our documentation at [docs.split.io](http://docs.split.io) for more detailed information.\n\n**System Status:**\n\nWe use a status page to monitor the availability of Split's various services. You can check the current status at [status.split.io](http://status.split.io).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsplitio%2Fpython-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsplitio%2Fpython-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsplitio%2Fpython-api/lists"}