Giter Site home page Giter Site logo

launchdarkly / python-server-sdk Goto Github PK

View Code? Open in Web Editor NEW
38.0 52.0 44.0 1.39 MB

LaunchDarkly Server-side SDK for Python

Home Page: https://docs.launchdarkly.com/sdk/server-side/python

License: Other

Python 99.76% Makefile 0.24%
launchdarkly python feature-flags feature-toggles sdk launchdarkly-sdk managed-by-terraform

python-server-sdk's Introduction

LaunchDarkly Server-side SDK for Python

Actions Status readthedocs

PyPI PyPI

LaunchDarkly overview

LaunchDarkly is a feature management platform that serves trillions of feature flags daily to help teams build better software, faster. Get started using LaunchDarkly today!

Twitter Follow

Supported Python versions

This version of the LaunchDarkly SDK is compatible with Python 3.8 through 3.12. It is tested with the most recent patch releases of those versions. Python versions 2.7 to 3.6 are no longer supported.

Getting started

Refer to the SDK reference guide for instructions on getting started with using the SDK.

Learn more

Read our documentation for in-depth instructions on configuring and using LaunchDarkly. You can also head straight to the complete reference guide for this SDK.

Generated API documentation is on readthedocs.io.

Testing

We run integration tests for all our SDKs using a centralized test harness. This approach gives us the ability to test for consistency across SDKs, as well as test networking behavior in a long-running application. These tests cover each method in the SDK, and verify that event sending, flag evaluation, stream reconnection, and other aspects of the SDK all behave correctly.

Contributing

We encourage pull requests and other contributions from the community. Check out our contributing guidelines for instructions on how to contribute to this SDK.

Verifying SDK build provenance with the SLSA framework

LaunchDarkly uses the SLSA framework (Supply-chain Levels for Software Artifacts) to help developers make their supply chain more secure by ensuring the authenticity and build integrity of our published SDK packages. To learn more, see the provenance guide.

About LaunchDarkly

  • LaunchDarkly is a continuous delivery platform that provides feature flags as a service and allows developers to iterate quickly and safely. We allow you to easily flag your features and manage them from the LaunchDarkly dashboard. With LaunchDarkly, you can:
    • Roll out a new feature to a subset of your users (like a group of users who opt-in to a beta tester group), gathering feedback and bug reports from real-world use cases.
    • Gradually roll out a feature to an increasing percentage of users, and track the effect that the feature has on key metrics (for instance, how likely is a user to complete a purchase if they have feature A versus feature B?).
    • Turn off a feature that you realize is causing performance problems in production, without needing to re-deploy, or even restart the application with a changed configuration file.
    • Grant access to certain features based on user attributes, like payment plan (eg: users on the ‘gold’ plan get access to more features than users in the ‘silver’ plan). Disable parts of your application to facilitate maintenance, without taking everything offline.
  • LaunchDarkly provides feature flag SDKs for a wide variety of languages and technologies. Read our documentation for a complete list.
  • Explore LaunchDarkly

python-server-sdk's People

Contributors

albertyw avatar andrefreitas avatar ashanbrown avatar bwoskow-ld avatar cwaldren-ld avatar dependabot[bot] avatar drichelson avatar eli-darkly avatar eplusminus avatar github-actions[bot] avatar hauntsaninja avatar jdmoldenhauer avatar jkodumal avatar jpgimenez avatar keelerm84 avatar kparkinson-ld avatar launchdarklyci avatar launchdarklyreleasebot avatar ld-repository-standards[bot] avatar louis-launchdarkly avatar mattbriancon avatar mnito avatar mrdon avatar patrickstreule avatar phillipuniverse avatar pkaeding avatar rsoberano-ld avatar slindstr avatar theholy7 avatar thieman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

python-server-sdk's Issues

launchdarkly Python Test data sources

Is your feature request related to a problem? Please describe.
This feature, "Test data sources", is not supported in python (according to the documentation)

Describe the solution you'd like
Similar to other languages.

Describe alternatives you've considered

Additional context

Getting numerous Error posting diagnostic event (giving up permanently): HTTP error 401 (invalid SDK key)

After init code part

if self.client.get().is_initialized():
logger.info("Launch Darkly SDK successfully initialized.")
I get "Launch Darkly SDK successfully initialized."
I've double checked sdk key and it's right as well as reading flags.
Confg is simple containing only sdk key.
self.client.set_config(Config(sdk_key))
Logs
I have started getting
Error posting diagnostic event (giving up permanently): HTTP error 401 (invalid SDK key)
Deployment is on kubernetes with multiple pods, and framework is Flask, it some race condition happening here?
Note that in local I am not getting this message.

SDK version
launchdarkly-server-sdk = "^7.4.2"

Language version, developer tools
python 3.9

OS/platform
For instance, Ubuntu 16.04

'matches' operator is anchored to the beginning of the string

Given a user like this:

{
  'key': 'user-key',
  'custom': {
    'greeting': 'hello world',
  }
}

And a flag target using the 'matches' operator with a regex that should match a part of the value: (world|planet)

The user should match the targeting rule, but does not. In other LaunchDarkly SDKs, the user does match this rule.

Thread exception

I am using python 2.7.15, ldclient-py=6.0.0, i dont want to call the ldclient.close() method as this is a long running application, i am getting the following error.
File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
Traceback (most recent call last): File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner File "/env/local/lib/python2.7/site-packages/ldclient/repeating_timer.py", line 12, in runTraceback (most recent call last): File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
__bootstrap_inner

Backing off log.error() causes multiple issues on Sentry

Like many people, we use Sentry for exception logging. The backoff library you guys are using will log messages that look like:

Backing off _connect(...) for 0.7s (requests.exceptions.ReadTimeout: HTTPSConnectionPool(host='st...
Backing off _connect(...) for 1.0s (requests.exceptions.ReadTimeout: HTTPSConnectionPool(host='st...
...

Each of these log messages counts as separate issue. On a recent LD outage, we had thousands of these issues and events inside of Sentry, which was really annoying.

a GAE-friendly (probably synchronous) client?

I'm evaluating LaunchDarkly for my company and I'm running into some issues getting things going on Google App Engine standard for python.

I got past the familiar SSL issues, but App Engine Standard and background threads aren't very compatible, I was wondering if there was a simple way to make the client be synchronous with perhaps some in-memory caching. I'd be more than willing to contribute code along these lines but would need some guidance.

I found a similar issue with a different library that seems to have found a workaround.

Thanks,

Jason

RedisFeatureStore should handle redis outage

From my reading of the code and from some limited testing, the LaunchDarkly client gracefully handles unavailability of the LaunchDarkly service.

The RedisFeatureStore does not appear to handle outages gracefully. IMO it should return the default when redis is unavailable. (I discovered the problem when I had my redis URL misconfigured while running in ldd mode.)

ImportError: cannot import name 'VersionInfo'

Is this a support request?
This issue tracker is maintained by LaunchDarkly SDK developers and is intended for feedback on the SDK code. If you're not sure whether the problem you are having is specifically related to the SDK, or to the LaunchDarkly service overall, it may be more appropriate to contact the LaunchDarkly support team; they can help to investigate the problem and will consult the SDK team if necessary. You can submit a support request by going here or by emailing [email protected].

Note that issues filed on this issue tracker are publicly accessible. Do not provide any private account information on your issues. If your problem is specific to your account, you should submit a support request as described above.

Describe the bug
Importing VersionInfo in the operators.py file gives out an import error since semver has deprecated VersionInfo and replaced it by Version

To reproduce
Run operators.py file from launchdarkly repo.

Expected behavior
Importing VersionInfo must be successful from launchdarkly

Logs

    from .client import *
  File "/usr/local/lib/python3.6/dist-packages/ldclient/client.py", line 18, in <module>
    from ldclient.flag import EvaluationDetail, evaluate, error_reason
  File "/usr/local/lib/python3.6/dist-packages/ldclient/flag.py", line 12, in <module>
    from ldclient import operators
  File "/usr/local/lib/python3.6/dist-packages/ldclient/operators.py", line 8, in <module>
    from semver import VersionInfo
ImportError: cannot import name 'VersionInfo'

SDK version
Latest version

Language version, developer tools
Python 3.6.9 and 3.6.15

OS/platform
Ubuntu 18.04 and 20.04

Additional context
https://readthedocs.org/projects/python-semver/downloads/pdf/latest/

Support configured defaults

LDClient should be able to take a dict of default values to allow the centralization of defaults, especially useful in offline mode supporting different environments.

Can jsonpickle's version restriction be relaxed? (0.9.3 -> 0.9.6)

Hi, I'm trying to make use of launchdarkly in my app, but I'm having issues because of the fact that we also use jsonpickle in it, and we're using it at version 0.9.6. I was wondering if there was anything stopping this library from updating to <1.0.0? 1.0 they got rid of python 3.3 support (since it EOLd), so I understand if you can't upgrade there, but 0.9.6 should be version safe/compatible, and even adds some new features/clears up some old bugs.

Thanks!

Python client fails when no config set

I'm got the following when I tried the Quickstart tutorial:


Traceback (most recent call last):
  File "test.py", line 4, in <module>
    client = LDClient("api-094349dd-49bf-4aa5-91a7-7ad9bbbd1817")
  File "/Users/tly/.virtualenvs/launchdarkly/lib/python2.7/site-packages/ldclient/client.py", line 153, in __init__
    self._store = config.feature_store_class()
AttributeError: 'NoneType' object has no attribute 'feature_store_class'

I'll put together a pull request to fix this.

Error closing client when LaunchDarkly relay proxy in daemon mode

Describe the bug
Using LaunchDarkly relay proxy in daemon mode (use_ldd=True) causes the following error whenever the client is closed.

'LDClient' object has no attribute '_update_processor': AttributeError
Traceback (most recent call last):
...
    client.close()
  File "/var/task/ldclient/client.py", line 160, in close
    if self._update_processor and self._update_processor.is_alive():
AttributeError: 'LDClient' object has no attribute '_update_processor'

Note that this can also be triggered by calling ldclient.set_config(config).

The issue is that because we are running in daemon mode, the _update_processor attribute for the client was never set. The following lines from ldclient.client.LDClient#__init__ capture this.

if self._config.use_ldd:
            log.info("Started LaunchDarkly Client in LDD mode")
            return

but the _update_processor attribute is not set until later in the object initialization.

To reproduce

Create a client with a config that has use_ldd set to True and try to call close on that client.

Expected behavior

The client should close the connection without an issue.

Logs

'LDClient' object has no attribute '_update_processor': AttributeError
Traceback (most recent call last):
...
ldclient.set_config(config)
File "/var/task/ldclient/__init__.py", line 47, in set_config
old_client.close()
File "/var/task/ldclient/client.py", line 160, in close
if self._update_processor and self._update_processor.is_alive():
AttributeError: 'LDClient' object has no attribute '_update_processor'

SDK version
6.8.4

Language version, developer tools
Python 3.6

Additional context
I discovered this while using the SDK in a lambda function. Even though it was a new call to the lambda, calling ldclient.set_config caused the client from the previous run to try to close, which caused this issue.

Unexpected keyword argument 'total' prevents events from being sent

Occasionally, I see this in the logs:

Unhandled exception in event processor. Analytics events were not processed. [init() got an unexpected keyword argument 'total']

It doesn't happen all the time, and I think I traced it down to how retries are handled. This library uses a _EventRetry subclass of urllib3.Retry, however, Retry will try to recreate itself via the "new" function, passing in all the arguments it received. Unfortunately, _EventRetry doesn't support any of those arguments, specifically 'total', and I think this is causing the error.

The fix would be to, at a minimum, add **kwargs to the constructor, or better yet, pass those same arguments down.

RedisFeatureStore does not offer ssl_ca_certs kwarg

Is your feature request related to a problem? Please describe.

I would love for the RedisFeatureStore to allow for me to specify a host, port, password, SSL, and ssl_ca_cert if applicable when trying to connect to a Redis cluster that has TLS/SSL enabled.

Describe the solution you'd like

Ideally, I could use the existing RedisFeatureStore.new_feature_store() method with a new set of kwargs instead of just the connection url.

store = Redis.new_feature_store(host=..., port=..., password=..., ssl=True, ssl_ca_certs=...)

Describe alternatives you've considered

The required redis package already supports these args, I think the adjustment will be using something other than redis.ConnectionPool.from_url during initialization of _RedisFeatureStoreCore.

Unexpected keyword argument 'connect_timeout'

Latest version of the LaunchDarkly client (v7.0.0 at the time of writing) doesn't support the 'connect_timeout' configuration argument in my code. This is running Python 3.9 on Mac OS Catalina.

Example code:

import ldclient
from ldclient.config import Config

def main():
    ldclient.set_config(Config(sdk_key='test-key', connect_timeout=5))

if __name__ == "__main__":
    main()

Response from the code:

TypeError: __init__() got an unexpected keyword argument 'connect_timeout'

Expected behavior
A LaunchDarkly client to be instantiated for use in my code.

allow for loading initial information of a TestData from a file

Is your feature request related to a problem? Please describe.
We have very many feature flags in our codebase, many of which are permanent for partial availability reasons.

We'd like our devs' tests to be initialized with a known-good state of those feature flags that we'd store on disk and then use the TestData API to override those values in their tests.

Describe the solution you'd like

It'd be really nice for Files and TestData to have a way to cross through them.

Something like:

feature_store: FeatureStore = Files.load_from_file('/path/to/flagdata.json'); 
td = TestData(feature_store)
td.update(td.flag(...))

Describe alternatives you've considered
Currently, we try to not know much of anything about the schema of the flag data on disk from a dump of https://app.launchdarkly.com/sdk/latest-all

We have a subclass of TestData that takes a FeatureStore argument, and overrides _make_init_data to use the FeatureStore's values as the initial values in _TestDataSource's FeatureStore (with some jiggering of version). That could probably be made into how TestData operates if created with a FeatureStore.

However, getting the FeatureStore to pass into TestData filled with data is grody because there's no public way to turn file data into a FeatureStore directly without knowing details about the schema of the flag data.

One horrible hack imagined was creating a Config with an InMemoryFeatureStore as feature_store and a Files.new_data_source() as update_processor_class, passing that Config to an LDClient, and waiting for the LDClient to initialize. Then, using the contents of InMemoryFeatureStore as the initial FeatureStore our subclass uses and throwing away that Files-y LDClient.

Something like:

feature_store = InMemoryFeatureStore()
data_source_factory = Files.new_data_source(paths=["flagdata.json"], auto_update=False)
files_ldclient = LDClient(Config(sdk_key='sdk-fake', update_processor_class=data_source_factory, send_events=False, feature_store=feature_store)
td = OurTestData(feature_store) # See "Additional context"

Additional context

The subclass we wrote:

class OurTestData(TestData):
     def __init__(self, initial_feature_store: Optional[FeatureStore]):
         self.initial_feature_store = initial_feature_store
         super().__init__()
 
     def _make_init_data(self) -> dict:
         features = {}
         if self.initial_feature_store:
           features = self.initial_feature_store.all(FEATURES, lambda x: x)
         for k, v in self._current_flags.items():
             initial_v = features.get(k, None)
             if initial_v:
               v['version'] = initial_v['version']
             features[k] = v
 
         return {FEATURES: features}

YAMLLoadWarning

Is this a support request?
No

Describe the bug
Using Launch Darkly in Python 3.6 gives the following warning:

YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated ...

Further details can be found here:
https://github.com/yaml/pyyaml/wiki/PyYAML-yaml.load(input)-Deprecation

Is there a plan to update this?

To reproduce

import ldclient
ldclient.get().variation(...)

Expected behavior
No warnings

Logs

YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the 
default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.

SDK version
launchdarkly-server-sdk==6.11.1

Language version, developer tools
Python 3.6

OS/platform
Ubuntu 18.04

Additional context
None

Python SDK is not updating the 'Evaluated ...' value for the flag

Describe the bug
When I use the Python SDK to check the value of a Feature flag, it is not updating the 'Evaluated ...' value. I.e. the value for the flag still reads as 'Evaluated 9 days ago', even though I just accessed (and got a valid response back from) the flag.
However, if I call ldclient.get().close(), it works.
The documentation states that "In most long-running applications, you should not have to call close", which makes sense to me. Shouldn't calling flush be enough?

To reproduce
Simply call ld_client.variation, without calling close afterwards.
See here for an example.

Expected behavior
Every time I call flush it should update the value displayed in the Launch Darkly user interface.

Logs
N/A

SDK version
7.0.1

Language version, developer tools
Python 3.9.1

OS/platform
Windows 10

Additional context
N/A

TypeError: backoff.on_exception when running in uvicorn

Describe the bug
I noticed the following error when trying to use launch darkly in a fastapi project with code reloading:

TypeError: backoff.on_exception applied to a regular function inside coroutine, this will lead to event loop hiccups. Use backoff.on_exception on coroutines in asynchronous code.

The error is thrown from this line in python-server-sdk.

The command to run uvicorn is here in the base image.

To reproduce
I created a simple repo to reproduce the issue.

git clone https://github.com/dj0nes/ldclient-uvicorn-issue.git
docker-compose up

Expected behavior
The application should run without crashing.

SDK version
launchdarkly-server-sdk~=6.11.1

Language version, developer tools
python 3.7

OS/platform
alpine 3.8

setting user attributes to non-strings when strings are expected can cause problems

We've identified some potential problems that can happen if any of the non-custom user attributes that are expected to be strings (that is, all of them except :anonymous) are instead set to a number or some other type. The Python SDK, like the other SDKs in weakly-typed languages, does not prevent this since the user object is simply a dictionary.

  1. LaunchDarkly will not process analytics events for such a user.
  2. If you set "secondary" to a non-string, and try to evaluate a flag that has a percentage rollout, the evaluation will fail.

We believe this behavior is the same in all existing versions of the Python SDK.

Our planned fix is to make the SDK coerce these values to strings as needed. To avoid causing unexpected changes in behavior for existing code, we will not enforce strict typing in this major version.

DeprecationWarning The 'warn' method

6.9.1 version, I got deprecation warning about warn. Can you fix these annoying messages?

C:\Python37\lib\site-packages\ldclient\client.py:287: DeprecationWarning: The 'warn' method is deprecated, use 'warning' instead
    + str(default) + " for feature key: " + key)

Unhandled exception in event consumer. Analytics events were not processed.

When calling launchdarkly_client.toggle(), we often see an error log with the following traceback:

Traceback (most recent call last):
  File "/path/to/virtualenv/lib/python3.5/site-packages/ldclient/event_consumer.py", line 50, in do_send
    data=json.dumps(body))
  File "/usr/local/python/lib/python3.5/json/__init__.py", line 230, in dumps
    return _default_encoder.encode(obj)
  File "/usr/local/python/lib/python3.5/json/encoder.py", line 198, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/local/python/lib/python3.5/json/encoder.py", line 256, in iterencode
    return _iterencode(o, 0)
  File "/usr/local/python/lib/python3.5/json/encoder.py", line 179, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <object object at 0x7f3b18c7c230> is not JSON serializable

The user object we are providing to .toggle() does not contain any non-json-serializable fields. Example: {'anonymous': True, 'key': 'SECRET', 'custom': {'client': 'sandbox', 'roles': (), 'superuser': False}}

We are currently using version 0.20.3, but this problem repros on 3.0.0. Running on Python 3.5.2 on Ubuntu 14.04.

Is there a way for us to opt-out of these failing analytics events? Or can the this client library be updated to fix this error?

ldclient.get() call is getting hanged (time out) on updating requests version to 2.18.4 from 2.12.5

Description: The ldclient.get() call is getting timed out in my service on updating the requests version from 2.12.5 to 2.18.4 . On probing further I found out that the ldclient.get() method calls LDClient (in client.py file) and LDClient calls self._update_processor.start() this is the call which is actually getting timed out. If I comment out the self._update_processor.start() call then the ldclient.get() runs fine. One more thing is that ldclient has a requirement requests>=2.17.3 but still it seems to be working with the lower version. I tried with the updated versions of ldclient as well but got the same behaviour.

Env details:
Python: 2.7
LDClient: 5.0.4
Requests: 2.18.4
Ubuntu:14.04

Allow client to be stopped and restarted

This behavior doesn't seem to work in this situation: Configure the client with an invalid SDK key, then attempt to stop the client. Ensure that a new SDK key is properly passed through to all http clients.

Log warning on every analytics bulk POST

Seemingly every time the library sends bulk analytic data back, the following error is logged as a warning:

Unhandled exception in event processor. Analytics events were not processed. ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))

It doesn't seem to affect either the performance of the library or even the analytics as viewed in the Launchdarkly web UI.

It seems to have started on May 21st, which doesn't correspond to any library upgrades on our side. We are running the latest 6.9.2

Inaccurate uwsgi `enable-threads` error logging

Right now, if you run the client in a uwsgi environment without the enable-threads option set, this message gets error logged:

The LaunchDarkly client requires the enable-threads option be passed to uWSGI.

However, the uwsgi config could not have enable-threads explicitly set, but rather have threads implicitly enabled by setting a threads option.

By default the Python plugin does not initialize the GIL. This means your app-generated threads will not run. If you need threads, remember to enable them with enable-threads. Running uWSGI in multithreading mode (with the threads options) will automatically enable threading support. This “strange” default behaviour is for performance reasons, no shame in that.

In the case where enable-threads is not specified in the uwsgi config, but threads is, the LaunchDarkly client will incorrectly log the above error message.

Problem importing lib v4.0.2

Looks like maybe python2.6-requirements.txt isn't in the zip file on PYPI.

Searching for ldclient-py>=4.0.0
Reading https://pypi.python.org/simple/ldclient-py/
Downloading https://pypi.python.org/packages/4a/19/744c4fa7ab4116b3267de1ec132290b92fb4c24e39de0cb421aee6ae4fab/ldclient-py-4.0.2.tar.gz#md5=781fdd286c422f31155364c30c188ae0
Best match: ldclient-py 4.0.2
Processing ldclient-py-4.0.2.tar.gz
Writing /tmp/easy_install-RZ8Mp3/ldclient-py-4.0.2/setup.cfg
Running ldclient-py-4.0.2/setup.py -q bdist_egg --dist-dir /tmp/easy_install-RZ8Mp3/ldclient-py-4.0.2/egg-dist-tmp-bLgInv
Traceback (most recent call last):
  File "setup.py", line 86, in <module>
    include_package_data=True)
  File "/opt/circleci/python/2.7.12/lib/python2.7/distutils/core.py", line 151, in setup
    dist.run_commands()
  File "/opt/circleci/python/2.7.12/lib/python2.7/distutils/dist.py", line 953, in run_commands
    self.run_command(cmd)
  File "/opt/circleci/python/2.7.12/lib/python2.7/distutils/dist.py", line 972, in run_command
    cmd_obj.run()
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/command/install.py", line 67, in run
    self.do_egg_install()
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/command/install.py", line 117, in do_egg_install
    cmd.run()
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/command/easy_install.py", line 411, in run
    self.easy_install(spec, not self.no_deps)
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/command/easy_install.py", line 655, in easy_install
    return self.install_item(None, spec, tmpdir, deps, True)
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/command/easy_install.py", line 702, in install_item
    self.process_distribution(spec, dist, deps)
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/command/easy_install.py", line 747, in process_distribution
    [requirement], self.local_index, self.easy_install
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/pkg_resources/__init__.py", line 851, in resolve
    dist = best[req.key] = env.best_match(req, ws, installer)
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/pkg_resources/__init__.py", line 1123, in best_match
    return self.obtain(req, installer)
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/pkg_resources/__init__.py", line 1135, in obtain
    return installer(requirement)
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/command/easy_install.py", line 674, in easy_install
    return self.install_item(spec, dist.location, tmpdir, deps)
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/command/easy_install.py", line 700, in install_item
    dists = self.install_eggs(spec, download, tmpdir)
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/command/easy_install.py", line 881, in install_eggs
    return self.build_and_install(setup_script, setup_base)
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/command/easy_install.py", line 1120, in build_and_install
    self.run_setup(setup_script, setup_base, args)
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/command/easy_install.py", line 1106, in run_setup
    run_setup(setup_script, args)
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/sandbox.py", line 258, in run_setup
    raise
  File "/opt/circleci/python/2.7.12/lib/python2.7/contextlib.py", line 35, in __exit__
    self.gen.throw(type, value, traceback)
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/sandbox.py", line 198, in setup_context
    yield
  File "/opt/circleci/python/2.7.12/lib/python2.7/contextlib.py", line 35, in __exit__
    self.gen.throw(type, value, traceback)
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/sandbox.py", line 169, in save_modules
    saved_exc.resume()
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/sandbox.py", line 144, in resume
    six.reraise(type, exc, self._tb)
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/sandbox.py", line 157, in save_modules
    yield saved
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/sandbox.py", line 198, in setup_context
    yield
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/sandbox.py", line 255, in run_setup
    DirectorySandbox(setup_dir).run(runner)
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/sandbox.py", line 285, in run
    return func()
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/sandbox.py", line 253, in runner
    _execfile(setup_script, ns)
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/setuptools/sandbox.py", line 47, in _execfile
    exec(code, globals, locals)
  File "/tmp/easy_install-RZ8Mp3/ldclient-py-4.0.2/setup.py", line 22, in <module>
    cmd = ['git', 'describe']
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/pip/req/req_file.py", line 84, in parse_requirements
    filename, comes_from=comes_from, session=session
  File "/home/ubuntu/observer/venv/lib/python2.7/site-packages/pip/download.py", line 425, in get_file_content
    'Could not open requirements file: %s' % str(exc)
pip.exceptions.InstallationError: Could not open requirements file: [Errno 2] No such file or directory: 'python2.6-requirements.txt'

Support for mobile key

Is your feature request related to a problem? Please describe.
I would like to have support of mobile key in the Python SDK.

Describe the solution you'd like
The Python SDK can reach access the LD server using the mobile key for client side Python scripts.

Describe alternatives you've considered
Creating another project to dump "unsecure" flags in and use the SDK key of this project. If ever the key is compromised, they only see the "unsecure" flags.

Additional context
I tried using mobile key with Python SDK but initialization fails.

Flags changes are not reflected if ldclient is initialized in uWSGI pre-fork worker

Describe the bug
Flag changes will not be reflected on forked web workers if the Launch Darkly client is initialized before the process is forked by uWSGI.

I think this is happening because the Launch Darkly client will spawn a thread for monitoring updates to flags, but when it's forked that thread will no longer work.

This can happen if the client initialization is triggered when a module is imported when the app is started (rather than initialized when it's first used inside of an endpoint).

The workaround for this requires you to avoid initializing the Launch Darkly client before forking occurs, but this can be a frustrating issue to debug if you're not aware of what is happening.

To reproduce
See this repo with a minimal example and instructions to reproduce the issue: https://github.com/pb-dod/launch_darkly_python_prefork#issue-reproduction-steps

Expected behavior
Maybe it's possible to detect forking and require the thread for monitoring flag updates to be re-initialized?

Or, maybe it should throw an exception if you try to initialize the Launch Darkly client inside of a pre-fork uWSGI worker? For example: https://gist.github.com/pb-dod/231b1b5dac9ea296918346a9288a598a

A warning might need to be added to the docs too.

Logs
n/a

SDK version
See example

Language version, developer tools
See example

OS/platform
See example

Additional context
n/a

Install broken on pip 10.x

From the pip CHANGELOG:

Move all of pip's APIs into the pip._internal package, properly reflecting the fact that pip does not currently have any public APIs. (#4696, #4700)

Collecting ldclient-py==4.0.6 (from -r requirements.txt (line 74))
  Downloading ldclient-py-4.0.6.tar.gz
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-install-qsq8HS/ldclient-py/setup.py", line 9, in <module>
        from pip.req import parse_requirements
    ImportError: No module named req

    ----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-install-qsq8HS/ldclient-py/

Strict requirements are no fun

Would it be possible to update the requirements.txt to not use strict (==) requirements? This has forced me to downgrade requests to 2.4.0.

Packaging error in v6.8.0 and 6.8.1

An error in package metadata has made it impossible to install the 6.8.0 release. We'll have a patch out shortly, and we'll be adding a test of the full packaging/installation process to our CI test suite. Sorry about that.

Generated documentation for Python SDK

Although the SDK contains documentation comments in Sphinx format, they weren't viewable anywhere except in your IDE. We will be putting them online starting with the next release, and maintaining them for every release version after that. We've also done some editing to improve the completeness and correctness of these comments.

If you'd like to watch this issue, we will update it when the docs go online.

ASGI/Asyncio Support

Is your feature request related to a problem? Please describe.

As far as I can tell, this SDK won't work with asyncio or asgi services due to the use of threading locks and queue.queue. This is preventing us from using it across all of our newer services.

Describe the solution you'd like

I'd like to see an async-first implementation where the launch darkly task is running in the background on the same event loop.

Describe alternatives you've considered

I'd also consider using the existing threaded mechanism, but provide async functions that don't rely on locks and the synchronous queue to request features when necessary.

I've considered wrapping the ld sdk in another thread and connecting it with async tasks using an asyncio.queue.

I've considered switching to a different feature flag provider.

Additional context

Is it possible I'm missing a different library? I was shocked to see that there was no asyncio first class citizen in the documentation in 2021, but maybe it hasn't been publicized yet.

py.typed file missing

Describe the bug
It looks like this library is fully typed but when I use mypy to lint my code I get this:

"ldclient": module is installed, but missing library stubs or py.typed marker
[import]
    import ldclient
    ^

In a python file that has:

import ldclient
ldclient.client.LDClient(...)
...

I think the only thing that needs to happen is create a py.typed marker file in the ldclient package directory?

To reproduce

  1. Mypy 0.942
  2. This mypy config in pyprojec.toml:
[tool.mypy]
plugins = [
    "pydantic.mypy",
    "sqlmypy"
]
exclude = [
    "build",
    "dist",
    ".venv",
    "venv",
    "get-poetry.py",
]
namespace_packages = true 
explicit_package_bases = true
strict = true
pretty = true
show_error_codes = true

    [[tool.mypy.overrides]]
    module = [
        "stuptools.*",
    ]
    ignore_missing_imports = true

Then linting with mypy ..

Expected behavior
Mypy passes

Logs
N/A

SDK version
7.4.0

Language version, developer tools
Python 3.7

OS/platform
MacOS

Additional context
N/A

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.