How can I get object from ZODB by url? - zope

How can I get object from ZODB database in Zope3 project by url 'http://ecample.com/folder1/object1'?
obj1 = someMethod('http://ecample.com/folder1/object1')
Is there any tools of methods for this? Like absoluteUrl() but opposite? Or I must parse url and manually get object from db root?...Thanks

You can turn a path into an object by using the traversing API:
from zope.traversing.api import traverse
obj = traverse(context, path)
You'll need a context to traverse from; use the site root for URL paths for example. If all you have is a URL, you'd need to parse out the path from it:
from urlparse import urlparse
path = urlparse(url).path

Related

can karate read files from outside the classpath with a relative path instead of absolute path

I'm trying to read a properties file for karate-config.js. It works when i provide the absolute path from my local but when i provide a relative path. it doesn't work. Any way around this? Thanks !
var config = karate.read("file:/repo/tests/utils/al_dev.json"); -- This doesn't work
var config = karate.read("file:~/repo/tests/utils/al_dev.json"); -- This doesn't work
var config = karate.read("file:/Users/user1/IdeaProjects/repo/tests/utils/al_dev.json"); -- This works
I was able to get it working. I had to update the path to reflect the project structure and it worked.
var config = karate.read("file:../../utils/al_dev.json");
Project structure:
project1 ->
tests ->
Utils ->
Services ->
client 1 ->
client 2 ->
I took advantage of answer wrote by Peter Thomas and it worked for me, I could read a json body from a file somewhere else in the project, not needed to be in the same folder as features. This is a sample of code I used:
Scenario: POST with json file reading from anywhere.
Given path "/api/apitesting/v1/transactions"
And def projectPath = karate.properties['user.home']
And def filePath = projectPath + "/IdeaProjects/01 Courses TM/karate/src/test/resources/data/TestBodyAnywhere.json"
And def requestBody = read('file:' + filePath)
And request requestBody
When method post
Then status 201
As you can see, I used user.home instead of user.dir, (which use to be recommended but this points directly to the same folder where you are calling it instead of pointing to outside that folder). User.home points directly to your root user, so it would be something like this C:/Users/MyUser. Then, from there you can start indicating the relative path in a new variable to your file. Finally, remember to use 'File:' keyword inside the read method and concatenate it with your path variable.
Hope it helps. ;)
Best regards!
Sorry, Karate (Java) can't resolve these special OS paths. I guess you know that this is not recommended, best practice is all test resources be kept under the project root. Anyway, here is a workaround:
* def home = java.lang.System.getProperty('user.home')
* def temp = read('file:' + home + '/repo/tests/utils/al_dev.json')

boto3 load custom models

For example:
session = boto3.Session()
client = session.client('custom-service')
I know that I can create a json with API definitions under ~/.aws/models and botocore will load it from there. The problem is that I need to get it done on the AWS Lambda function, which looks like impossible to do so.
Looking for a way to tell boto3 where are the custom json api definitions so it could load from the defined path.
Thanks
I have only a partial answer. There's a bit of documentation about botocore's loader module, which is what reads the model files. In a disscusion about loading models from ZIP archives, a monkey patch was offered up which extracts the ZIP to a temporary filesystem location and then extends the loader search path to that location. It doesn't seem like you can load model data directly from memory based on the API, but Lambda does give you some scratch space in /tmp.
Here's the important bits:
import boto3
session = boto3.Session()
session._loader.search_paths.extend(["/tmp/boto"])
client = session.client("custom-service")
The directory structure of /tmp/boto needs to follow the resource loader documentation. The main model file needs to be at /tmp/boto/custom-service/yyyy-mm-dd/service-2.json.
The issue also mentions that alternative loaders can be swapped in using Session.register_component so if you wanted to write a scrappy loader which returned a model straight from memory you could try that too. I don't have any info about how to go about doing that.
Just adding more details:
import boto3
import zipfile
import os
s3_client = boto3.client('s3')
s3_client.download_file('your-bucket','model.zip','/tmp/model.zip')
os.chdir('/tmp')
with zipfile.ZipFile('model.zip', 'r') as archive:
archive.extractall()
session = boto3.Session()
session._loader.search_paths.extend(["/tmp/boto"])
client = session.client("custom-service")
model.zip is just a compressed file that contains:
Archive: model.zip
Length Date Time Name
--------- ---------- ----- ----
0 11-04-2020 16:44 boto/
0 11-04-2020 16:44 boto/custom-service/
0 11-04-2020 16:44 boto/custom-service/2018-04-23/
21440 11-04-2020 16:44 boto/custom-service/2018-04-23/service-2.json
Just remember to have the proper lambda role to access S3 and your custom-service.
boto3 also allows setting the AWS_DATA_PATH environment variable which can point to a directory path of your choice.
[boto3 Docs]
Everything zipped with your lambda function is put under /opt/.
Let's assume all your custom models live under a models/ folder. When this folder is mounted to the lambda environment, it'll live under /opt/models/.
Simply specify AWS_DATA_PATH=/opt/models/ in the Lambda configuration and boto3 will pick up models in that directory.
This is better than fetching models from S3 during runtime, unpacking, and then modifying session parameters.

Ways to import a JSON file in public folder in Vue-CLI

I want to import a JSON file to use it, I need it to modify it in the future so I put it in public folder not assets, When I refer to it like this import JSON from ../../public/Data.json it works but I don't think so after building project can be resolved because after building there is no public folder. So I tried this :
let addr = process.env.BASE_URL;
import JSON from `${addr}Data.json`;
But It throws an error : SyntaxError
I'm confused now which way is the best and is there another way ?
The assets in the public folder are copied as is to the root of the dist folder. In your code, you can reference it just as /Data.json (if your app is deployed at the root of the domain).
E.g
async someMethod() {
const baseUrl = process.env.BASE_URL;
const data = await this.someHttpClient.get(`${ baseUrl }/Data.json`);
}
If you want to import the JSON as you have tried, I suggest to put it somewhere in the src folder and import from there
E.g.
import data from '#/data/someData.json'
console.log(data);
I came across this because I was doing a stand alone SPA that I wanted to run with no DB and keep the config in a JSON file. The import statement above works great for a static conf file, but anything imported like that gets compiled with the build, so even though your someData.json will exist in the public folder you won't see any changes in your dist because it's actually reading a JS compiled file.
To get around this I:
Convert the JSON file into a simple JS variable in a conf.js file:
e.g.
var srcConf={'bGreatJSON':true};
In index.html, did
<script src='./conf.js'>
Now that the JS variable has been declared in my Vue component I can just look for the window.srcConf and assign it if it exists in mounted or created:
if(typeof window.srcConf!='undefined')
this.sConf=window.srcConf;
This also avoids the GET CORS issue that others posts I've seen runs into, even in the same directory I kept getting CORS violations trying to do an axios call to read the file.

Generate index.html for AWS S3

I am trying to simulate directory listing for my bucket on ASW S3. Currently I am creating "index.html" locally as follows:
for root, dirs, files in os.walk(job_dir):
objects = []
for obj in dirs+files:
m_time_epoch = os.stat(os.path.join(path,obj)).st_mtime
mtime = datetime.fromtimestamp(m_time_epoch).strftime('%c')
size = os.stat(os.path.join(path,obj)).st_size
type = 'dir' if os.path.isdir(os.path.join(path,obj)) else 'file'
objects.append({'name': obj,
'mtime': mtime,
'size': size,
'type': type})
generate_index(objects, dest_path)
And then passing it together with destination path (bucket URL) to a function which will create "index.html" using jinja template.
Is there better way to do it? I would like to avoid JavaScript though. I made some googling however so far did not find an elegant solution.
What would be the easiest alternative of "os.walk" using boto3 python client?
I found some snippets e.g. here:
How do I list directory contents of an S3 bucket using Python and Boto3?
But is not there a simpler solution?
Thanks...
I'd recommend using the list_objects_v2 method in boto3.
import boto3
s3 = boto3.client('s3')
paginator = s3.get_paginator('list_objects_v2')
response_iterator = paginator.paginate(
Bucket='MyBucket'
)
objects = []
for response in response_iterator:
for r in response['Contents']:
print("File is called {}".format(r['Key']))
While iterating through the objects in the bucket, you could build an object you could pass to a Jinja template to create the index.html page

Getting Path (context root) to the Application in Restlet

I am needing to get the application root within a Restlet resource class (it extends ServerResource). My end goal is trying to return a full explicit path to another Resource.
I am currently using getRequest().getResourceRef().getPath() and this almost gets me what I need. This does not return the full URL (like http://example.com/app), it returns to me /resourceName. So two problems I'm having with that, one is it is missing the schema (the http or https part) and server name, the other is it does not return where the application has been mounted to.
So given a person resource at 'http://dev.example.com/app_name/person', I would like to find a way to get back 'http://dev.example.com/app_name'.
I am using Restlet 2.0 RC3 and deploying it to GAE.
It looks like getRequest().getRootRef().toString() gives me what I want. I tried using a combination of method calls of getRequest().getRootRef() (like getPath or getRelativePart) but either they gave me something I didn't want or null.
Just get the base url from service context, then share it with the resources and add resource path if needed.
MyServlet.init():
String contextPath = getServletContext().getContextPath();
getApplication().getContext().getAttributes().put("contextPath", contextPath);
MyResource:
String contextPath = getContext().getAttributes().get("contextPath");
request.getRootRef() or request.getHostRef()?
The servlet's context is accessible from the restlet's application:
org.restlet.Application app = org.restlet.Application.getCurrent();
javax.servlet.ServletContext ctx = ((javax.servlet.ServletContext) app.getContext().getAttributes().get("org.restlet.ext.servlet.ServletContext"));
String path = ctx.getResource("").toString();