Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update with changes from djhenderson #42

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ lib
include
man
share
__pycache__
*.egg-info

# Ignore Python byte compiled files and Windows GUI Python files
*.pyc
Expand All @@ -20,6 +22,8 @@ share

# Ignore text editor backup files
*~
*.bak

# Ignore test/config.ini
# Ignore all config.ini file: they contain private config info
test/config.ini
sample-apps/*/config.ini
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ python:
- "3.2"
- "3.3"
- "3.4"
- "3.5"

install: pip install coveralls

# SDK does not have any external dependencies.

script: coverage run --source=familysearch setup.py test

after_success: coveralls
23 changes: 11 additions & 12 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ familysearch-python-sdk-opensource
.. image:: https://readthedocs.org/projects/familysearch-python-sdk-opensource/badge/?version=latest
:target: https://readthedocs.org/projects/familysearch-python-sdk-opensource/?badge=latest
:alt: Documentation Status

.. image:: https://www.codacy.com/project/badge/4875862e69c54164be173a94def06f09
:target: https://www.codacy.com/app/elderamevans/familysearch-python-sdk-opensource
:target: https://www.codacy.com/app/djhenderson/familysearch-python-sdk-opensource
:alt: Codacy Badge

.. image:: https://travis-ci.org/elderamevans/familysearch-python-sdk-opensource.svg?branch=master
:target: https://travis-ci.org/elderamevans/familysearch-python-sdk-opensource
.. image:: https://travis-ci.org/djhenderson/familysearch-python-sdk-opensource.svg?branch=master
:target: https://travis-ci.org/djhenderson/familysearch-python-sdk-opensource
:alt: Build status

.. image:: https://coveralls.io/repos/elderamevans/familysearch-python-sdk-opensource/badge.svg
:target: https://coveralls.io/r/elderamevans/familysearch-python-sdk-opensource
.. image:: https://coveralls.io/repos/djhenderson/familysearch-python-sdk-opensource/badge.svg
:target: https://coveralls.io/r/djhenderson/familysearch-python-sdk-opensource
:alt: Code Coverage

.. image:: https://img.shields.io/pypi/v/familysearch-python-sdk-opensource.svg
:target: https://pypi.python.org/pypi/familysearch-python-sdk-opensource
:alt: PyPI Version
Expand All @@ -25,13 +25,12 @@ familysearch-python-sdk-opensource
:target: https://pypi.python.org/pypi/familysearch-python-sdk-opensource


This is a reboot/spinoff of https://github.com/familysearch-devnet/python-fs-stack.
This is a reboot/spinoff of https://github.com/familysearch-devnet/python-fs-stack which was last updated about June 8, 2011.

This is a fork of https://github.com/AmEv7Fam/familysearch-python-sdk-opensource which was last updated about July 21, 2015.

May or may not have all of the latest FamilySearch endpoints in place, but it is flexible enough to allow for additional endpoints

It is designed for Python 3 and 2.7. Python 2.6 is the earliest supported version, but bugfixes are low-priority. 2.5 and earlier are not guaranteed to work, or supported, and are considered legacy.

To get started, visit http://elderamevans.github.io/familysearch-python-sdk-opensource.



To get started, visit http://elderamevans.github.io/familysearch-python-sdk-opensource (May be 404 Not found).
23 changes: 23 additions & 0 deletions docs/Authentication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
* `login(self, username, password)`
Log into FamilySearch using Basic Authentication.
This mechanism is available only to approved developer keys.

* `oauth_desktop_login(self, ruri=None)`
Log into FamilySearch using OAuth2 Authentication.
This is primarily a convenience function for desktop apps.
Not normally intended for production apps, but should
work while waiting for approval for password login.
Default Redirect URI is "http://localhost:63342/fslogin",
but you can set your own as a paramater.

* `oauth_code_login(self, code)`
Convenience function for Web servers to log into FamilySearch
with the token code FamilySearch hands you.

* `unauthenticated_login(self, ip_address)`
Log into FamilySearch without authenticating.
Has very limited read-only access.
Not intended for general use.

* `logout(self)`
Log the current session out of FamilySearch.
1 change: 1 addition & 0 deletions docs/Authorities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [`dates(self, **kwargs)`](https://familysearch.org/developers/docs/api/dates/Date_resource)
5 changes: 5 additions & 0 deletions docs/Discovery.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
* `update_collection(self, collection)`

* `fix_discovery(self)`
The Hypermedia items are semi-permanent. Some things change
based on who's logged in (or out).
4 changes: 2 additions & 2 deletions docs/Memories.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
* [`memories(**kwargs)`](https://familysearch.org/developers/docs/api/memories/Memories_resource)
* [`memory(mid)`](https://familysearch.org/developers/docs/api/memories/Memory_resource)
* [`user_memories(**kwargs)`](https://familysearch.org/developers/docs/api/memories/User_Memories_resource)
* [`memory_personas(mid):`](https://familysearch.org/developers/docs/api/memories/Memory_Personas_resource)
* [`memory_personas(mid)`](https://familysearch.org/developers/docs/api/memories/Memory_Personas_resource)
* [`memory_persona(mid, pid)`](https://familysearch.org/developers/docs/api/memories/Memory_Persona_resource)
* [`memory_comments(mid)`](https://familysearch.org/developers/docs/api/memories/Memory_Comments_resource)
* [`memories_comment(mid, cmid)`](https://familysearch.org/developers/docs/api/memories/Memories_Comment_resource)
* [`memories_comment(mid, cmid)`](https://familysearch.org/developers/docs/api/memories/Memories_Comment_resource)
6 changes: 3 additions & 3 deletions docs/Person.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@
* [`person_discussion_reference(pid, drid)`](https://familysearch.org/developers/docs/api/tree/Person_Discussion_References_resource)
* [`person_merge(pid, dpid, **kwargs)`](https://familysearch.org/developers/docs/api/tree/Person_Merge_resource)
* [`person_change_summary(pid)`](https://familysearch.org/developers/docs/api/tree/Person_Merge_resource)
* [`person_not_a_match(pid, dpid):`](https://familysearch.org/developers/docs/api/tree/Person_Not_A_Match_resource)
* [`person_not_a_match(pid, dpid)`](https://familysearch.org/developers/docs/api/tree/Person_Not_A_Match_resource)
* [`person_restore(pid)`](https://familysearch.org/developers/docs/api/tree/Person_Restore_resource)
* [`preferred_spouse_relationship(pid)`](https://familysearch.org/developers/docs/api/tree/Preferred_Spouse_Relationship_resource)
* [`preferred_parent_relationship(pid)`](https://familysearch.org/developers/docs/api/tree/Preferred_Parent_Relationship_resource)
* [`person_memories(pid)`](https://familysearch.org/developers/docs/api/tree/Person_Memories_resource)
* [`person_memories(pid, **kwargs)`](https://familysearch.org/developers/docs/api/tree/Person_Memories_resource)
* [`person_memory_references(pid)`](https://familysearch.org/developers/docs/api/tree/Person_Memory_References_resource)
* [`person_memory_reference(pid, erid)`](https://familysearch.org/developers/docs/api/tree/Person_Memory_References_resource)
* [`person_memories_portrait(pid, **kwargs)`](https://familysearch.org/developers/docs/api/tree/Person_Memories_Portrait_resource)
* [`person_portraits(pid)`](https://familysearch.org/developers/docs/api/tree/Person_Portraits_resource)
* [`person_portraits(pid)`](https://familysearch.org/developers/docs/api/tree/Person_Portraits_resource)
2 changes: 1 addition & 1 deletion docs/Places.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* [`place_group(pgid)`](https://familysearch.org/developers/docs/api/places/Place_Group_resource)
* [`place(pid)`](https://familysearch.org/developers/docs/api/places/Place_resource)
* [`place_description_children()`](https://familysearch.org/developers/docs/api/places/Place_Description_Children_resource)
* [`place_type(ptid):`](https://familysearch.org/developers/docs/api/places/Place_Type_resource)
* [`place_type(ptid)`](https://familysearch.org/developers/docs/api/places/Place_Type_resource)
* [`place_type_group(ptgid)`](https://familysearch.org/developers/docs/api/places/Place_Type_Group_resource)
* [`place_types(self)`](https://familysearch.org/developers/docs/api/places/Place_Types_resource)
* [`def place_type_groups(self):`](https://familysearch.org/developers/docs/api/places/Place_Type_Groups_resource)
10 changes: 5 additions & 5 deletions docs/Sources.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
* [`source_descriptions()`](https://familysearch.org/developers/docs/api/sources/Source_Descriptions_resource)
* [`source_description(sdid):`](https://familysearch.org/developers/docs/api/sources/Source_Description_resource)
* [`source_folders():`](https://familysearch.org/developers/docs/api/sources/Source_Folders_resource)
* [`source_folder(udcid):`](https://familysearch.org/developers/docs/api/sources/Source_Folder_resource)
* [`source_description(sdid)`](https://familysearch.org/developers/docs/api/sources/Source_Description_resource)
* [`source_folders()`](https://familysearch.org/developers/docs/api/sources/Source_Folders_resource)
* [`source_folder(udcid)`](https://familysearch.org/developers/docs/api/sources/Source_Folder_resource)
* [`source_folder_source_descriptions(udcid, **kwargs)`](https://familysearch.org/developers/docs/api/sources/Source_Folder_Source_Descriptions_resource)
* [`user_source_folders()`](https://familysearch.org/developers/docs/api/sources/User_Source_Folders_resource)
* [`user_source_descriptions(**kwargs):`](https://familysearch.org/developers/docs/api/sources/User_Source_Descriptions_resource)
* [`source_references_query(self, **kwargs):`](https://familysearch.org/developers/docs/api/tree/Source_References_Query_resource)
* [`user_source_descriptions(**kwargs)`](https://familysearch.org/developers/docs/api/sources/User_Source_Descriptions_resource)
* [`source_references_query(self, **kwargs)`](https://familysearch.org/developers/docs/api/tree/Source_References_Query_resource)
7 changes: 5 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
Modules are modeled after the layout of [the official FamilySearch API documentation](https://familysearch.org/developers/docs/api/resources).
If you're not sure which function you need, it's best to use the URL of the FamilySearch Developer documentation, and search in that section for that URL.
Modules are modeled after the layout of
[the official FamilySearch API documentation](https://familysearch.org/developers/docs/api/resources).
If you're not sure which function you need,
it's best to use the URL of the FamilySearch Developer documentation,
and search in that section for that URL.

* [Main Module](Main_Module.md)
* [Authentication](Authentication.md)
Expand Down
51 changes: 34 additions & 17 deletions familysearch/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# -*- coding: utf-8 -*-

# For PyLint users:
# I'll get back to you to the recommeneded command.
r"""This is a WIP, unofficial SDK for accessing
# I'll get back to you to the recommended command.

"""This is a WIP, unofficial SDK for accessing
the FamilySearch API.
Currently designed to support Python 3.2+ and 2.6+.

Expand All @@ -24,19 +27,20 @@

# Python imports


try:
# Python 3
from urllib.request import Request as BaseRequest
from urllib.request import build_opener
from urllib.error import HTTPError
from urllib.parse import(urlsplit, urlunsplit, parse_qs, urlencode)
PY3 = True
except ImportError:
# Python 2
from urllib import urlencode
from urllib2 import Request as BaseRequest
from urllib2 import build_opener, HTTPError
from urlparse import(urlsplit, urlunsplit, parse_qs)
PY3 = False

import json
import time
Expand Down Expand Up @@ -64,13 +68,14 @@

# Magic

__version__ = '1.2.0'
__version__ = '1.3.0alpha'


class Request(BaseRequest):
"""Add ability for the Request object to allow it to handle
additional methods.
"""

def __init__(self, *args, **kwargs):
self._method = kwargs.pop('method', None)
BaseRequest.__init__(self, *args, **kwargs)
Expand All @@ -79,6 +84,7 @@ def get_method(self):
"""The Request object has been enhanced to handle PUT, DELETE, OPTIONS,
and HEAD request methods.
"""

if self._method:
return self._method
else:
Expand All @@ -96,22 +102,21 @@ class FamilySearch(Authentication, Authorities, ChangeHistory, Discovery,
...needs to be re-written...
"""

def __init__(self, agent, key, session=None,
def __init__(self, agent, dev_key, session=None,
base='https://sandbox.familysearch.org'):

"""Instantiate a FamilySearch proxy object.

Keyword arguments:
agent -- User-agent string to use for requests
key -- FamilySearch developer key
dev_key -- FamilySearch developer key
(optional if reusing an existing session ID)
session (optional) -- existing session ID to reuse
base (optional) -- base URL for the API;
defaults to 'https://sandbox.familysearch.org'
"""

self.agent = '%s FSPySDK/%s' % (agent, __version__)
self.key = key
self.user_agent = '%s FSPySDK/%s' % (agent, __version__)
self.dev_key = dev_key
self.access_token = session
self.base = base
self.user_base = self.base + "/platform/users/"
Expand All @@ -120,13 +125,15 @@ def __init__(self, agent, key, session=None,
self.logged_in = bool(self.access_token)

Discovery.__init__(self)
super().__init__()
if PY3:
super().__init__()
else:
super(FamilySearch, self).__init__()
# Discovery needs to explicitly be first, as it is the hypermedia
# engine.

# There might be a better fix, but it's better than nothing.


def _request(self, url, data=None, headers=None, method=None, nojson=False):
"""
Make a request to the FamilySearch API.
Expand All @@ -137,6 +144,7 @@ def _request(self, url, data=None, headers=None, method=None, nojson=False):

Returns a file-like object representing the response.
"""

if headers is None:
headers = {}
if data:
Expand All @@ -148,26 +156,28 @@ def _request(self, url, data=None, headers=None, method=None, nojson=False):
try:
data = data.encode('utf-8')
except AttributeError:
#Some things are not JSON, and need to be sent as bytes!
# Some things are not JSON, and need to be sent as bytes!
pass
request = Request(url, data, headers, method=method)
if not nojson:
if method is not "GET" and "Content-type" not in request.headers:
request.add_header('Content-type', 'application/x-fs-v1+json')
if 'Accept' not in request.headers:
request.add_header('Accept', 'application/json')
request.add_header('Accept', 'application/x-fs-v1+json;application/x-gedcomx-v1+json;application/x-gedcomx-atom+json;application/json')
if 'Accept-Charset' not in request.headers:
request.add_header('Accept-Charset', 'UTF-8')
if self.logged_in and not self.cookies:
# Add sessionId parameter to url if cookie is not set
request.add_header('Authorization', 'Bearer ' + self.access_token)
request.add_header('User-Agent', self.agent)
request.add_header('User-Agent', self.user_agent)
try:
return self.opener.open(request)
except HTTPError as error:
eh = dict(error.headers)
error_headers = dict(error.headers)
if error.code == 401:
self.logged_in = False
if error.code == 429:
time.sleep(eh['Retry-after']/1000)
time.sleep(error_headers['Retry-after'] / 1000)
return self._request(url, data, headers, method, nojson)
raise

Expand All @@ -177,8 +187,8 @@ def _add_subpath(self, url, subpath):

For example, adding sub to http://example.com/path?query
becomes http://example.com/path/sub?query.

"""

parts = urlsplit(url)
path = parts[2] + '/' + subpath
return urlunsplit((parts[0], parts[1], path, parts[3], parts[4]))
Expand All @@ -187,6 +197,7 @@ def _add_query_params(self, url, params=None, **kw_params):
"""Add the specified query parameters to the given URL.
Parameters can be passed either as a dictionary or as keyword arguments.
"""

if params is None:
params = {}
parts = urlsplit(url)
Expand All @@ -202,6 +213,7 @@ def _fs2py(self, response, nojson=False):
Take JSON from FamilySearch response, and allow Python to handle it.
Also, inject headers into response.
"""

headers = dict(response.info())
response = response.read()
response = response.decode("utf-8")
Expand All @@ -218,25 +230,30 @@ def get(self, url, data=None, headers=None, nojson=False):

def post(self, url, data=None, headers=None, nojson=False):
"""HTTP POST request"""

return self._fs2py(self._request(
url, data, headers, "POST", nojson), nojson)

def put(self, url, data=None, headers=None, nojson=False):
"""HTTP PUT request"""

return self._fs2py(self._request(
url, data, headers, "PUT", nojson), nojson)

def head(self, url, data=None, headers=None, nojson=False):
"""HTTP HEAD request"""

return self._fs2py(self._request(
url, data, headers, "HEAD", nojson), nojson)

def options(self, url, data=None, headers=None, nojson=False):
"""HTTP OPTIONS request"""

return self._fs2py(self._request(
url, data, headers, "OPTIONS", nojson), nojson)

def delete(self, url, data=None, headers=None, nojson=False):
"""HTTP DELETE request"""

return self._fs2py(self._request(
url, data, headers, "DELETE", nojson), nojson)
Loading